Time zones, perhaps because they are an entirely human creation, are even messier than the complications caused by the earth’s irregular rotation. In a rational world, we’d all follow the clock in Greenwich, and some of us would eat our lunch at 02:00, others at 22:00. Our stomachs would figure it out. This is actually done in China, which spans four conventional time zones. Elsewhere, we have time zones with irregular and shifting boundaries and, to make matters worse, the daylight savings time.
As capricious as the time zones may appear to the enlightened, they are a fact of life. When you implement a calendar application, it needs to work for people who fly from one country to another. When you have a conference call at 10:00 in New York, but happen to be in Berlin, you expect to be alerted at the correct local time.
The Internet Assigned Numbers Authority (IANA) keeps a database of all known time zones around the world (www.iana.org/time-zones), which is updated several times per year. The bulk of the updates deals with the changing rules for daylight savings time. Java uses the IANA database.
Each time zone has an ID, such as America/New_York or Europe/Bertin. To find out all available time zones, call Zoneld.getAvaitabteZonelds. At the time of this writing, there are almost 600 IDs.
Given a time zone ID, the static method Zoneld.of(id) yields a Zoneld object. You can use that object to turn a LocatDateTime object into a ZonedDateTime object by calling tocat.atZone(zoneld), or you can construct a ZonedDateTime by calling the static method ZonedDateTime.of(year, month, day, hour, minute, second, nano, zoneld). For example,
ZonedDateTime apottolltaunch = ZonedDateTime.of(1969, 7, 16, 9, 32, 0, 0,
ZoneId.of(“America/New_York”));
// 1969-07-16T09:32-04:00[America/New_York]
This is a specific instant in time. Call apotto11taunch.toInstant to get the Instant. Conversely, if you have an instant in time, call instant.atZone(ZoneId.of(“UTC”)) to get the ZonedDateTime at the Greenwich Royal Observatory, or use another ZoneId to get it elsewhere on the planet.
Many of the methods of ZonedDateTime are the same as those of LocalDateTime (see the API notes at the end of this section). Most are straightforward, but daylight savings time introduces some complications.
When daylight savings time starts, clocks advance by an hour. What happens when you construct a time that falls into the skipped hour? For example, in 2013, Central Europe switched to daylight savings time on March 31 at 2:00. If you try to construct nonexistent time March 31 2:30, you actually get 3:30.
ZonedDateTime skipped = ZonedDateTime.of(
LocatDate.of(2013, 3, 31),
LocatTime.of(2, 30),
ZoneId.of(“Europe/Berlin”));
// Constructs March 31 3:30
Conversely, when daylight time ends, clocks are set back by an hour, and there are two instants with the same local time! When you construct a time within that span, you get the earlier of the two.
ZonedDateTime ambiguous = ZonedDateTime.of(
LocatDate.of(2013, 10, 27), // End of daylight savings time
Loca!Time.of(2, 30),
ZoneId.of(“Europe/Berlin”));
// 2013-10-27T02:30+02:00[Europe/Berlin]
ZonedDateTime anHourLater = ambiguous.plusHours(1);
// 2013-10-27T02:30+01:00[Europe/Berlin]
An hour later, the time has the same hours and minutes, but the zone offset has changed.
You also need to pay attention when adjusting a date across daylight savings time boundaries. For example, if you set a meeting for next week, don’t add a duration of seven days:
ZonedDateTime nextMeeting = meeting.plus(Duration.ofDays(7));
// Caution! Won’t work with daylight savings time
Instead, use the Period class.
ZonedDateTime nextMeeting = meeting.plus(Period.ofDays(7)); // OK
The example program in Listing 6.3 demonstrates the ZonedDateTime class.
Source: Horstmann Cay S. (2019), Core Java. Volume II – Advanced Features, Pearson; 11th edition.