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.
You are misunderstanding the purpose of
LocalDateTime
.To quote the class documentation:
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
withZoneId.systemDefault()
as you already used in your third example.For your second example this could be:
tl;dr
LocalDateTime
.Instant
&ZonedDateTime
.Example:
Run in IdeOne.com.
Details
The Answer by Krüske is correct. You misunderstand the meaning of
LocalDateTime
class. It does not represent the date-time of a particular locality. Just the opposite, it does not represent an actual moment at all.I suggest thinking of
Instant
as your basic building-block class in java.time. TheInstant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).Your input string complies with the ISO 8601 format used by default in the
Instant
class for both parsing and generating string representations. TheZ
on the end is short forZulu
and means UTC. No need to specify a formatting pattern.As a programmer you should learn to think and work in UTC primarily. Forget about your own time zone. Think of UTC as the One True Time. Apply a time zone as a variation, and only as needed.
Specify a proper time zone name in the format of
continent/region
, such asAmerica/Montreal
,Africa/Casablanca
, orPacific/Auckland
. Never use the 3-4 letter abbreviation such asBST
orEST
orIST
as they are not true time zones, not standardized, and not even unique(!). If byBST
you meant British Summer Time, then the actual time zone name would beEurope/London
. The java.time classes will determine how to adjust for any anomalies including Daylight Saving Time (DST).About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as
java.util.Date
,Calendar
, &SimpleDateFormat
.The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as
Interval
,YearWeek
,YearQuarter
, and more.