How to convert a time to another time zone
Short answer
Attach the time to a zone with atZone(), then withZoneSameInstant() shows the same moment in another zone:
void main() {
var berlin = LocalDateTime.of(2026, 3, 8, 15, 0).atZone(ZoneId.of("Europe/Berlin"));
var tokyo = berlin.withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
IO.println(berlin);
IO.println(tokyo);
}Output:
2026-03-08T15:00+01:00[Europe/Berlin]
2026-03-08T23:00+09:00[Asia/Tokyo]From UTC
Server time is often stored as an Instant in UTC. Show it to the user in their zone:
void main() {
Instant stored = Instant.parse("2026-07-01T12:00:00Z");
var local = stored.atZone(ZoneId.of("America/New_York"));
IO.println(local.toLocalDateTime());
}Output:
2026-07-01T08:00Daylight saving time
ZoneId knows about daylight saving changes. The same time of day on different dates gives a different offset:
void main() {
var zone = ZoneId.of("Europe/London");
IO.println(LocalDateTime.of(2026, 1, 15, 12, 0).atZone(zone).getOffset());
IO.println(LocalDateTime.of(2026, 7, 15, 12, 0).atZone(zone).getOffset());
}Output:
Z
+01:00Z means a zero offset from UTC: in winter London is on UTC, and in summer it is an hour ahead.
Common mistake
Using withZoneSameLocal() instead of withZoneSameInstant(). It keeps the clock time and only changes the zone — that is a different moment:
void main() {
var berlin = LocalDateTime.of(2026, 3, 8, 15, 0).atZone(ZoneId.of("Europe/Berlin"));
IO.println(berlin.withZoneSameLocal(ZoneId.of("Asia/Tokyo")));
IO.println(berlin.withZoneSameInstant(ZoneId.of("Asia/Tokyo")));
}Output:
2026-03-08T15:00+09:00[Asia/Tokyo]
2026-03-08T23:00+09:00[Asia/Tokyo]Functions used in this recipe
- ZonedDateTime — A date and time in a specific time zone — with daylight saving time taken into account.
- Instant — An exact moment on the UTC timeline — for logs, timestamps and measurements.