Skip to content

Commit

Permalink
Merge pull request #30 from jcookems/fix228
Browse files Browse the repository at this point in the history
Fix 228: Table: DateTime serialization for milliseonds
  • Loading branch information
jcookems committed Apr 4, 2012
2 parents d59baba + f86207f commit e21de2b
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,6 @@ public Date unmarshal(String arg0) throws Exception {

@Override
public String marshal(Date arg0) throws Exception {
return new ISO8601DateConverter().format(arg0);
return new ISO8601DateConverter().shortFormat(arg0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
Expand All @@ -26,38 +27,60 @@
*/
public class ISO8601DateConverter {
// Note: because of the trailing "0000000", this is not quite ISO 8601 compatible
private static final String DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z'";
private static final String DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
private static final String SHORT_DATETIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss'Z'";
private static final String DATETIME_PATTERN_NO_S = "yyyy-MM-dd'T'HH:mm'Z'";
private static final String DATETIME_PATTERN_TO_DECIMAL = "yyyy-MM-dd'T'HH:mm:ss.";

public String format(Date date) {
return getFormat().format(date);
DateFormat iso8601Format = new SimpleDateFormat(DATETIME_PATTERN, Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
return iso8601Format.format(date);
}

public String shortFormat(Date date) {
return getShortFormat().format(date);
DateFormat iso8601Format = new SimpleDateFormat(SHORT_DATETIME_PATTERN, Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
return iso8601Format.format(date);
}

public Date parse(String date) throws ParseException {
if (date == null)
return null;

// Sometimes, the date comes back without the ".SSSSSSS" part (presumably when the decimal value
// of the date is "0". Use the short format in that case.
if (date.indexOf('.') < 0)
return getShortFormat().parse(date);
else
return getFormat().parse(date);
}
int length = date.length();
if (length == 17) {
// [2012-01-04T23:21Z] length = 17
return parseDateFromString(date, DATETIME_PATTERN_NO_S);
}
else if (length == 20) {
// [2012-01-04T23:21:59Z] length = 20
return parseDateFromString(date, SHORT_DATETIME_PATTERN);
}
else if (length >= 22 && length <= 28) {
// [2012-01-04T23:21:59.1Z] length = 22
// [2012-01-04T23:21:59.1234567Z] length = 28
// Need to handle the milliseconds gently.

private DateFormat getFormat() {
DateFormat iso8601Format = new SimpleDateFormat(DATETIME_PATTERN, Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
return iso8601Format;
Date allExceptMilliseconds = parseDateFromString(date, DATETIME_PATTERN_TO_DECIMAL);
long timeWithSecondGranularity = allExceptMilliseconds.getTime();
// Decimal point is at 19
String secondDecimalString = date.substring(19, date.indexOf('Z'));
Float secondDecimal = Float.parseFloat(secondDecimalString);
int milliseconds = Math.round(secondDecimal * 1000);
long timeInMS = timeWithSecondGranularity + milliseconds;
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timeInMS);
return calendar.getTime();
}
else {
throw new IllegalArgumentException(String.format("Invalid Date String: %s", date));
}
}

private DateFormat getShortFormat() {
DateFormat iso8601Format = new SimpleDateFormat(SHORT_DATETIME_PATTERN, Locale.US);
private static Date parseDateFromString(final String value, final String pattern) throws ParseException {
DateFormat iso8601Format = new SimpleDateFormat(pattern, Locale.US);
iso8601Format.setTimeZone(TimeZone.getTimeZone("GMT"));
return iso8601Format;
return iso8601Format.parse(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ private InputStream generateEntry(PropertiesWriter propertiesWriter) {
writer.writeEndElement(); // title

writer.writeStartElement("updated");
writer.writeCharacters(iso8601DateConverter.shortFormat(dateFactory.getDate()));
writer.writeCharacters(iso8601DateConverter.format(dateFactory.getDate()));
writer.writeEndElement(); // updated

writer.writeStartElement("author");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public String serialize(String edmType, Object value) {

String serializedValue;
if (value instanceof Date) {
serializedValue = iso8601DateConverter.shortFormat((Date) value);
serializedValue = iso8601DateConverter.format((Date) value);
}
else if (value instanceof byte[]) {
serializedValue = new String(Base64.encode((byte[]) value));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

import static org.junit.Assert.*;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import org.junit.Test;

Expand All @@ -29,9 +31,23 @@ public void shortFormatWorks() throws Exception {

// Act
Date result = converter.parse(value);
String value2 = converter.format(result);

// Assert
assertNotNull(result);

Calendar calendar = Calendar.getInstance();
calendar.setTime(result);
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals("Year", 2012, calendar.get(Calendar.YEAR));
assertEquals("Month", 1, calendar.get(Calendar.MONTH) + 1);
assertEquals("Day", 12, calendar.get(Calendar.DAY_OF_MONTH));
assertEquals("Hour", 0, calendar.get(Calendar.HOUR));
assertEquals("Minute", 35, calendar.get(Calendar.MINUTE));
assertEquals("Second", 58, calendar.get(Calendar.SECOND));
assertEquals("Millisecond", 0, calendar.get(Calendar.MILLISECOND));

assertEquals("2012-01-12T00:35:58.000Z", value2);
}

@Test
Expand All @@ -42,9 +58,50 @@ public void longFormatWorks() throws Exception {

// Act
Date result = converter.parse(value);
String value2 = converter.format(result);

// Assert
assertNotNull(result);

Calendar calendar = Calendar.getInstance();
calendar.setTime(result);
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals("Year", 2012, calendar.get(Calendar.YEAR));
assertEquals("Month", 1, calendar.get(Calendar.MONTH) + 1);
assertEquals("Day", 12, calendar.get(Calendar.DAY_OF_MONTH));
assertEquals("Hour", 0, calendar.get(Calendar.HOUR));
assertEquals("Minute", 35, calendar.get(Calendar.MINUTE));
assertEquals("Second", 58, calendar.get(Calendar.SECOND));
assertEquals("Millisecond", 123, calendar.get(Calendar.MILLISECOND));

assertEquals("2012-01-12T00:35:58.123Z", value2);
}

@Test
public void mixedFormatWorks() throws Exception {
// Arrange
ISO8601DateConverter converter = new ISO8601DateConverter();
String value = "2012-01-12T00:35:58.12Z";

// Act
Date result = converter.parse(value);
String value2 = converter.format(result);

// Assert
assertNotNull(result);

Calendar calendar = Calendar.getInstance();
calendar.setTime(result);
calendar.setTimeZone(TimeZone.getTimeZone("GMT"));
assertEquals("Year", 2012, calendar.get(Calendar.YEAR));
assertEquals("Month", 1, calendar.get(Calendar.MONTH) + 1);
assertEquals("Day", 12, calendar.get(Calendar.DAY_OF_MONTH));
assertEquals("Hour", 0, calendar.get(Calendar.HOUR));
assertEquals("Minute", 35, calendar.get(Calendar.MINUTE));
assertEquals("Second", 58, calendar.get(Calendar.SECOND));
assertEquals("Millisecond", 120, calendar.get(Calendar.MILLISECOND));

assertEquals("2012-01-12T00:35:58.120Z", value2);
}

@Test
Expand All @@ -56,9 +113,11 @@ public void shortFormatRoundTrips() throws Exception {
// Act
Date result = converter.parse(value);
String value2 = converter.shortFormat(result);
String value3 = converter.format(result);

// Assert
assertNotNull(result);
assertEquals(value, value2);
assertEquals("2012-01-12T00:35:58.000Z", value3);
}
}

0 comments on commit e21de2b

Please sign in to comment.