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:
LocalDateTime#parse
approach to get the correct result? 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.
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());