I was developing a part of code where I had to use existing api using Calendar API where I was using purely new API. Got some strange behavior in the conversion, see this example:
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
String date1 = "0000-01-01T00:00:00Z";
Calendar calendar = Calendar.getInstance();
calendar.setTime(df.parse(date1));
Instant instant = calendar.toInstant();
ZonedDateTime zonedDateTime = instant.atZone(calendar.getTimeZone().toZoneId());
System.out.println(calendar.getTime() + " " +calendar.getTimeZone().getDisplayName());
System.out.println(instant.toString());
System.out.println(zonedDateTime.toString());
String date2 = "0000-01-01T00:00:00+01:00";
calendar.setTime(df.parse(date2));
instant = calendar.toInstant();
zonedDateTime = instant.atZone(calendar.getTimeZone().toZoneId());
System.out.println(calendar.getTime() + " " +calendar.getTimeZone().getDisplayName());
System.out.println(instant.toString());
System.out.println(zonedDateTime.toString());
The output I am getting is as follows:
Thu Jan 01 01:00:00 CET 1 Central European Standard Time
-0001-12-30T00:00:00Z
-0001-12-30T00:09:21+00:09:21[Europe/Paris]
Thu Jan 01 00:00:00 CET 1 Central European Standard Time
-0001-12-29T23:00:00Z
-0001-12-29T23:09:21+00:09:21[Europe/Paris]
So the first line from Gregorian calendar is correct for both cases:
- we get 1st of Jan 1:00 AM at +01:00 zone in case1
- we get 1st of Jan 0:00 AM at +01:00 zone in case2
After converting from Calendar
to Instant
we already see problem with a date because we are now suddenly:
- on 30th of Dec (48 hours before) in case 1
- on 29th of Dec (72 hours before) in case 2 ... also found there is also a small random inaccuracy of couple of hundreds of milliseconds introduced during conversion which you can't see here
Now when we convert next from Instant
to ZonedDateTime
we are now
- 9 minutes 21 seconds later because timezone Europe/Paris passed to
instant.atZone()
resulted in strange timezone of +00:09:21
I tested it more and generally conversion between Calendar
and Instant
is becoming heavily unreliable for dates before year 1583 while Instant
to Local/ZonedDateTime
becomes unreliable due to timezone issue for dates before 1911.
Now I know that hardly anybody stores/converts time for dates before 1911 (but I can still imagine such use case), but hey! lets see when Christopher Columbus departed to discovered America!:
1492-08-03
1492-08-11T23:00:00Z
1492-08-11
As a result I've also found that getting epoch millis from both apis yeld different results for same ISO date at early years before 1911 (problem seems to be in Calendar implementation):
System.out.println(Instant.parse("1911-01-01T00:00:00Z").toEpochMilli());
calendar.setTime(df.parse("1911-01-01T00:00:00Z"));
System.out.println(calendar.getTimeInMillis());
What is the correct way to convert so it would 'just work' (tm) ?
Note: So far I think the most safe way is to convert to ISO date string first. Is there any better solution?