In Java 8 Date and Time went another remodeling resulting in much better API and concepts better reflecting developer’s needs. Here we’ll go through Java 8 new Date and Time concepts.
Java history around Date/Time mess
Problems with time
Developers who write business systems often need to calculate date/time of something (e.g. a flight starts at 10:00 PM in one city and flies for 6 hours, when will it arrive? Do they have DST at that day? etc.). The rules for Earth calendars are just crazy and it’s basically impossible to handle them inside our systems. Here are some of the problems:
- Australia has horizontal and vertical timezones during summer
- Timezone Donut in Arizona
Arizona – no DST, Navajo Reservation – DST, Hopi Reservation inside Navajo Reservation – no DST :-)
Daylight Saving Time (with local modifications)
- DST yes, but not during Ramadan
- DST doesn’t start/end in full hour (e.g. India +05:30, Nepal +05:45)
- DST moves by 1 hour, except Lord Howe Island (Australia), where it moves by 0:30
- Greenwich (the place) is GMT+01:00 during summer :-)
- Brazil sets its summer time by decree every year (probably during the Rio Carnival ;-) )
Leap years and seconds
Yes, there are leap seconds too, and not each and every day has the same number of seconds. All it means is that the time 23:59:60 is perfectly valid time.
Date/Time before Java 8
Before Java 8 there were not many possibilities to express time-related concepts and doing date calculations was tedious.
It was introduced in 1.0 and in Java 1.1 almost all its methods were deprecated. The Date class is simple and sometimes enough when accuracy is not important and you don’t want to do any calculations on it, but there are some issues with it:
- It is mutable (need to create defensive copies)
- Knows nothing about Time Zones, Daylight Saving Time, leap years/seconds, etc.
It was another attempt to add Date and Time support in Java. The class in tedious to instantiate and work with, but at least it allows to do some date/time calculations. Calendar is also mutable, doesn’t include leap seconds (for me hardly a problem) and has awkward API:
Calendar cal = Calendar.getInstance(); // now cal.set(2017, 1, 18); // February 18th Date date = cal.getTime(); // get Date
This library became de facto standard library for time and date calculations in Java. Java 8 Date Time API is based on joda-time, but arguably more convenient.
Conceptual changes in Java 8
The Date Time API has been designed from scratch and greatly extended. There are classes that represent different date and time concepts and better fit what we do with time – set schedules, calculate periods, calculating end day of something, etc.
Important thing is that whole API follows common themes:
- objects are immutable, thread-safe and cacheable
- enums for months and many other items
- day calculation strategies
- each day always has 86400 seconds (no leap seconds).
Java 8 Date and Time representations
In this section we present the most important Java 8 classes for date and time concepts.
Instant – a point in time
Think of it as a point in space (cosmic time) – no timeones, no DSTs, no… nothing. It’s just a point on a timeline.
Some of its notable properties:
- It is a point on a time line with nanosecond precision
- Holds time in UTC timezone
- Immutable and thread-safe
- useful for representing timestamps
Example values of java.time.Instant:
System.out.println(Instant.MIN); System.out.println(Instant.EPOCH); System.out.println(Instant.ofEpochMilli(1)); System.out.println(Instant.now()); System.out.println(Instant.now(Clock.systemUTC())); System.out.println(Instant.parse("2017-07-01T14:40:08.000Z")); System.out.println(Instant.MAX);
-1000000000-01-01T00:00:00Z 1970-01-01T00:00:00Z 1970-01-01T00:00:00.001Z 2017-10-02T17:26:43.742Z 2017-10-02T17:26:43.742Z 2017-07-01T14:40:08Z +1000000000-12-31T23:59:59.999999999Z
LocalTime – time of day
Represents a time of day and comes with a bunch of methods to manipulate time. It’s like a meeting time – e.g. our Daily Scrum meeting starts everyday at 10:00 AM.
import java.time.LocalTime; LocalTime now = LocalTime.now(); LocalTime workshopStarts = LocalTime.of(9, 30); // 9:30 AM LocalTime night = LocalTime.of(23, 30).plusHours(2); // 1:30 AM
LocalDate – a date without time (day precision)
Represents date objects without time – e.g. event from the past.
import java.time.LocalDate; LocalDate today = LocalDate.now(); LocalDate theBattle = LocalDate.of(1410, Month.July, 15);
An example of how February 29th is handled:
// all are equal: LocalDate.of(2016, 1, 31).plusMonths(1); LocalDate.of(2016, 3, 31).minusMonths(1); LocalDate.of(2016, 2, 29);
LocalDateTime – both in one object
Represents a date with time. For example scheduled appointment or flight departure date:
import java.time.LocalDateTime; import java.time.Month; LocalDateTime departureDate = LocalDateTime .of(2017, Month.OCTOBER, 2, 15, 50); System.out.println("Departure: " + departureDate); // Departure: 2017-10-02T15:50
MonthDay, YearMonth, Year
Of course there are classes for individual parts of a date.
MonthDay – day of month accuracy
import java.time.MonthDay; MonthDay christmas = MonthDay.of(Month.DECEMBER, 25); System.out.println("Christmas: " + christmas); // Christmas: --12-25
YearMonth – month of year accuracy
import java.time.YearMonth; YearMonth endOfSummer = YearMonth.of(2017, Month.SEPTEMBER); System.out.println(endOfSummer); // 2017-09
Year – year accuracy
import java.time.Year; Year past = Year.of(1980); System.out.printf("Was %s a leap year? %b%n", past, past.isLeap()); // Was 1980 a leap year? true
ZonedTime, ZonedDateTime – date/time within time zone
These two classes are like LocalDate(Time), but with time zone information – date and time are expressed for selected time zone. In Java 8 there is ZoneId class for time zone objects (see How to get available time zones).
import java.time.ZoneDateTime; import java.time.ZoneId; Set<String> names = ZoneId.getAvailableZones(); // names: "CEST, America/Chicago, ..." ZoneId ourZone = ZoneId.of("Europe/Warsaw"); ZoneDateTime.of(y, m, d, h, m, s, ourZone);
Length of time
Duration – machine time distance
It’s the duration between two Instant objects and doesn’t keep date information (day, month, year). It’s just a distance between two timestamps.
import java.time.Duration; import java.time.Instant; Instant beginning = Instant.EPOCH; Instant end = Instant.now(); Duration length = Duration.between(beginning, end); System.out.println("Millis since the Epoch: " + length.toMillis());
Period – amount of time between dates
The java.time.Period class represents an amount of time between two LocalDates. The class differs from Duration in keeping the distance with date (year, month, day) granularity and how it works with time zones. When Period is added to the ZonedDateTime it will handle DST if encountered, whereas Duration will just add defined amount of time (violating DST rules).
import java.time.LocalDate; import java.time.Month; import java.time.Period; LocalDate pastDate = LocalDate.of(2015, Month.MAY, 19); Period period = Period.between(pastDate, LocalDate.now()); System.out.printf("It was %d years ago.%n", period.getYears()); // It was 2 years ago.
Warning: period.getDays/Months/Years() return corresponding parts of period. If you want to calculate total number of days between two dates use ChronoUnit.DAYS.between(past, today).
It’s just the beginning
There are more classes in java.time package, but these are enough to get started. In other tutorials we’ll show how to convert dates, format them, perform calculations using TemporalAdjusters and more. Stay tuned! :-)