Font Awesome Free 5.13.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)

Date and Time API (Java)

An overview of the Java Date and Time API

Date and Time API basics

Java 1.0 had Date, most methods deprecated with introduction of Calendar in Java 1.1. Still not perfect (sometimes awkward API, didn't deal with leap seconds, ...) -> the recommendation used to be to use a library like Joda Time instead.

Java 8 introduced a new Data and Time API under java.time, which solves a lot of the issues with the older solutions.

Some key points:

  • All instances of java.time objects are immutable (operations that change dates or times return new objects)
  • A day has exactly 86400 seconds (leap seconds are dealt with by making seconds last a little bit longer)

Instants and Durations

Instant: represents a point on the time line

Duration: represents the amount of time between two instants

Instant start = Instant.now();
// perform some computations
Instant end = Instant.now();
Duration timeElapsed = Duration.between(start, end);
long millis = timeElapsed.toMillis();
Duration oneWeek = Duration.ofDays(7);
long secondsInWeek = oneWeek.toSeconds();

Computations with durations:

  • Option 1: use methods directly on durations
  • Option 2: convert to nanoseconds
    • Note that a long of nanoseconds doesn't allow you to use the entire range of a Duration, but it a long can hold almost 300 years worth of nanoseconds
// Option 1
if (duration1.multipliedBy(10).minus(duration2).isNegative()) {
// ...
}
// Option 2
if (duration1.toNanos() * 10 < duration2.toNanos()) {
// ...
}

Local dates and time

Local date/time: has a date and/or time of day, but no time zone information

Example use cases:

  • Someone's birthday (this refers to a certain calendar date, but not to a precise instant on the time line)
  • Calculations with date and time when you want to ignore time zones and don't want daylight savings time to be taken into account
    • Example: a meeting that is at 10:00 every 7 days (regardless of daylight savings time)
    • Note: you can also ignore daylight savings time when working with zoned times, see below

Local dates

LocalDate today = LocalDate.now();
LocalDate test1 = LocalDate.of(2019, 8, 28);
LocalDate test2 = LocalDate.of(2019, Month.AUGUST, 28);
System.out.println(test1.equals(test2)); // true
LocalDate programmersDay = LocalDate.of(2019, 1, 1).plusDays(255);
// Duration.ofYears(1) wouldn't produce the correct result in a leap year
LocalDate birthdayNextYear = birthday.plus(Period.ofYears(1));
today.until(christmas, ChronoUnit.DAYS) // get # days until Christmas

Note: methods adjusting dates don't throw exceptions if the result would be invalid but adjust it to a valid date instead!

LocalDate test = LocalDate.of(2016, 1, 31).plusMonths(1);
System.out.println(test); // 2016-02-29

Temporal adjusters

Example: compute first Tuesday of a month

LocalDate firstTuesday = LocalDate.of(year, month, 1).with(
TemporalAdjusters.nextOrSame(DayOfWeek.TUESDAY))

Local time

LocalTime currentTime = LocalTime.now();
LocalTime bedTime = LocalTime.of(00, 30);
LocalTime alarmTime = bedTime.plusHours(8);

Zoned time

Zoned time: date and time plus time zone information

  • Represents particular instant in time
  • When performing calculations or transforming between time zones, daylight savings time and time zone rules are taken into account
ZonedDateTime apolloLaunch = ZonedDateTime.of(1969, 7, 16, 9, 32, 0, 0,
ZoneId.of("America/New_York"));
System.out.println(apolloLaunch); // 1969-07-16T09:32-04:00[America/New_York]
Instant now = Instant.now();
ZonedDateTime nowInUtc = now.atZone(ZoneId.of("UTC"));
// Duration.ofDays(7) wouldn't work with daylight savings time
ZonedDateTime nextMeeting = currentMeeting.plus(Period.ofDays(7))

Note: there is also OffsetDateTime, which uses a fixed offset from UTC. This is useful for some technical applications like network protocols. For dealing with human time, ZonedDateTime is typically the best option.

Formatting and parsing dates

The DateTimeFormatter class now replaces the old DateTimeFormat (you can still call toFormat() on a DateTimeFormatter to get a legacy DateTimeFormat)

// predefined ISO_OFFSET_DATE_TIME format (ISO-8601-compliant)
String formatted = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now());
System.out.println(formatted); // 2019-08-28T16:02:07.5384469+02:00
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
String formatted = formatter.format(ZonedDateTime.now());
System.out.println(formatted); // August 28, 2019 at 4:05:04 PM CEST
LocalDate parsed1 = LocalDate.parse("2019-08-28");
DateTimeFormatter patternFormatter = DateTimeFormatter.ofPattern("yyyy/dd/MM");
LocalDate parsed2 = LocalDate.parse("2019/28/08", patternFormatter);
System.out.println(parsed1.equals(parsed2)); // true
// throws DateTimeParseException
LocalDate parsed3 = LocalDate.parse("2019/08/28", patternFormatter);

Resources

  • Core Java SE 9 for the Impatient (book by Cay S. Horstmann)