How to use the DateTime API in Java 8: Part 2

Sep 12, 2019
hackajob Staff

Following on from our previous tutorial, today we’re going full steam ahead with part 2, this time focusing on ‘ZonedDateTime’.

The 'ZonedDateTime' class is similar to 'LocalDateTime' with the only difference being that it has a time zone component. In addition to the year, month date, hour and minutes, it also has a ‘Zone ID’ that represents a specific time zone. Note that the ‘ZonedDateTime’ class supports around 40 different time zones, and supports time zone information via the 'ZoneId' class explained below.

ZoneId

The ‘java.time’ package has a class called ‘ZonedId’ which represents a time zone. There are several ways of creating a 'ZoneId', with the following code demonstrating how this works:

ZoneId currentTimeZone = ZoneId.systemDefault();

ZoneId australiaTimeZone = ZoneId.of("Australia/Sydney");

ZoneId parisTimeZone = ZoneId.of("GMT+2");

System.out.println("Current System time is "+LocalTime.now(currentTimeZone));

System.out.println("Australia Time is "+LocalTime.now(australiaTimeZone));

System.out.println("Paris Time is "+LocalTime.now(parisTimeZone));

From the code above, we can see that the ‘ZoneId.systemDefault’ returns a ‘ZoneId’ corresponding to the current system time zone. The ‘ZoneId.of’ returns a ‘ZoneId’ corresponding to the String time zone specified, and the accepted String values are specified in the API documentation for ‘ZoneId’. In addition to specifying the actual time zone name, the ‘ZoneId.of’ method also allows for the time zone to be specified as an offset from GMT or UTC.

When you execute this code, the following output is printed:

Current System time is 15:19:46.885

Australia Time      is 19:49:46.886

Paris Time          is 11:49:46.895

ZonedDateTime Creation

Just like ‘LocalDate’, ‘LocalTime’ and ‘LocalDateTime’, ‘ZonedDateTime’ has several static methods that can be used to create a ‘ZonedDateTime’ instance. The following code demonstrates this:

ZonedDateTime zonedDateTime = ZonedDateTime.now();

System.out.println("ZonedDateTime1: "+zonedDateTime);

ZoneId parisZoneId = ZoneId.of("Europe/Paris");

zonedDateTime = ZonedDateTime.now(parisZoneId);

System.out.println("ZonedDateTime2: "+zonedDateTime);

LocalDate date = LocalDate.parse("1995-08-14");

LocalTime time = LocalTime.parse("09:45");

zonedDateTime = ZonedDateTime.of(date,time,ZoneId.systemDefault());

System.out.println("ZonedDateTime3: "+zonedDateTime);

With the example above, we can see that the ‘ZonedDateTime.now()’ returns a ‘ZonedDateTime’ corresponding to the current date and time, using a default time zone from the system clock. From there, the ‘ZonedDateTime.now(zoneId)’ returns a ‘ZonedDateTime’ corresponding to the current date and time in the specified time zone. The ‘ZonedDateTime.of’ method creates a ‘ZonedDateTime’ using the ‘LocalDate’, ‘LocalTime;' and ‘ZonedId’ specified. In addition, there are several overloaded versions of the ‘of’ method that can be used to create a ‘ZonedDateTime’ using a number of parameters.

When the code above is executed, the following output will be printed to the console:

ZonedDateTime1: 2019-08-29T15:33:38.526+05:30[Asia/Calcutta]

ZonedDateTime2: 2019-08-29T12:03:38.528+02:00[Europe/Paris]

ZonedDateTime3: 1995-08-14T09:45+05:30[Asia/Calcutta]

As you can see, with each Date or Time, the time zone is also printed. It’s key to note that ‘ZonedDateTime’ has several other methods that can be used in order to create a ‘ZonedDateTime’ instance so make sure to check out the literature on how it works for more information.

ZonedDateTime Operations

Just like ‘LocalDate’, ‘LocalTime’ and ‘LocalDateTime’, ‘ZonedDateTime’ has several methods that can be used to perform arithmetic, extract information or perform comparisons. The following code demonstrates how this works:

ZoneId parisZoneId = ZoneId.of("Europe/Paris");

ZonedDateTime zonedDateTime1 = ZonedDateTime.of(2012,8,11,5,25,0,0,parisZoneId);

System.out.println("zonedDateTime1 is "+zonedDateTime1);

ZonedDateTime zonedDateTime2 = zonedDateTime1.minusMinutes(15);

System.out.println(" minus 15 minutes:  "+zonedDateTime2);

Month month = zonedDateTime1.getMonth();

System.out.println("Month: "+month);

LocalDate date = zonedDateTime1.toLocalDate();

System.out.println("Date   :"+date);

ZonedDateTime zonedDateTime3 = zonedDateTime1.withHour(8);

System.out.println(" with hour as 8:  "+zonedDateTime3);

In the example above, we can see that the ‘ZonedDateTime.minusMinutes’ method subtracts the specified number of minutes from the 'ZonedDateTime' object. The ‘ZonedDateTime.getMonth’ returns the month component in the ‘ZonedDateTime’ object. From there, the ‘ZonedDateTime.toLocalDate’ returns the ‘LocalDate’ component in the ‘ZonedDateTime’ and the ‘ZonedDateTime.withHour’ sets the hour component in the ‘ZonedDateTime’ to the specified value.

When the code above is executed, it’ll print the following output to the console:

zonedDateTime1  is 2012-08-11T05:25+02:00[Europe/Paris]

minus 15 minutes  :2012-08-11T05:10+02:00[Europe/Paris]

Month:         :AUGUST

Date           :2012-08-11

with hour as 8 :2012-08-11T08:25+02:00[Europe/Paris]

Period and Duration

Java 8’s DateTime API allows you to easily calculate the time between both date objects and time objects. The two classes that can be used to achieve this are ‘Period’ and ‘Duration’ and we’ve explained how they work below.

Period

The ‘Period’ class represents time in years, months and days and can be used to measure the period between two dates. The total period of time is represented by all three units together: months, days and years. The following code demonstrates how this works:

LocalDate date1 = LocalDate.of(2012, Month.MAY, 5);

LocalDate date2 = LocalDate.of(2016, Month.OCTOBER,11);

System.out.println("Date1   :"+date1);

System.out.println("Date2   :"+date2);

Period period = Period.between(date1, date2);

System.out.print("Period using Period.between :");

System.out.print(period.getYears() + " years,");

System.out.print(period.getMonths() + " months,");

System.out.println(period.getDays() + " days");

Period period2 = date1.until(date2);

System.out.print("Period using LocalDate.until   :");

System.out.print(period2.getYears() + " years,");

System.out.print(period2.getMonths() + " months,");

System.out.print(period2.getDays() + " days");

Within the example above, we can see that the ‘Period.between’ is a static method on the ‘Period’ class that returns a ‘Period’ object. Remember that the ‘Period’ class has the methods ‘getYears’, ‘getMonths’ and ‘getDays’ that return the years, months and days between the dates. Finally, ‘LocalDate.until’ can also be used to find the period between dates.

When this code is executed, the following output will be printed:

Date1   :2012-05-05

Date2   :2016-10-11

Period using Period.between :4 years,5 months,6 days

Period using LocalDate.until   :4 years,5 months,6 days

Duration

The ‘Duration’ class represents time in both seconds or nanoseconds and can be used to measure shorter durations of time, typically between two ‘LocalTime’ objects. The following lines of code showcase how this works:

LocalTime time1 = LocalTime.parse("09:30:10");

LocalTime time2 = LocalTime.parse("12:15:25");

System.out.println("Time1   :"+time1);

System.out.println("Time2   :"+time2);

Duration duration = Duration.between(time1, time2);

System.out.print("Duration is ");

System.out.print(duration.getSeconds()+" seconds,");

System.out.println(duration.getNano()+" nanoseconds");

System.out.print("Duration in hours:");

System.out.println(duration.toHours() + " hours");

System.out.print("Duration in minutes:");

System.out.println(duration.toMinutes() + " minutes");

The ‘Duration.between’ mentioned above is a static method on the 'Duration' class that returns a 'Duration' object. The ‘Duration’ class has the methods ‘getSeconds’ and ‘getNanoseconds’ that return the seconds and nanoseconds between the time instances, whereas the ‘Duration.toHours’ method returns the duration in hours. Finally, ‘Duration.toMinutes’ returns the duration in minutes.

When this code is executed, it will print the following output:

Time1   :09:30:10

Time2   :12:15:25

Duration is       :9915 seconds,0 nanoseconds

Duration in hours :2 hours

Duration in minutes  :165 minutes

Other important classes in java.time

Instant

The ‘Instant’ class represents a certain instant of time up to nanosecond precision, is similar to the ‘java.util.Date’ class and is typically used to record a timestamp in an application. The following code demonstrates how this works:

Instant instant = Instant.now();

System.out.println("Current instant is: "+instant);

Instant instant2 = Instant.parse("2012-04-25T18:13:20.163Z");

System.out.println("Instant2 is: "+instant2);

ZonedDateTime zonedDateTime = instant2.atZone(ZoneId.of("Australia/Sydney"));

System.out.println("ZonedDateTime is: "+zonedDateTime);

Above, we can see that ‘Instant.now’ returns an ‘Instant’ that corresponds to the current time as per the UTC time zone, whilst ‘instant.parse’ creates an ‘Instant’ corresponding to the date and time in the supplied 'String'. The 'String' supplied must be a valid instant in the UTC time zone and has to be in the same format as specified above. From there, the ‘Instant.atZone’ combines the instant with a time zone and returns a ‘ZonedDateTime’.

When this code is executed, it will print the following:

Current instant is: 2019-08-30T10:21:44.577Z

Instant2     is: 2012-04-25T18:13:20.163Z

ZonedDateTime   is: 2012-04-26T04:13:20.163+10:00[Australia/Sydney]

In addition to the method outlined above, there are several other static methods on the ‘Instant’ class that can be used to obtain an ‘Instant’. Just like ‘LocalDate', 'LocalTime’ and ‘LocalDateTime’, the ‘Instant’ class has several methods that can be used to perform instant arithmetic or instant comparison.

Clock

Just as the name suggests, the ‘Clock’ class represents a clock and can be used to obtain an ‘Instant’. The ‘Instant’ returned by the clock is always as per the UTC time zone, with the ‘Clock’ class having a time zone component which can be used to convert the time returned by the clock to any time zone required.

The following code shows how this works:

Clock clock = Clock.systemDefaultZone();

System.out.println("clock:"+clock.instant());

ZonedDateTime time2 = clock.instant().atZone(clock.getZone());

System.out.println("Time:"+time2);

Within the code above, we can see that the ‘Clock.systemDefaultTimeZone’ creates a ‘Clock’ corresponding to the system clock as well as the default time zone. The ‘Clock.instant’ method returns the current ‘Instant’ represented by the clock in the UTC time zone. The ‘clock.getZone’ returns the time zone component in the clock, whilst the ‘Instant.atZone’ method combines the UTC ‘Instant’ returned by the clock with the time zone in the clock returning a ‘ZonedDateTime’.

When this code is executed, it will print the following output:

clock:2019-08-30T12:00:28.582Z

Time:2019-08-30T17:30:28.603+05:30[Asia/Calcutta]

In addition to these methods, there are several others in the ‘Clock’ class that can be used to create a clock instance with different time zones and more.

In addition to the ‘Java.time’ package, there are a few other packages added by Java 8 that correspond to time and date. We’ve outlined some examples below:

java.time.format - This has classes which can be used to parse and format date or time objects. The ‘DateTimeFormatter’ class referenced earlier (for formatting a ‘LocalDate’, ‘LocalTime’, ‘LocalDateTime’ or ‘ZonedDateTime’) is part of this package.

java.time.chrono - This has classes that handle other calendar systems, such as ‘HijrahDate’ (which represents a date in the Hijra calendar system) and ‘JapaneseDate’ (which represents a date in the Japanese calendar system) as an example.

java.time.temportal - This has classes for both fields and units. A field represents a component in a date or time like hours, minutes etc whilst a unit is used to measure an amount of time, such as years, days or minutes. As well as this, this class also has date/time adjusters which can used for special-case ‘DateTime’ calculations, like the first Monday of the month for example.

Overall, the Java 8 DateTime API is a significant improvement from the Pre Java 8 ‘Date’ and ‘Calendar’ classes. Providing easy-to-use methods that can be used to perform calculations related to both date and time, we highly recommend learning as much as you can about Java 8’s DateTime API and the different classes that go alongside it.

Liked this tutorial? Make sure to read our other articles about all-things Java 8.