Hi, I noticed that with the following data:
LocalDateTime ldt = LocalDateTime.parse("2017-01-01T00:00:00"); ZonedDateTime dt1 = ZonedDateTime.of(ldt, ZoneId.of("GMT+10")); ZonedDateTime dt2 = ZonedDateTime.of(ldt, ZoneId.of("UTC+10")); dt1.equals(dt2) returns true as expected, but with: GregorianCalendar gc1 = GregorianCalendar.from(dt1); GregorianCalendar gc2 = GregorianCalendar.from(dt2); gc1.equals(gc2) returns false. Looking at the code, I see when a GregorianCalendar is being constructed, TimeZone.getTimeZone() gets called, but it doesn't recognise UTC time-zones with offsets, and falls back to GMT(+0), whereas ZoneId treats GMT and UTC based zones equivalently. PFA a patch to fix this. Thank you, Naufal
diff -r 65464a307408 src/java.base/share/classes/java/util/TimeZone.java --- a/src/java.base/share/classes/java/util/TimeZone.java Thu Aug 03 18:56:59 2017 +0000 +++ b/src/java.base/share/classes/java/util/TimeZone.java Sat Dec 16 10:10:14 2017 +0000 @@ -782,7 +782,8 @@ private static volatile TimeZone defaultTimeZone; static final String GMT_ID = "GMT"; - private static final int GMT_ID_LENGTH = 3; + static final String UTC_ID = "UTC"; + private static final int GMT_UTC_ID_LENGTH = 3; // a static TimeZone we can reference if no AppContext is in place private static volatile TimeZone mainAppContextDefault; @@ -799,9 +800,9 @@ int length; // Error if the length of id isn't long enough or id doesn't - // start with "GMT". - if ((length = id.length()) < (GMT_ID_LENGTH + 2) || - id.indexOf(GMT_ID) != 0) { + // start with "GMT" or "UTC". + if ((length = id.length()) < (GMT_UTC_ID_LENGTH + 2) || + id.indexOf(GMT_ID) != 0 && id.indexOf(UTC_ID) != 0) { return null; } @@ -815,7 +816,7 @@ return zi; } - int index = GMT_ID_LENGTH; + int index = GMT_UTC_ID_LENGTH; boolean negative = false; char c = id.charAt(index++); if (c == '-') {