Bill Bejeck is a software developer and enjoys the challenges that software development brings. Bill also loves exploring new languages, technologies and learning and educating by blogging. Bill is a DZone MVB and is not an employee of DZone and has posted 28 posts at DZone. You can read more from them at their website. View Full User Profile

Whats New in Java 8 - Date API Part II

04.07.2014
| 3645 views |
  • submit to reddit

This post is continues our review of the Date API that came with the release of Java 8. We are going to continue our concentration on classes that make working with dates/times very easy. Working with date objects in previous releases of Java was very challenging with respect to adding time or getting the difference between dates. Hopefully after looking at the classes we present here, your opinion of working with dates and times in Java will change. Specifically, we are going to take a look at the following classes:

  • Other classes to represent dates/times ZonedDateTime and OffsetDateTime
  • Getting the current snapshot in time with Instant
  • Using the Clock class to get system time but specify different time zones
  • Represent arbitrary number of days with the Period class
  • Represent arbitrary amount of hours with the Duration class

Zoned/Offset Dates and Times

In the last post we covered the LocalDateTimeLocalDate and the LocalTime classes. As the name suggests, these classes give the date and or time for a given locality with no time-zone or offset from UTC/Greenwhich time. Java 8 provides the ZonedDateTime class which provides date-times with a time-zone representation. Creating a ZonedDateTime instance can be done several ways, but here we will demonstrate using two of the many static factory methods:

Creating a ZonedDateTime Instance
 //Uses the system clock using the default time-zone.
 ZonedDateTime zdt = ZonedDateTime.now();
 //Displays as 2014-03-28T21:52:09.122-04:00
 //Uses the system clock with the specified time-zone
 ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
 //Displays as 2014-03-29T01:45:34.605Z[Europe/Dublin]

Next we have the OffsetDateTime and the OffsetTime classes that represent date-time or time (respectively) with offsets from UTC/Greenwhich time. Here we show creating OffsetDateTimeand OffsetTime using some of the other available static factory methods:

Creating OffsetDateTime/OffsetTime Instances
OffsetDateTime odt = OffsetDateTime.of(LocaDateTime.now(),ZoneOffset.of("-4"));
//Displays as 2014-03-28T22:30:28.911-04:00
OffsetTime ot = OffsetTime.ofInstant(Intant.now(),ZoneId.of("America/Los_Angeles"));
//Displays as 19:45:40.661-07:00

In the last example we see the use of the Instant class which we will introduce soon. It’s worth noting at this point that the ZondedDateTime,OffsetDateTime classes store time to nanosecond precision. Typically we would use the ZonedDateTime class when showing date-times to users and the OffsetDateTime class when interacting with systems.

Clock

The [a href="http://docs.oracle.com/javase/8/docs/api/java/time/Clock.html" style="font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; font-size: 18px; color: rgb(117, 21, 144); -webkit-transition: color 0.3s; transition: color 0.3s; white-space: pre-wrap; word-wrap: break-word;"]Clock class gives us the ability to get the current date/time from the system clock with a specific time-zone. Although there are date-time classes that have a now() method returning the current date-time, the system clock uses the default time-zone. The Clock class allows us to get the system time with a given time-zone. We can then plug the Clock instance into other classes where we want to get the current time using a given time-zone.

Creating Clock instances
//Returns Clock with default time-zone
Clock default = Clock.systemDefaultZone();
//Clock with desired time-zone
Clock clock = Clock.system(ZoneId.of("America/Chicago"));

We can now re-work our previous example of creating an OffsetTime object using a Clockinstance to set the desired time-zone:

Using Clock with OffsetDateTime
Clock clock = Clock.system(ZoneId.of("America/Los_Angeles"));
......
public void someOperation(Clock clock){
     OffsetTime ot = OffsetTime.of(clock);
     ... some work involving the OffsetTime intance
}

The Clock class also allows us to specify how it ‘ticks’, meaning we can have the time returned from the Clock instance ticking on whole minutes or seconds

Setting the ‘tick’ level for a Clock
Clock wholeMinuteClock = Clock.tickMinutes(ZoneId.of("Europe/Athens"));
Clock wholeSecondClock = Clock.tickSeconds(ZonieId.of("Europe/Prauge"));

Instant

The Instant class is used to capture the current ‘instant’ in time. The Instant class is useful for obtaining event timestamps and also has nanosecond precision.

Getting an Instant
//Record the current moment on the time-line from the system clock
Instant now = Instant.now();
//Record the current instant with the given Clock instance
Instance now = Instant.now(clock)

The Instant class has several other methods for adjusting an Instant instance such as adding/subtracting time or converting to a OffsetDateTime or ZonedDateTime.

Period

The Period class represents an arbitrary amount of time in years, months, or days. Period objects can be particularly useful for adding/subtracting time to/from a date. For example:

Using Period class to add to or subtract from dates
@Test
public void test_add_days(){
    LocalDateTime today = LocalDateTime.parse("2014-03-12T19:36:33");
    Period sixDays = Period.ofDays(6);
    LocalDateTime nextWeek = today.plus(sixDays);
    assertThat(nextWeek.toString(),is("2014-03-18T19:36:33"));
}
@Test
public void test_subtract_days(){
    LocalDate today = LocalDate.parse("2014-03-12");
    Period twoWeeks = Period.ofWeeks(2);
    LocalDate past = today.minus(twoWeeks);
    assertThat(past.toString(),is("2014-02-26"));
}

The Period class also offers a static method Period.between that is great for determining elapsed time between dates:

Getting time between dates with Period class
@Test
public void test_period_between_dates(){
    LocalDate twins = LocalDate.parse("2003-11-18");
    LocalDate mayhem = LocalDate.parse("2009-06-01");
    Period timeBetween = Period.between(twins,mayhem);
    assertThat(timeBetween.getYears(),is(5));
    assertThat(timeBetween.getMonths(),is(6));
    assertThat(timeBetween.getDays(),is(14));
}

While the Period.between method requires types of LocalDate, the date-time classes in the java.time package offer a toLocalDate() method that returns a LocalDate from the date-time instance.

Duration

The Duration class represents arbitrary amounts of time in hours, minutes or seconds. The useage pattern for Duration is similar to that of the Period class. Here are examples of adjusting time objects using the Duration class:

using Duration to add/subtract time
@Test
public void test_add_time(){
    Duration oneHourThirtyMinutes = Duration.ofHours(1).plusMinutes(30);
    OffsetTime now = OffsetTime.parse("10:15:30-05:00");
    OffsetTime later = now.plus(oneHourThirtyMinutes);
    assertThat(later.toString(),is("11:45:30-05:00"));
    Duration threeHours = Duration.parse("PT3H");
    LocalTime twoPM = LocalTime.parse("14:00:00");
    LocalTime fivePM = twoPM.plus(threeHours);
    assertThat(fivePM.toString(),is("17:00"));
}
@Test
public void test_subtract_time(){
    OffsetTime offsetTime = OffsetTime.parse("13:34:00+01:00");
    LocalTime earlier = LocalTime.parse("09:30:25");
    LocalTime later = LocalTime.parse("15:33:47");
    Duration timeSpan = Duration.between(earlier,later);
    OffsetTime adjustedOffsetTime = offsetTime.minus(timeSpan);
    assertThat(adjustedOffsetTime.toString(),is("07:30:38+01:00"));
}

The Duration class also has a between method for determing the amount of time (hours based) between time objects:

using Duration to determine difference between time objects
@Test
public void test_time_between(){
    LocalTime earlier = LocalTime.parse("09:30:25");
    LocalTime later = LocalTime.parse("15:33:47");
    Duration timeSpan = Duration.between(earlier,later);
    assertThat(timeSpan.toString(),is("PT6H3M22S"));
    assertThat(LocalTime.MIDNIGHT.plus(timeSpan).toString(),is("06:03:22"));
}

The Duration.between method requires types of Temporal. All of the time and date-time classes in the java.time package implement the Temporal interface.

Conclusion

This wraps up our brief tour of the new Date API in Java 8. Hopefully you can see the promise in the new Date API for working with dates and times. In future posts I plan to continue coverage of the new features found in Java 8. Thanks for your time.

Resources

Published at DZone with permission of Bill Bejeck, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)