Java 8 APIs: java.util.time - Instant, LocalDate, LocalTime, and LocalDateTime


I started to experience the Java 8 new APIs (still Early Access at the moment of writing this post) and the first thing I looked into was the new date and time API (JSR 310). As there is much to cover in this new long awaited API I think it worth few posts with some examples. This post would be the first in a series, starting with some basic classes of the package: Instant, LocalDate, LocalTime, and LocalDateTime.


Instant (java.time.Instant)

Probably the best place to start with the java.time package is the Instant class. An Instant represents a point in time (similar to java.util.Date) with nanoseconds precision (unlike the old Date which has milliseconds precision). Representing a point in time using nanoseconds precision requires more space than a Long can provide, therefore the internal representation is composed of two Long fields, the first holds the number of seconds since (or before) the standard Java epoch and the other the number of nanoseconds of the last seconds (so never larger than 999,999,999). Let's start with obtaining an Instant instance and print its value:

// Get the current time
Instant instant = Instant.now();

// Output format is ISO-8601
System.out.println(instant);

Instant.toString() returns a ISO8601 formatted string (such as: '2013-06-25T16:22:52.966Z'), a much more logical choice than the one used by the old Date class. Here are some other ways to create Instants:

// Convert a java.util.Date into an Instant
Instant instant = Instant.ofEpochMilli(new Date().getTime());

// Create from a String
instant = Instant.parse("1995-10-23T10:12:35Z");

The second example above creates an Instant by parsing a String, this string must by a valid representation of a UTC Instant (NB: Instant is a point of time, it doesn't store any TimeZone information and as such it supports only UTC formatted strings). Instant API provides some useful methods to allow calculations using Instants and other classes in the package, below is a first example:

// Adding 5 hours and 4 minutes to an Instant
instant.plus(Duration.ofHours(5).plusMinutes(4));

How many instances of java.time.Instant are used in the example above? Two. The java.time package is planned to be thread safe and as such most of its classes are immutable, Instant is not an exception to that rule and as such the plus() method creates a new instance.

Instant instant1 = instant.plus(Duration.ofHours(5).plusMinutes(4));
System.out.println("Instant is immutable, so instant==instant returns: " + (instant == instant1));

The output would be: 
Instant is immutable, so instant==instant returns: false

Here are few more examples of Instant calculations:

// Substract 5 days of an instant
instant.minus(5, ChronoUnit.DAYS); // Option 1
instant.minus(Duration.ofDays(5)); // Option 2

// How many minutes are between to Instants?
long diffAsMinutes = instant.periodUntil(instant1, ChronoUnit.MINUTES); // Option 1
long diffAsMinutes = ChronoUnit.MINUTES.between(instant, instant1); // Option 2

Instants are Comparable which means they can be used in any place a Comparable is expected (such as collections). Instant also provides the isAfter() and isBefore() methods which can make a more readable code:

// Compare the two
System.out.format("instant1.compareTo(instant)=%d.%n", instant1.compareTo(instant));

// We can check to see which Instant is before/after the other
System.out.format("instant1.isAfter(instant)=%b, instant1.isBefore(instant)=%b.%n", 
 instant1.isAfter(instant), instant1.isBefore(instant));

The output would be:
instant1.compareTo(instant)=1.
instant1.isAfter(instant)=true, instant1.isBefore(instant)=false.

LocalDate and LocalTime

LocalDate represents a date without a time zone, such as 1-1-2000. LocalTime represents time without a time zone, such as 04:44:59.12 - unlike Instant which is an offset from the Java epoch and as such can be calculated into a precise point of time these two are just date or time without any relation to the epoch - a human readable date and time. There are several ways to obtain LocalTime and LocalDate instances, here are few:


LocalDate localDate = LocalDate.now();
localDate = LocalDate.ofYearDay(2005, 86); // The 86th day of 2005 (27-Mar-2005)
localDate = LocalDate.of(2013, Month.AUGUST, 10); //10th of Aug 2013

LocalTime localTime = LocalTime.of(22, 33); //10:33 PM
localTime = LocalTime.now();
localTime = LocalTime.ofSecondOfDay(4503); // The 4,503 second in a day (1:15:30 AM)

LocalDate and Local time follow the same general concept of multithreading as Instant does - and as such their instances are immutable. LocalDate and LocalTime have calculation and comparison methods similar to the ones Instant has (some of the methods are defined by the java.time.temporal.Temporal interface which implemented by all of these classes):


LocalDate localDate1 = localDate.plus(5, ChronoUnit.HOURS);
localDate.isBefore(localDate1);

LocalDateTime

The last important player in the simple date and time classes is LocalDateTime - this is a combination of LocalDate and LocalTime representing a date and the time within that date, again no time zone. LocalDateTime seems to be very similar to Instant, a reminder: "an Instant is point in time without time zone” and one could say that a point in time is nothing more than a date and time within that date. But there is a difference: LocalDateTime is not a point on the time line as Instant is, LocalDateTime is just a date and time as a person would write on a note. Consider the following example: two persons which were born at 11am, July the 2nd 2013. The first was born in the UK while the second in California. If we ask any of them for their birth date it will look that they were born on the same time (this is the LocalDateTime) but if we align the dates on the timeline (using Instant) we will find out that the one born in California is few hours younger than the one born in the UK (NB: to create the appropriate Instant we have to convert the time to UTC, this is where the difference lays). Beside of that LocalDateTime behaves very similar to the other classes illustrated above:


LocalDateTime localDateTime = LocalDateTime.now();

// Jump to 25 hours and 3 minutes into the future
LocalDateTime inTheFuture = localDateTime.plusHours(25).plusMinutes(3);

// We could do the same on localTime or localDate
System.out.println(localDateTime.toLocalTime().plusHours(25).plusMinutes(3));
System.out.println(localDateTime.toLocalDate().plusMonths(2));

// We could also use TemportalAmount (in this case a Duration and Period)
System.out.println(localDateTime.toLocalTime().plus(Duration.ofHours(25).plusMinutes(3)));
System.out.println(localDateTime.toLocalDate().plus(Period.ofMonths(2)));

Comments

hernan said…
Good explanation. The only thing a miss is a mention to Jodatime, on which this is based.
Eyal Lupu said…
Thanks for the feedback.

Indeed joda-time is an important part of the revised Java date and time API however JSR310 is not based on joda-time, it is more ‘inspired by it’. Stephen Colebourne (the creator of joda-time and a leader for JSR310) explains the flaws in joda-time and why JSR310 isn’t an ‘immediate decedent’ of it (see: this post in his blog)
grails hql said…
good and clear explanation
Excellent! Thanks for this - I've been looking at this feature for ages. Followed your instructions and it works a treat!
Unknown said…
This comment has been removed by a blog administrator.

Popular posts from this blog

New in Spring MVC 3.1: CSRF Protection using RequestDataValueProcessor

Hibernate Exception - Simultaneously Fetch Multiple Bags

Hibernate Derived Properties - Performance and Portability