Dates and times in Java have evolved significantly over the years. Here’s how the main types stack up, why the newer
java.timeAPI was needed, and when to use each.
java.util.Date & java.sql.Timestamp
-
Representation: Internally holds a
longof milliseconds since the Unix epoch (January 1, 1970 UTC). -
Usage:
Date now = new Date(); long ms = now.getTime(); -
Drawbacks:
- Mutable and not thread-safe
- Many of its methods are deprecated (e.g.
getYear()) - Lacks clear separation between date-only, time-only, and timezone data
-
TimestampextendsDateto add nanosecond precision for JDBC; primarily used when reading/writing SQLTIMESTAMPcolumns.
The Modern java.time API (Java 8+)
Designed by the team behind Joda-Time, this API fixes the pain points of the old classes. All types are immutable, thread-safe, and clearly modeled.
LocalDate
-
What it holds: A date without time or timezone (year-month-day).
-
When to use: Birthdays, anniversaries, or any date that doesn’t need a time component.
LocalDate today = LocalDate.now(); LocalDate birthday = LocalDate.of(1990, Month.JULY, 19);
LocalTime
-
What it holds: A time-of-day without date or timezone (hour-minute-second).
-
When to use: Business hours, daily schedules, or any time-only value.
LocalTime meeting = LocalTime.of(14, 30);
LocalDateTime
-
What it holds: Combines
LocalDateandLocalTime—still no timezone. -
When to use: Logging events on the local machine, user input without zone context.
LocalDateTime appointment = LocalDateTime.of(2025, 5, 20, 9, 0);
ZonedDateTime & OffsetDateTime
-
ZonedDateTime: A date-time with a full timezone (e.g. Europe/Paris). -
OffsetDateTime: A date-time with a fixed offset from UTC (e.g. +05:30). -
When to use: Scheduling across time zones, storing instants in a human-readable form.
ZonedDateTime parisMeeting = ZonedDateTime.of(2025,5,20,14,0,0,0, ZoneId.of("Europe/Paris"));
Instant
-
What it holds: A point on the global timeline (UTC), measured in seconds and nanoseconds from the epoch.
-
When to use: Timestamps for logging, measuring elapsed time, or interoperation with legacy
Date/Timestamp.Instant now = Instant.now(); Date legacy = Date.from(now);
Duration & Period
-
Duration: Amount of time in seconds/nanoseconds (time-based). -
Period: Amount of time in years/months/days (date-based). -
When to use:
Durationfor measuring spans like “5 hours, 30 minutes.”Periodfor calendar-based spans like “3 years, 2 months.”
Duration flight = Duration.ofHours(8).plusMinutes(15); Period age = Period.between(birthday, today);
Why the New API?
- Clarity – Clear separation of date-only vs. time-only vs. combined vs. zoned types.
- Immutability – Thread-safe by design, no surprises from shared mutable state.
- Fluent API – Methods like
plusDays(),withMonth(), ortruncatedTo()make transformations easy to read. - Interoperability – Built-in converters to/from legacy types (
Date,Calendar,Timestamp). - Powerful Parsing/Formatting –
DateTimeFormatterwith ISO standards and custom patterns.
By choosing the right type—LocalDate for dates, LocalTime for times, ZonedDateTime for zone-aware moments, and Duration/Period for spans—you’ll write code that’s clearer, safer, and less error-prone.