Unravel โบ Java concepts โบ Time and dates
Time zones, DST and Instant
An Instant is one exact moment on the global timeline.
Learn these first
At a glance
An Instant is the moment a rocket launches, the same for everybody.
- 1Store and exchange moments as Instant (or UTC, or epoch milliseconds)Convert to a zone only for display: instant.atZone(ZoneId.of("Europe/Paris")).
- 2zdt.withZoneSameInstant(ZoneId.of("Asia/Tokyo")) shows the same moment in Tokyo; withZoneSameLocal keeps the clock reading but changes the moment
- 3Use region ids (America/New_York), not fixed offsets (-05:00), because offsets do not know about daylight saving timeZoneId.systemDefault() depends on the server.
- 4On DST change days "add one day" and "add 24 hours" differ: zdt.plusDays(1) keeps the wall clock, plus(Duration.ofHours(24)) keeps elapsed time
- Local times can be ambiguous (the hour repeated when clocks go back) or non-existent (skipped when clocks go forward)
- A recurring "every day at 09:00" job must be stored as a local time plus a zone, not as UTC, or it drifts by an hour twice a year
- Zone rules come from the IANA tz database bundled with the JDK (tzdb.dat), so an old JDK may not know a recent government change; update the JDK or the tzdata
import java.time.*;public class Meetings { static ZonedDateTime inTokyo(Instant when) { return when.atZone(ZoneId.of("Asia/Tokyo")); } static Instant parisNineAm(LocalDate day) { return day.atTime(9, 0).atZone(ZoneId.of("Europe/Paris")).toInstant(); } static ZonedDateTime convert(ZonedDateTime t) { return t.withZoneSameInstant(ZoneId.of("America/New_York")); } static long nowMillis() { return Instant.now().toEpochMilli(); }}- line 3 uses atZone, the core of Time zones, DST and Instant
- line 4 uses atZone, the core of Time zones, DST and Instant
- line 5 uses withZoneSameInstant, the core of Time zones, DST and Instant
- line 6 uses now, the core of Time zones, DST and Instant
Read the full explanation (about 2 min)
An Instant is one exact moment on the global timeline. A LocalDateTime is only a wall-clock reading with no zone. A ZonedDateTime ties a wall-clock reading to a zone, which is what daylight saving time needs.
A mental model
An Instant is the moment a rocket launches, the same for everybody. A LocalDateTime is "8 pm" on a note with no city, meaningless until you say where. A ZonedDateTime says "8 pm in Paris".
How it works
Store and exchange moments as Instant (or UTC, or epoch milliseconds). Convert to a zone only for display: instant.atZone(ZoneId.of("Europe/Paris")).
zdt.withZoneSameInstant(ZoneId.of("Asia/Tokyo")) shows the same moment in Tokyo; withZoneSameLocal keeps the clock reading but changes the moment.
Use region ids (America/New_York), not fixed offsets (-05:00), because offsets do not know about daylight saving time. ZoneId.systemDefault() depends on the server.
On DST change days "add one day" and "add 24 hours" differ: zdt.plusDays(1) keeps the wall clock, plus(Duration.ofHours(24)) keeps elapsed time.
Going deeper
Local times can be ambiguous (the hour repeated when clocks go back) or non-existent (skipped when clocks go forward). ZonedDateTime resolves by default to the earlier offset and shifts forward; use withEarlierOffsetAtOverlap when the choice matters.
A recurring "every day at 09:00" job must be stored as a local time plus a zone, not as UTC, or it drifts by an hour twice a year. The scheduler tools on this site explain how cron treats these cases.
Pass a Clock into code that needs "now" so tests can use Clock.fixed(...); set the server and the JVM to UTC.
Under the hood
Zone rules come from the IANA tz database bundled with the JDK (tzdb.dat), so an old JDK may not know a recent government change; update the JDK or the tzdata. An Instant is a count of seconds and nanoseconds since 1970-01-01T00:00:00Z.
Common mistakes
- Using
LocalDateTimefor events that happened at a specific moment. - Storing local times without the zone.
- Relying on the default time zone of the server.
- Using fixed offsets for users in DST regions.
How Unravel recognises it
When you paste code, Unravel looks for these signs of time zones, dst and instant. Spotting them yourself is a good habit when you read unfamiliar code:
- Types:
ZoneOffsetZoneRules - Method calls:
withZoneSameInstant()withZoneSameLocal()atZone()ZoneId.of()ZoneId.systemDefault()toInstant()Instant.now()ofEpochSecond()ofEpochMilli()toEpochMilli()ZonedDateTime.now()getOffset()atOffset()
Part of a learning path
- I/O, networking and time ยท previous: Formatting, parsing and date arithmetic ยท next: Legacy Date, Calendar and SimpleDateFormat
Related concepts
Frequently asked questions
What is Time zones, DST and Instant?
An Instant is one exact moment on the global timeline. A LocalDateTime is only a wall-clock reading with no zone. A ZonedDateTime ties a wall-clock reading to a zone, which is what daylight saving time needs.
What are the most common mistakes with Time zones, DST and Instant?
Using LocalDateTime for events that happened at a specific moment. Storing local times without the zone. Relying on the default time zone of the server. Using fixed offsets for users in DST regions.
How can I see Time zones, DST and Instant in real code?
Paste your own Java into Unravel and it will point out where time zones, dst and instant appears, explain how it works at the detail level you choose, and draw the flow of the code around it.