From 2367948a0f7bbcf42cb3ef9d97216319a526d3eb Mon Sep 17 00:00:00 2001 From: Sebastian Bazley Date: Sun, 1 Mar 2015 17:59:34 +0000 Subject: [PATCH] LANG-1061 FastDateParser error - timezones not handled correctly git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1663140 13f79535-47bb-0310-9956-ffa450edef68 --- src/changes/changes.xml | 1 + .../commons/lang3/time/FastDateParser.java | 3 +- .../lang3/time/FastDateParserSDFTest.java | 118 ++++++++++++++++++ 3 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/apache/commons/lang3/time/FastDateParserSDFTest.java diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 5e3ceb7af8f..d5a33dd2b0d 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -22,6 +22,7 @@ + FastDateParser error - timezones not handled correctly NumberUtils#createNumber() returns positive BigDecimal when negative Float is expected DiffBuilder.append(String, Object left, Object right) does not do a left.equals(right) check StrSubstitutor.replaceSystemProperties does not work consistently diff --git a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java index bdde1d2787b..159053f9b17 100644 --- a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java +++ b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java @@ -780,7 +780,8 @@ private static class TimeZoneStrategy extends Strategy { } final StringBuilder sb= new StringBuilder(); - sb.append("(GMT[+\\-]\\d{0,1}\\d{2}|[+\\-]\\d{2}:?\\d{2}|"); + sb.append("(GMT[+-]\\d{1,2}:\\d{2}").append('|'); + sb.append("[+-]\\d{4}").append('|'); for(final String id : tzNames.keySet()) { escapeRegex(sb, id, false).append('|'); } diff --git a/src/test/java/org/apache/commons/lang3/time/FastDateParserSDFTest.java b/src/test/java/org/apache/commons/lang3/time/FastDateParserSDFTest.java new file mode 100644 index 00000000000..a97345b710b --- /dev/null +++ b/src/test/java/org/apache/commons/lang3/time/FastDateParserSDFTest.java @@ -0,0 +1,118 @@ +package org.apache.commons.lang3.time; + +import static org.junit.Assert.*; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +/** + * Compare FastDateParser with SimpleDateFormat + */ +@RunWith(Parameterized.class) +public class FastDateParserSDFTest { + + @Parameters(name= "{index}: {0} {1} {2}") + public static Collection data() { + return Arrays.asList(new Object [][]{ + // General Time zone tests + {"z yyyy", "GMT 2010", Locale.UK, true}, // no offset specified, but seems to be allowed + {"z yyyy", "GMT-123 2010", Locale.UK, false}, + {"z yyyy", "GMT-1234 2010", Locale.UK, false}, + {"z yyyy", "GMT-12:34 2010", Locale.UK, true}, + {"z yyyy", "GMT-1:23 2010", Locale.UK, true}, + // RFC 822 tests + {"z yyyy", "-1234 2010", Locale.UK, true}, + {"z yyyy", "-12:34 2010", Locale.UK, false}, + {"z yyyy", "-123 2010", Locale.UK, false}, + // year tests + { "MM/dd/yyyy", "01/11/12", Locale.UK, true}, + { "MM/dd/yy", "01/11/12", Locale.UK, true}, + }); + } + + private final String format; + private final String input; + private final Locale locale; + private final boolean valid; + + public FastDateParserSDFTest(String format, String input, Locale locale, boolean valid) { + this.format = format; + this.input = input; + this.locale = locale; + this.valid = valid; + } + + @Test + public void testOriginal() throws Exception { + final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); + final TimeZone timeZone = TimeZone.getDefault(); + final DateParser fdf = new FastDateParser(format, timeZone, locale); + checkParse(locale, sdf, fdf, input); + } + + @Test + public void testUpperCase() throws Exception { + final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); + final TimeZone timeZone = TimeZone.getDefault(); + final DateParser fdf = new FastDateParser(format, timeZone , locale); + checkParse(locale, sdf, fdf, input.toUpperCase(locale)); + } + + @Test + @Ignore // not currently supported + public void testLowerCase() throws Exception { + final SimpleDateFormat sdf = new SimpleDateFormat(format, locale); + final TimeZone timeZone = TimeZone.getDefault(); + final DateParser fdf = new FastDateParser(format, timeZone , locale); + checkParse(locale, sdf, fdf, input.toLowerCase(locale)); + } + + private void checkParse(final Locale locale, final SimpleDateFormat sdf, final DateParser fdf, final String formattedDate) throws ParseException { + Date expectedTime=null; + Class sdfE = null; + try { + expectedTime = sdf.parse(formattedDate); + if (!valid) { + // Error in test data + throw new RuntimeException("Test data error: expected SDF parse to fail, but got " + expectedTime); + } + } catch (ParseException e) { + if (valid) { + // Error in test data + throw new RuntimeException("Test data error: expected SDF parse to succeed, but got " + e); + } + sdfE = e.getClass(); + } + Date actualTime = null; + Class fdfE = null; + try { + actualTime = fdf.parse(formattedDate); + if (!valid) { + // failure in test + fail("Expected FDP parse to fail, but got " + actualTime); + } + } catch (ParseException e) { + if (valid) { + // failure in test + fail("Expected FDP parse to succeed, but got " + e); + } + fdfE = e.getClass(); + } + if (valid) { + assertEquals(locale.toString()+" "+formattedDate +"\n",expectedTime, actualTime); + } else { + assertEquals(locale.toString()+" "+formattedDate + " expected same Exception ", sdfE, fdfE); + } + } +}