Skip to content

Large ISO-8601 Dates are formatted/serialized incorrectly #2167

@joaoe

Description

@joaoe

The problem

java.text.ParseException: Cannot parse date "痝055-12-02T16:47:04.192+0000": not compatible with any of standard forms ("yyyy-MM-dd'T'HH:mm:ss.SSSZ", "yyyy-MM-dd'T'HH:mm:ss.SSS", "EEE, dd MMM yyyy HH:mm:ss zzz", "yyyy-MM-dd")
	at com.fasterxml.jackson.databind.util.StdDateFormat.parse(StdDateFormat.java:372)

Years > 9999 are not rendered as 5 numbers or more, but with a non numerical characters for the thousands digit..

The testcase

public class MyTestCase{
  public static void main(String[] args) throws JsonProcessingException, ParseException {
    StdDateFormat formatter = new StdDateFormat();
    System.out.println(formatter.format(new Date(Long.MIN_VALUE)));
    System.out.println(formatter.format(new Date(Long.MAX_VALUE)));
    System.out.println(formatter.parse(formatter.format(new Date(Long.MIN_VALUE))));
    System.out.println(formatter.parse(formatter.format(new Date(Long.MAX_VALUE))));

    assert formatter.parse(formatter.format(new Date(Long.MAX_VALUE))).getTime() == Long.MAX_VALUE;
    // Will fail due to lack of support for negative dates.
    //assert formatter.parse(formatter.format(new Date(Long.MIN_VALUE))).getTime() == Long.MIN_VALUE;
  }
}

Expected

a) All dates are formatted correctly, meaning, years bigger than 9999.
b) or some sort of exception telling the data is not supported.

The location
'0' + something
https://github.com/FasterXML/jackson-databind/blob/master/src/main/java/com/fasterxml/jackson/databind/util/StdDateFormat.java#L442

Suggestion
a) Adding '0' with an integer is not a safe operation. But if you are doing it, you need an upper bound check, e.g.:

 private static void pad2(StringBuffer buffer, int value) {
     int tens = value / 10;
+    if (tens >= 10) {
+        pad2(buffer, tens);
+        buffer.append((char) ('0' + value % 10));
+        return;
+    }
     if (tens == 0) {
         buffer.append('0');
     } else {
         buffer.append((char) ('0' + tens));
         value -= 10 * tens;
     }
     buffer.append((char) ('0' + value));
 }
 
 private static void pad3(StringBuffer buffer, int value) {
     int h = value / 100;
+    if (h >= 100) {
+        pad3(buffer, h);
+        pad2(buffer, value % 100);
+        return;
+    }
     if (h == 0) {
         buffer.append('0');
     } else {
         buffer.append((char) ('0' + h));
         value -= (h * 100);
     }
     pad2(buffer, value);
 }

b) Or if you do not want to support such high years, then throw some sort of exception. E.g.:

     protected void _format(TimeZone tz, Locale loc, Date date,
             StringBuffer buffer)
     {
         Calendar cal = _getCalendar(tz);
         cal.setTime(date);

+        int year = cal.get(Calendar.YEAR);
+        if (cal.get(Calendar.ERA) == 0) {
+            year = -year + 1;
+        }
+        if (year < 0 || 9999 < year) {
+            throw new IndexOutOfBoundsException("Year not within the range [0,9999]: " + Integer.toString(year))
+        }
 
-        pad4(buffer, cal.get(Calendar.YEAR));
+        pad4(buffer, year);
         buffer.append('-');
         pad2(buffer, cal.get(Calendar.MONTH) + 1);
         buffer.append('-');
         pad2(buffer, cal.get(Calendar.DAY_OF_MONTH));

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions