Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 328
pandaadb Avatar asked Sep 12 '16 13:09

pandaadb


1 Answers

You are misunderstanding the purpose of LocalDateTime.

To quote the class documentation:

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

This class does not store or represent a time-zone. Instead, it is a description of the date, as used for birthdays, combined with the local time as seen on a wall clock. It cannot represent an instant on the time-line without additional information such as an offset or time-zone.

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());
like image 197
Michaela Maura Elschner Avatar answered Sep 20 '22 12:09

Michaela Maura Elschner