As the Answer by Matt Johnson said:
- Use a proper time zone name in the
continent/region
format. Avoid the 3-4 letter codes that are neither unique nor standardized.
- Use the java.time framework built into Java 8 and later. See Tutorial. Avoid the old date-time classes, java.util.Date/.Calendar.
An Instant
is a moment on the timeline in UTC with nanosecond resolution. Apply a time zone (ZoneId
) to get a ZonedDateTime
.
Long input = 1457928024812L;
Instant instant = Instant.ofEpochMilli ( input );
ZoneId zoneId = ZoneId.of ( "America/Chicago" );
ZonedDateTime zdt = ZonedDateTime.ofInstant ( instant, zoneId );
ZonedDateTime zdtHourLater = zdt.plusHours ( 1 );
Dump to console.
System.out.println ( "input: " + input + " | instant: " + instant + " | zoneId: " + zoneId + " | zdt: " + zdt + " | zdtHourLater: " + zdtHourLater );
input: 1457928024812 | instant: 2016-03-14T04:00:24.812Z | zoneId: America/Chicago | zdt: 2016-03-13T23:00:24.812-05:00[America/Chicago] | zdtHourLater: 2016-03-14T00:00:24.812-05:00[America/Chicago]
So, no such problem in java.time. Adding an hour moves across midnight as expected, from 11 PM on the 13th to just after midnight on the 14th.
Daylight Saving Time (DST)
DST is handled properly.
Crossing the DST change-over
Adding one hour from 1:59 AM jumps two hours on the clock to 3:59 AM, as expected.
ZonedDateTime zdtBeforeTwoAm = ZonedDateTime.of ( 2016, Month.MARCH.getValue ( ), 13, 1, 59, 0, 0, zoneId );
ZonedDateTime zdtBeforeTwoAmPlus = zdtBeforeTwoAm.plusHours ( 1 );
Dump to console.
System.out.println ( "zdtBeforeTwoAm: " + zdtBeforeTwoAm + " | zdtBeforeTwoAmPlus: " + zdtBeforeTwoAmPlus );
zdtBeforeTwoAm: 2016-03-13T01:59-06:00[America/Chicago] | zdtBeforeTwoAmPlus: 2016-03-13T03:59-05:00[America/Chicago]
Asking for 2 AM
Asking for 2 AM is not valid (no such time). So java.time automatically moves to a valid equivalent, 3 AM.
ZonedDateTime zdtTwoAm = ZonedDateTime.of ( 2016, Month.MARCH.getValue ( ), 13, 2, 0, 0, 0, zoneId );
Dump to console.
System.out.println ("zdtTwoAm: " + zdtTwoAm );
zdtTwoAm: 2016-03-13T03:00-05:00[America/Chicago]