Java has introduced a new date and time API in Java 8. The interface is much more intuitive than the old java.util.Date and java.util.Calendar based APIs. The new library was developed and integrated via JSR-310 and is heavily inspired from the popular Joda-Time library. It has a comprehensive set of classes for various use cases (as you’ll see later on in the article). Another important benefit of the new library is that the objects created are immutable and therefore cause less problems in multithreaded programming.

The new APIs are designed to be fluent, e.g.:

LocalTime time = LocalTime.now().plusHours(4).minusMinutes(20).withNano(0) 1 LocalTime time = LocalTime . now ( ) . plusHours ( 4 ) . minusMinutes ( 20 ) . withNano ( 0 )

The main classes in the new library are

LocalDate

A LocalDate stores the year-month-day information with no time and no time zone. For example, you will use this class to represent a date like Jun 15, 2014. The use case for this class is to represent birthday, start/end day of a project, holiday etc.

To get a LocalDate object for today, use

LocalDate current = LocalDate.now(); 1 LocalDate current = LocalDate . now ( ) ;

To create a LocalDate object for a particular date

LocalDate birthday = LocalDate.of(2014, Month.JULY, 20); 1 LocalDate birthday = LocalDate . of ( 2014 , Month . JULY , 20 ) ;

LocalDates are very easy to compare

if (current.isAfter( someDate )) { ... } 1 if ( current . isAfter ( someDate ) ) { . . . }

To convert a LocalDate to a string representation (ISO-8601)

birthday.toString() 1 birthday . toString ( )

There are many utility methods in this class to make life easier for the programmer

boolean isLeap = current.isLeapYear(); int numDaysInMonth = current.lengthOfMonth(); 1 2 boolean isLeap = current . isLeapYear ( ) ; int numDaysInMonth = current . lengthOfMonth ( ) ;

Date Manipulation

It’s very easy to manipulate dates to get new dates. There are lots of methods to add/subtract/set day/month/year for a given date. Since the objects in the new library are immutable, all these methods return a new LocalDate object. The methods can be easily chained together without sacrificing code readability.

To push a date ahead by a month and fifteen days

date = date.plusMonths(1).plusDays(15); 1 date = date . plusMonths ( 1 ) . plusDays ( 15 ) ;

To get a date with first day of current month

date = current.withDayOfMonth(1); 1 date = current . withDayOfMonth ( 1 ) ;

To get a date with month changed to October

date = date.with(Month.OCTOBER); 1 date = date . with ( Month . OCTOBER ) ;

Adjusters for more complex manipulations

The new library has support for complex manipulations like

Get the date on the last day of this month

import static java.time.temporal.TemporalAdjusters.*; ... date = date.with(lastDayOfMonth()); 1 2 3 import static java . time . temporal . TemporalAdjusters . * ; . . . date = date . with ( lastDayOfMonth ( ) ) ;

Get the date on next Sunday

import static java.time.DayOfWeek.*; ... date = date.with(next(SUNDAY)); 1 2 3 import static java . time . DayOfWeek . * ; . . . date = date . with ( next ( SUNDAY ) ) ;

LocalTime

LocalTime is similar to LocalDate but stores time information. It stores time (hours, minutes, seconds, and nanoseconds) with no date or time zone. E.g. “20:00” or “8:00 PM”. This class is useful for representing alarms, office opening hours, etc.

The methods for this class are on the same pattern as that for LocalDate

LocalTime current = LocalTime.now(); LocalTime time = LocalTime.of(20, 00); if (current.isAfter( time )) { ... } String timeStr = time.toString(); // 20:00 (ISO-8601 representation) 1 2 3 4 LocalTime current = LocalTime . now ( ) ; LocalTime time = LocalTime . of ( 20 , 00 ) ; if ( current . isAfter ( time ) ) { . . . } String timeStr = time . toString ( ) ; // 20:00 (ISO-8601 representation)

Just like LocalDate, LocalTime also has lots of utility methods to manipulate time values.

time = time.plusHours(3).minusMinutes(30); 1 time = time . plusHours ( 3 ) . minusMinutes ( 30 ) ;

LocalDateTime

LocalDateTime combines LocalDate and LocalTime and stores year-month-day-hours-minutes-seconds-nanoseconds. E.g. 15 Jun 2014 at 20:00. This class can be useful for representing restaurant reservations, music concert timings etc. The API is very similar to the previous 2 classes.

LocalDateTime dt1 = LocalDateTime.now(); LocalDateTime dt2 = LocalDateTime.of(2014, JULY, 20, 23, 40); dt1 = dt1.plusMonths(6).minusHours(12); dt2 = dt2.with(next(SUNDAY)); String dtStr = dt2.toString(); // ISO-8601 representation 1 2 3 4 5 LocalDateTime dt1 = LocalDateTime . now ( ) ; LocalDateTime dt2 = LocalDateTime . of ( 2014 , JULY , 20 , 23 , 40 ) ; dt1 = dt1 . plusMonths ( 6 ) . minusHours ( 12 ) ; dt2 = dt2 . with ( next ( SUNDAY ) ) ; String dtStr = dt2 . toString ( ) ; // ISO-8601 representation

ZonedDateTime

ZonedDateTime is the main date/time class that has time zone support. The other classes that are used by the library to represent time zone related information are

ZoneId – e.g. “Europe/London”

ZoneOffset – “+05:30”, i.e. offset from UTC

ZoneRules – behind the scenes class that represents the rules that govern a particular time zone. Not used directly by your code

A ZonedDateTime object stores LocalDateTime, ZoneId and ZoneOffset. e.g. 15th June 2014 at 20:00, 05:30 hours ahead of UTC. This class is the closest equivalent of java.util.GregorianCalendar class.

As with other library classes, the API is quite intuitive

ZonedDateTime dt = ZonedDateTime.of(1983, JULY.getValue(), 20, 15, 27, 40, 0, ZoneId.of("Europe/London")); dt = dt.plusYears(30).minusHours(4) dt = dt.with(next(SUNDAY)) 1 2 3 ZonedDateTime dt = ZonedDateTime . of ( 1983 , JULY . getValue ( ) , 20 , 15 , 27 , 40 , 0 , ZoneId . of ( "Europe/London" ) ) ; dt = dt . plusYears ( 30 ) . minusHours ( 4 ) dt = dt . with ( next ( SUNDAY ) )

Instant

The Instant class is a timestamp. It is useful for representing machine time. A value returned from the Instant class counts time (nanoseconds) beginning from the first second of January 1, 1970 (1970-01-01T00:00:00Z) also called the EPOCH. An instant that occurs before the epoch has a negative value, and an instant that occurs after the epoch has a positive value. Instant objects are useful, for example, while logging. This class is the closest equivalent of java.util.Date.

Instant i1 = Instant.now(); Instant i2 = Instant.now(); if (i1.isAfter( i2)) { ... } 1 2 3 Instant i1 = Instant . now ( ) ; Instant i2 = Instant . now ( ) ; if ( i1 . isAfter ( i2 ) ) { . . . }

Amounts

All the classes that we’ve seen till now, represent instances on the timeline. The amount classes, however, are not tied to the timeline. They are used to represent amount of time, e.g. 3 years, 40 minutes, etc. There are two amount classes in the new library:

Duration

Period

Duration

Duration is useful for representing time based amount – hours, minutes, seconds and nanoseconds. Useful for representing stop watch, timeouts, etc.

Duration duration = Duration.ofHours(2); duration = duration.multipliedBy(3); 1 2 Duration duration = Duration . ofHours ( 2 ) ; duration = duration . multipliedBy ( 3 ) ;

Duration objects can also be added to datetime objects

LocalDateTime dt = LocalDateTime.now(); dt = dt.plus(duration); 1 2 LocalDateTime dt = LocalDateTime . now ( ) ; dt = dt . plus ( duration ) ;

Period

Period objects can be used to represent date based amounts (years, months, days). They can be used to refer to duration of projects for example.

Period period = Period.ofMonths(6); period = period.plusDays(10); 1 2 Period period = Period . ofMonths ( 6 ) ; period = period . plusDays ( 10 ) ;

Happy coding!