You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ch...@apache.org on 2015/05/01 01:27:28 UTC

[lang] LANG-1116: DateUtilsTest.testLang530 fails for some timezones

Repository: commons-lang
Updated Branches:
  refs/heads/master cb83f7cb3 -> bea1ae92a


LANG-1116: DateUtilsTest.testLang530 fails for some timezones


Project: http://git-wip-us.apache.org/repos/asf/commons-lang/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-lang/commit/bea1ae92
Tree: http://git-wip-us.apache.org/repos/asf/commons-lang/tree/bea1ae92
Diff: http://git-wip-us.apache.org/repos/asf/commons-lang/diff/bea1ae92

Branch: refs/heads/master
Commit: bea1ae92aa52a985f8c171c6e17ff7fc4aa61fe4
Parents: cb83f7c
Author: Chas Honton <ch...@apache.org>
Authored: Thu Apr 30 16:19:38 2015 -0700
Committer: Chas Honton <ch...@apache.org>
Committed: Thu Apr 30 16:19:38 2015 -0700

----------------------------------------------------------------------
 src/changes/changes.xml                         |  1 +
 .../apache/commons/lang3/time/DateUtils.java    | 42 ++++++--------------
 .../commons/lang3/time/FastDateParser.java      | 26 +++++++++++-
 .../commons/lang3/time/DateFormatUtilsTest.java | 17 ++++++++
 4 files changed, 55 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-lang/blob/bea1ae92/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 27a7f5c..d75b9c6 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,7 @@
   <body>
 
   <release version="3.5" date="tba" description="tba">
+    <action issue="LANG-1116" type="fix" dev="chas" due-to="Aaron Sheldon">DateUtilsTest.testLang530 fails for some timezones</action>
     <action issue="LANG-1114" type="fix" dev="britter" due-to="Andy Coates">TypeUtils.ParameterizedType#equals doesn't work with wildcard types</action>
     <action issue="LANG-1119" type="add" dev="britter" due-to="Loic Guibert">Add rotate(string, int) method to StringUtils</action>
     <action issue="LANG-1118" type="fix" dev="britter" due-to="Loic Guibert">StringUtils.repeat('z', -1) throws NegativeArraySizeException</action>

http://git-wip-us.apache.org/repos/asf/commons-lang/blob/bea1ae92/src/main/java/org/apache/commons/lang3/time/DateUtils.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/lang3/time/DateUtils.java b/src/main/java/org/apache/commons/lang3/time/DateUtils.java
index 74da2b6..0961073 100644
--- a/src/main/java/org/apache/commons/lang3/time/DateUtils.java
+++ b/src/main/java/org/apache/commons/lang3/time/DateUtils.java
@@ -18,12 +18,12 @@ package org.apache.commons.lang3.time;
 
 import java.text.ParseException;
 import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.Locale;
 import java.util.NoSuchElementException;
+import java.util.TimeZone;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -365,37 +365,21 @@ public class DateUtils {
         if (str == null || parsePatterns == null) {
             throw new IllegalArgumentException("Date and Patterns must not be null");
         }
-        
-        SimpleDateFormat parser;
-        if (locale == null) {
-            parser = new SimpleDateFormat();
-        } else {
-            parser = new SimpleDateFormat("", locale);
-        }
-        
-        parser.setLenient(lenient);
-        final ParsePosition pos = new ParsePosition(0);
-        for (final String parsePattern : parsePatterns) {
-
-            String pattern = parsePattern;
 
-            // LANG-530 - need to make sure 'ZZ' output doesn't get passed to SimpleDateFormat
-            if (parsePattern.endsWith("ZZ")) {
-                pattern = pattern.substring(0, pattern.length() - 1);
-            }
-            
-            parser.applyPattern(pattern);
-            pos.setIndex(0);
+        final TimeZone tz = TimeZone.getDefault();
+        final Locale lcl = locale==null ?Locale.getDefault() : locale;
+        final ParsePosition pos = new ParsePosition(0);
 
-            String str2 = str;
-            // LANG-530 - need to make sure 'ZZ' output doesn't hit SimpleDateFormat as it will ParseException
-            if (parsePattern.endsWith("ZZ")) {
-                str2 = str.replaceAll("([-+][0-9][0-9]):([0-9][0-9])$", "$1$2"); 
+        for (final String parsePattern : parsePatterns) {
+            FastDateParser fdp = new FastDateParser(parsePattern, tz, lcl, null, lenient);
+            try {
+                Date date = fdp.parse(str, pos);
+                if (pos.getIndex() == str.length()) {
+                    return date;
+                }
+                pos.setIndex(0);
             }
-
-            final Date date = parser.parse(str2, pos);
-            if (date != null && pos.getIndex() == str2.length()) {
-                return date;
+            catch(IllegalArgumentException iae) {
             }
         }
         throw new ParseException("Unable to parse the date: " + str, -1);

http://git-wip-us.apache.org/repos/asf/commons-lang/blob/bea1ae92/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
----------------------------------------------------------------------
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 2d469a6..3f8d021 100644
--- a/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
+++ b/src/main/java/org/apache/commons/lang3/time/FastDateParser.java
@@ -75,7 +75,7 @@ public class FastDateParser implements DateParser, Serializable {
      *
      * @see java.io.Serializable
      */
-    private static final long serialVersionUID = 2L;
+    private static final long serialVersionUID = 3L;
 
     static final Locale JAPANESE_IMPERIAL = new Locale("ja","JP","JP");
 
@@ -85,6 +85,7 @@ public class FastDateParser implements DateParser, Serializable {
     private final Locale locale;
     private final int century;
     private final int startYear;
+    private final boolean lenient;
 
     // derived fields
     private transient Pattern parsePattern;
@@ -106,7 +107,7 @@ public class FastDateParser implements DateParser, Serializable {
      * @param locale non-null locale
      */
     protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale) {
-        this(pattern, timeZone, locale, null);
+        this(pattern, timeZone, locale, null, true);
     }
 
     /**
@@ -121,11 +122,31 @@ public class FastDateParser implements DateParser, Serializable {
      * @since 3.3
      */
     protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
+        this(pattern, timeZone, locale, centuryStart, true);
+    }
+
+    /**
+     * <p>Constructs a new FastDateParser.</p>
+     *
+     * @param pattern non-null {@link java.text.SimpleDateFormat} compatible
+     *  pattern
+     * @param timeZone non-null time zone to use
+     * @param locale non-null locale
+     * @param centuryStart The start of the century for 2 digit year parsing
+     * @param lenient if true, non-standard values for Calendar fields should be accepted;
+     * if false, non-standard values will cause a ParseException to be thrown {@link CalendaretLenient(boolean)}
+     *
+     * @since 3.5
+     */
+    protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale,
+            final Date centuryStart, final boolean lenient) {
         this.pattern = pattern;
         this.timeZone = timeZone;
         this.locale = locale;
+        this.lenient = lenient;
 
         final Calendar definingCalendar = Calendar.getInstance(timeZone, locale);
+
         int centuryStartYear;
         if(centuryStart!=null) {
             definingCalendar.setTime(centuryStart);
@@ -336,6 +357,7 @@ public class FastDateParser implements DateParser, Serializable {
         // timing tests indicate getting new instance is 19% faster than cloning
         final Calendar cal= Calendar.getInstance(timeZone, locale);
         cal.clear();
+        cal.setLenient(lenient);
 
         for(int i=0; i<strategies.length;) {
             final Strategy strategy= strategies[i++];

http://git-wip-us.apache.org/repos/asf/commons-lang/blob/bea1ae92/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java b/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java
index b0a6b5d..5a1d69f 100644
--- a/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/time/DateFormatUtilsTest.java
@@ -23,6 +23,7 @@ import static org.junit.Assert.assertTrue;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
+import java.text.ParseException;
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Locale;
@@ -268,4 +269,20 @@ public class DateFormatUtilsTest {
         String date = "2013-11-18T12:48:05Z";
         DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.parse(date);
     }
+
+    @Test
+    public void testLang530() throws ParseException {
+        TimeZone save = TimeZone.getDefault();
+        try {
+            TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
+            final Date d = new Date();
+            final String isoDateStr = DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(d);
+            final Date d2 = DateUtils.parseDate(isoDateStr, new String[] { DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.getPattern() });
+            // the format loses milliseconds so have to reintroduce them
+            assertEquals("Date not equal to itself ISO formatted and parsed", d.getTime(), d2.getTime() + d.getTime() % 1000);
+        }
+        finally {
+            TimeZone.setDefault(save);
+        }
+    }
 }