Skip to content

Java date-time types

Published: at 03:24 PM

Every now and then I struggle a little bit with all the date-time types we have in the java.time package:

But digging a bit through the source code of these classes, the fog slowly disappears.

An Instant is actually a point in time without any extra information. Internally it is stored as the number of milliseconds and nanoseconds since the beginning of the epoch:

/**
 * The number of seconds from the epoch of 1970-01-01T00:00:00Z.
 */
private final long seconds;
/**
 * The number of nanoseconds, later along the time-line, from the seconds field.
 * This is always positive, and never exceeds 999,999,999.
 */
private final int nanos;

As we just have a point in time and we do not know where on the world this point in time was, we do not know the date and time. This is where LocalDateTime comes into play.

In contrast to Instant it stores the time and date:

/**
 * The date part.
 */
private final LocalDate date;
/**
 * The time part.
 */
private final LocalTime time;

But as LocalDateTime does not store any timezone, we again don’t know where on the world we are, as a date and time like 2025-05-24T15:10 happens in every timezone after each other.

Therefore, to convert a LocalDateTime into an Instant, we need to pass the timezone:

LocalDateTime dateTime = LocalDateTime.of(2025, 5, 24, 15, 10);
Instant instant = dateTime.atZone(ZoneId.of("Europe/Berlin")).toInstant();

The type on wich the method toInstant() is called, is a ZonedDateTime:

LocalDateTime dateTime = LocalDateTime.of(2025, 5, 24, 15, 10);
ZonedDateTime zonedDateTime = dateTime.atZone(ZoneId.of("Europe/Berlin"));

Hence, ZonedDateTime stores internally the LocalDateTime together with information about the timezone:

/**
 * The local date-time.
 */
private final LocalDateTime dateTime;
/**
 * The offset from UTC/Greenwich.
 */
private final ZoneOffset offset;
/**
 * The time-zone.
 */
private final ZoneId zone;

OffsetDateTime is actually only a layer above ZoneDateTime, as it does only handle the offset information, but not which timezone it actually is:

/**
 * The local date-time.
 */
private final LocalDateTime dateTime;
/**
 * The offset from UTC/Greenwich.
 */
private final ZoneOffset offset;

Finally, the type OffsetTime is just a combination of LocalTime and ZoneOffset:

/**
 * The local date-time.
 */
private final LocalTime time;
/**
 * The offset from UTC/Greenwich.
 */
private final ZoneOffset offset;