java 35 lines · 6 steps

Converting timestamps across time zones in Java

A utility class that treats epoch millis as an absolute instant and projects it into any zone without shifting the underlying moment.

Explained by highlit
1import java.time.Instant;
2import java.time.ZoneId;
3import java.time.ZonedDateTime;
4import java.time.format.DateTimeFormatter;
5 
6public final class TimeZoneConverter {
7 
8 private static final DateTimeFormatter ISO = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
9 
10 public static ZonedDateTime fromEpochMillis(long epochMillis, ZoneId zone) {
11 return Instant.ofEpochMilli(epochMillis).atZone(zone);
12 }
13 
14 public static long toEpochMillis(ZonedDateTime dateTime) {
15 return dateTime.toInstant().toEpochMilli();
16 }
17 
18 public static ZonedDateTime convertZone(ZonedDateTime source, ZoneId target) {
19 return source.withZoneSameInstant(target);
20 }
21 
22 public static String describe(long epochMillis, ZoneId zone) {
23 ZonedDateTime local = fromEpochMillis(epochMillis, zone);
24 return String.format("%s (%s) offset=%s",
25 local.format(ISO),
26 zone.getId(),
27 local.getOffset());
28 }
29 
30 public static long shiftAcrossZones(long epochMillis, ZoneId from, ZoneId to) {
31 ZonedDateTime original = fromEpochMillis(epochMillis, from);
32 ZonedDateTime shifted = convertZone(original, to);
33 return toEpochMillis(shifted);
34 }
35}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1An epoch instant is absolute; a ZoneId only changes how that same moment is displayed.
  2. 2java.time types are immutable, so conversions return new objects rather than mutating in place.
  3. 3withZoneSameInstant reframes a time without altering the point on the timeline it represents.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Converting timestamps across time zones in Java — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code