pandaadb pandaadb - 2 months ago 28
Java Question

Confusion with Java Time parsing UTC

I am confused with time handling in java time. I so long worked under the assumption that if a timestamp is specified as a zulu time, java would take care of the offset with regards to local time.

To illustrate. I am currently in BST which has an offset of UTC +1. With that in mind, I would expect this zulu time:

2016-09-12T13:15:17.309Z


to be

2016-09-12T14:15:17.309


LocalDateTime after parsing it. This is because my default systemtime is set to BST and the above timestamp (zulu time) specifies that it is a UTC time.

Instead however consider this sample:

String ts = "2016-09-12T13:15:17.309Z";
LocalDateTime parse = LocalDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
System.out.println(parse);


This will print:

2016-09-12T13:15:17.309


So the timestamp, parsed as a LocalDateTime, is not recognised as UTC time and instead treated as localtime directly.
So I thought, maybe I need to parse it as a ZonedDateTime and convert it to LocalDateTime specifically in order to get the correct local time. With this test:

String ts = "2016-09-12T13:15:17.309Z";
ZonedDateTime parse = ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME);
System.out.println(parse);
System.out.println(parse.toLocalDateTime());


I get the outputs:

2016-09-12T13:15:17.309Z
2016-09-12T13:15:17.309


Same output for both dates.

The only way to correctly parse this that I could find, is:

String ts = "2016-09-12T13:15:17.309Z";
Instant instant = Instant.parse(ts); // parses UTC
LocalDateTime ofInstant = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println(instant);
System.out.println(ofInstant);


This prints:

2016-09-12T13:15:17.309Z
2016-09-12T14:15:17.309


Which is correct.

So the question(s) are:


  • Shouldn't java time recognise a UTC timestamp and parse it to the correct system default?

  • How can I use the
    LocalDateTime#parse
    approach to get the correct result?

  • Should I use
    Instant
    for everything now and discard the parsing?



The issue is that
jersey/jackson
's java time modules parse the timestamps using the ISO format and the regular
LocalDateTime#parse
methods. I realised that my times are no off since they are being treated as
LocalTime
while in fact they are in Zulu time.

Answer

You are misunderstanding the purpose of LocalDateTime.

As describe in the JavaDocs it's:

A date-time without a time-zone in the ISO-8601 calendar system,
such as {@code 2007-12-03T10:15:30}.

So it's explicit purpose is just to represent a date and time without a time-zone. It's porpose is not to represent a date and time in the local time zone.

Therefore each conversion just strips the time zone.

So for your purposes you need a ZonedDateTime with ZoneId.systemDefault() as you already used in your third example.

For your second example this could be:

String ts = "2016-09-12T13:15:17.309Z";
ZonedDateTime parse = 
    ZonedDateTime.parse(ts, DateTimeFormatter.ISO_DATE_TIME)
        .withZoneSameInstant(ZoneId.systemDefault());
System.out.println(parse);
System.out.println(parse.toLocalDateTime());