Author: niallp
Date: Sat Jan 30 17:49:28 2010
New Revision: 904829

URL: http://svn.apache.org/viewvc?rev=904829&view=rev
Log:
Port LANG-530 to 2.x branch - Fix parseDate() cannot parse ISO8601 dates 
produced by FastDateFormat

Modified:
    
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/time/DateUtils.java
    
commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/time/DateUtilsTest.java

Modified: 
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/time/DateUtils.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/time/DateUtils.java?rev=904829&r1=904828&r2=904829&view=diff
==============================================================================
--- 
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/time/DateUtils.java
 (original)
+++ 
commons/proper/lang/branches/LANG_2_X/src/main/java/org/apache/commons/lang/time/DateUtils.java
 Sat Jan 30 17:49:28 2010
@@ -25,6 +25,8 @@
 import java.util.NoSuchElementException;
 import java.util.TimeZone;
 
+import org.apache.commons.lang.StringUtils;
+
 /**
  * <p>A suite of utilities surrounding the use of the
  * {...@link java.util.Calendar} and {...@link java.util.Date} object.</p>
@@ -78,6 +80,9 @@
      */
     public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
 
+    /** Sign characters */
+    private static final char[] SIGN_CHARS = new char[] {'+', '-'};
+
     /**
      * This is half a month, so this represents whether a date is in the top
      * or bottom half of the month.
@@ -286,19 +291,66 @@
         SimpleDateFormat parser = null;
         ParsePosition pos = new ParsePosition(0);
         for (int i = 0; i < parsePatterns.length; i++) {
+
+            String pattern = parsePatterns[i];
+
+            // LANG-530 - need to make sure 'ZZ' output doesn't get passed to 
SimpleDateFormat
+            if (parsePatterns[i].endsWith("ZZ")) {
+                pattern = pattern.substring(0, pattern.length() - 1);
+            }
+            
             if (i == 0) {
-                parser = new SimpleDateFormat(parsePatterns[0]);
+                parser = new SimpleDateFormat(pattern);
             } else {
-                parser.applyPattern(parsePatterns[i]);
+                parser.applyPattern(pattern); // cannot be null if i != 0
             }
             pos.setIndex(0);
-            Date date = parser.parse(str, pos);
-            if (date != null && pos.getIndex() == str.length()) {
+
+            String str2 = str;
+            // LANG-530 - need to make sure 'ZZ' output doesn't hit 
SimpleDateFormat as it will ParseException
+            if (parsePatterns[i].endsWith("ZZ")) {
+                int signIdx  = indexOfSignChars(str2, 0);
+                while (signIdx >=0) {
+                    str2 = reformatTimezone(str2, signIdx);
+                    signIdx = indexOfSignChars(str2, ++signIdx);
+                }
+            }
+
+            Date date = parser.parse(str2, pos);
+            if (date != null && pos.getIndex() == str2.length()) {
                 return date;
             }
         }
         throw new ParseException("Unable to parse the date: " + str, -1);
     }
+    private static int indexOfSignChars(String str, int startPos) {
+        int idx = StringUtils.indexOf(str, '+', startPos);
+        if (idx < 0) {
+            idx = StringUtils.indexOf(str, '-', startPos);
+        }
+        return idx;
+    }
+
+    /**
+     * Reformat the timezone in a date string.
+     *
+     * @param str The input string
+     * @param signIdx The index position of the sign characters
+     * @return The reformatted string
+     */
+    private static String reformatTimezone(String str, int signIdx) {
+        String str2 = str;
+        if (signIdx >= 0 &&
+            signIdx + 5 < str.length() &&
+            Character.isDigit(str.charAt(signIdx + 1)) &&
+            Character.isDigit(str.charAt(signIdx + 2)) &&
+            str.charAt(signIdx + 3) == ':' &&
+            Character.isDigit(str.charAt(signIdx + 4)) &&
+            Character.isDigit(str.charAt(signIdx + 5))) {
+            str2 = str.substring(0, signIdx + 3) + str.substring(signIdx + 4);
+        }
+        return str2;
+    }
 
     //-----------------------------------------------------------------------
     /**

Modified: 
commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/time/DateUtilsTest.java
URL: 
http://svn.apache.org/viewvc/commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/time/DateUtilsTest.java?rev=904829&r1=904828&r2=904829&view=diff
==============================================================================
--- 
commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/time/DateUtilsTest.java
 (original)
+++ 
commons/proper/lang/branches/LANG_2_X/src/test/java/org/apache/commons/lang/time/DateUtilsTest.java
 Sat Jan 30 17:49:28 2010
@@ -1170,6 +1170,15 @@
         TimeZone.setDefault(defaultZone);
     }
 
+    // http://issues.apache.org/jira/browse/LANG-520
+    public void testLang520() throws ParseException {
+        Date d = new Date();
+        String isoDateStr = 
DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT.format(d);
+        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); 
+    }
+    
     /**
      * Tests various values with the ceiling method
      */


Reply via email to