Harsha G
Harsha G

Reputation: 39

Formatting ISO 8601 in Java 7

I have date format like this 2016-11-25T09:29:10.588+01:00

I want to convert this to milliseconds and later while printing I have to again convert milliseconds to "yyyy-MM-dd HH:mm:ss.SSS" this format.

static FastDateFormat alarmDateFormat = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS");
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSXXX");
df1.setTimeZone(TimeZone.getTimeZone("UTC"));
String string1 = "2016-11-25T09:29:10.588+01:00";
Date result1 = df1.parse(string1);
long timeStamp = result1.getTime();
System.out.println("timeStamp : " +timeStamp);
String eventTime = alarmDateFormat.format(timeStamp);
System.out.println("AfterConverting : " + eventTime);

Result :

timeStamp : 1480062550588
AfterConverting : 2016-11-25 13:59:10.588

Date is proper but the time is different. I have tried setting timezone to "UTC" but it did't help.

Please note: In Java 8 it works fine with other libraries like Instant and all but we wanted in Java 7.

Upvotes: 2

Views: 3744

Answers (1)

user7605325
user7605325

Reputation:

You're calling setTimeZone in df1, but this formatter is used only for parsing, and it won't have any effect in formatting.

To format the date to a specific timezone, you must set it in the other formatter (if you don't set, the formatter uses the JVM default timezone). Also, you don't need to rely on another class such as FastDateFormat, you can simply use another SimpleDateFormat.

But to get exactly the same date/time, you need to use the same offset used in the input (+01:00). Date objects don't keep this information, so you must extract it from the input. One way would be to use substring:

SimpleDateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSXXX");
String string1 = "2016-11-25T09:29:10.588+01:00";
Date result1 = df1.parse(string1);
long timeStamp = result1.getTime();
System.out.println("timeStamp : " + timeStamp);

// extract the +01:00 offset from the input
String offset = string1.substring(23);
SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
// set the offset in the formatter (so output is converted to it)
df2.setTimeZone(TimeZone.getTimeZone("GMT" + offset));
String eventTime = df2.format(timeStamp);
System.out.println("AfterConverting : " + eventTime);

The output will be:

timeStamp : 1480062550588
AfterConverting : 2016-11-25 09:29:10.588

If you want to keep using FastDateFormat, it's also possible to set the timezone in it:

FastDateFormat f = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS", TimeZone.getTimeZone("GMT" + offset));
String eventTime = f.format(timeStamp);

Java new Date/Time API

The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.

For Java 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).

With this, you can parse the input to a org.threeten.bp.OffsetDateTime and use a org.threeten.bp.format.DateTimeFormatter for the output. In this case, the OffsetDateTime keeps the offset information, so you don't need to set it in the formatter:

OffsetDateTime odt = OffsetDateTime.parse(string1);
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println("timeStamp : " + odt.toInstant().toEpochMilli());
System.out.println("AfterConverting : " + odt.format(fmt));

The output is the same:

timeStamp : 1480062550588
AfterConverting : 2016-11-25 09:29:10.588

Upvotes: 4

Related Questions