Fixed [JACKSON-206], support for yet another iso-8601 date/time variation

diff --git a/release-notes/VERSION b/release-notes/VERSION
index 71463f8..48149c5 100644
--- a/release-notes/VERSION
+++ b/release-notes/VERSION
@@ -36,6 +36,24 @@
 == History: ==
 ------------------------------------------------------------------------
 
+1.3.1 [23-Nov-2009]
+
+  Fixes:
+
+  * [JACKSON-190] Problems deserializing certain nested generic types
+   (reported by Nathan C)
+  * [JACKSON-194] ObjectMapper class loading issues on Android
+   (reported by Martin L)
+  * [JACKSON-197] Remove 2 debug messages that print out to System.err
+   (reported by Edward T)
+  * [JACKSON-200] java.sql.Date deserialization not working well
+   (reported by Steve L)
+  * [JACKSON-202] Non-public fields not deserialized properly with
+    JAXB annotations
+   (reported by Mike P)
+  * [JACKSON-203] Date deserializers should map empty String to null
+   (reported by Steve L)
+
 1.3.0 [30-Oct-2009]
 
   Fixes:
diff --git a/src/mapper/java/org/codehaus/jackson/map/util/StdDateFormat.java b/src/mapper/java/org/codehaus/jackson/map/util/StdDateFormat.java
index 689dcad..0f1728e 100644
--- a/src/mapper/java/org/codehaus/jackson/map/util/StdDateFormat.java
+++ b/src/mapper/java/org/codehaus/jackson/map/util/StdDateFormat.java
@@ -17,6 +17,11 @@
 public class StdDateFormat
     extends DateFormat
 {
+    /* TODO !!! 24-Nov-2009, tatu: Need to rewrite this class soon:
+     * JDK date parsing is awfully brittle, and ISO-8601 is quite
+     * permissive. The two don't mix, need to write a better one.
+     */
+
     /**
      * Defines a commonly used date format that conforms
      * to ISO-8601 date formatting standard, when it includes basic undecorated
@@ -244,21 +249,40 @@
                 df = _formatISO8601_z = (SimpleDateFormat) DATE_FORMAT_ISO8601_Z.clone();
             }
         } else {
-            c = dateStr.charAt(len-3);
-            if (c == ':') { // remove optional colon
-                // remove colon
-                StringBuilder sb = new StringBuilder(dateStr);
-                sb.delete(len-3, len-2);
-                dateStr = sb.toString();
-            } else if (c == '+' || c == '-') { // missing minutes
-                // let's just append '00'
-                dateStr += "00";
-            }
-            // otherwise regular (or invalid)
+            // Let's see if we have timezone indicator or not...
+            if (hasTimeZone(dateStr)) {
+                c = dateStr.charAt(len-3);
+                if (c == ':') { // remove optional colon
+                    // remove colon
+                    StringBuilder sb = new StringBuilder(dateStr);
+                    sb.delete(len-3, len-2);
+                    dateStr = sb.toString();
+                } else if (c == '+' || c == '-') { // missing minutes
+                    // let's just append '00'
+                    dateStr += "00";
+                }
+                df = _formatISO8601;
+                if (_formatISO8601 == null) {
+                    df = _formatISO8601 = (SimpleDateFormat) DATE_FORMAT_ISO8601.clone();
+                }
+            } else {
+                /* 24-Nov-2009, tatu: Ugh. This is getting pretty
+                 *   ugly. Need to rewrite soon!
+                 */
 
-            df = _formatISO8601;
-            if (_formatISO8601 == null) {
-                df = _formatISO8601 = (SimpleDateFormat) DATE_FORMAT_ISO8601.clone();
+                // If not, plain date. Easiest to just patch 'Z' in the end?
+                StringBuilder sb = new StringBuilder(dateStr);
+                // And possible also millisecond part if missing
+                int timeLen = len - dateStr.lastIndexOf('T') - 1;
+                if (timeLen <= 8) {
+                    sb.append(".000");
+                }
+                sb.append('Z');
+                dateStr = sb.toString();
+                df = _formatISO8601_z;
+                if (df == null) {
+                    df = _formatISO8601_z = (SimpleDateFormat) DATE_FORMAT_ISO8601_Z.clone();
+                }
             }
         }
         return df.parse(dateStr, pos);
@@ -271,5 +295,20 @@
         }
         return _formatRFC1123.parse(dateStr, pos);
     }
+
+    private final static boolean hasTimeZone(String str)
+    {
+        // Only accept "+hh", "+hhmm" and "+hh:mm" (and with minus), so
+        int len = str.length();
+        if (len >= 6) {
+            char c = str.charAt(len-6);
+            if (c == '+' || c == '-') return true;
+            c = str.charAt(len-5);
+            if (c == '+' || c == '-') return true;
+            c = str.charAt(len-3);
+            if (c == '+' || c == '-') return true;
+        }
+        return false;
+    }
 }
 
diff --git a/src/test/org/codehaus/jackson/map/deser/TestDateDeserialization.java b/src/test/org/codehaus/jackson/map/deser/TestDateDeserialization.java
index e160c9b..fca8d9a 100644
--- a/src/test/org/codehaus/jackson/map/deser/TestDateDeserialization.java
+++ b/src/test/org/codehaus/jackson/map/deser/TestDateDeserialization.java
@@ -77,14 +77,6 @@
         assertEquals(Calendar.DECEMBER, c.get(Calendar.MONTH));
         assertEquals(28, c.get(Calendar.DAY_OF_MONTH));
 
-        // And finally, plain date (no time)
-        inputStr = "1972-12-28";
-        inputDate = mapper.readValue(quote(inputStr), java.util.Date.class);
-        c.setTime(inputDate);
-        assertEquals(1972, c.get(Calendar.YEAR));
-        assertEquals(Calendar.DECEMBER, c.get(Calendar.MONTH));
-        assertEquals(28, c.get(Calendar.DAY_OF_MONTH));
-
         inputStr = "1984-11-30T00:00:00.000Z";
         inputDate = mapper.readValue(quote(inputStr), java.util.Date.class);
         c.setTime(inputDate);
@@ -93,6 +85,38 @@
         assertEquals(30, c.get(Calendar.DAY_OF_MONTH));
     }
 
+    public void testDateUtilISO8601NoTimezone() throws Exception
+    {
+        ObjectMapper mapper = new ObjectMapper();
+        // Timezone itself is optional as well... 
+        String inputStr = "1984-11-13T00:00:09";
+        Date inputDate = mapper.readValue(quote(inputStr), java.util.Date.class);
+        Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        c.setTime(inputDate);
+        assertEquals(1984, c.get(Calendar.YEAR));
+        assertEquals(Calendar.NOVEMBER, c.get(Calendar.MONTH));
+        assertEquals(13, c.get(Calendar.DAY_OF_MONTH));
+        assertEquals(0, c.get(Calendar.HOUR_OF_DAY));
+        assertEquals(0, c.get(Calendar.MINUTE));
+        assertEquals(9, c.get(Calendar.SECOND));
+        assertEquals(0, c.get(Calendar.MILLISECOND));
+    }
+
+    public void testDateUtilISO8601JustDate() throws Exception
+    {
+        ObjectMapper mapper = new ObjectMapper();
+        // Plain date (no time)
+        String inputStr = "1972-12-28";
+        Date inputDate = mapper.readValue(quote(inputStr), java.util.Date.class);
+        Calendar c = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
+        c.setTime(inputDate);
+        assertEquals(1972, c.get(Calendar.YEAR));
+        assertEquals(Calendar.DECEMBER, c.get(Calendar.MONTH));
+        assertEquals(28, c.get(Calendar.DAY_OF_MONTH));
+
+    }
+
+
     @SuppressWarnings("deprecation")
     public void testDateSql() throws Exception
     {