Java 8 Instant class not have plusHours method despite shown in Oracle Tutorial example code

Solution 1:

The Oracle Tutorial is incorrect

Unfortunately, the Oracle Tutorial is incorrect on this matter. That line of example code is simply wrong. Good catch on your part.

This error is quite unfortunate as the Tutorial is otherwise a fine resource for learning and studying Java.

Instant::plus

The Instant class has no such method as plusHours defined in either Java 8 or Java 9.

Instead, you can call the plus method, and specify hours.

Instant later = instant.plus( 1 , ChronoUnit.HOURS ) ;

ZonedDateTime::plusHours

The Instant class is a basic building-block class, indicating a moment on the timeline in UTC. Usually when performing manipulations such as adding hours, you’ll likely want to account for anomalies such as Daylight Saving Time, and so you will care about time zone. For that, use the ZonedDateTime class. That class does offer a convenient plusHours method, a likely source of the confusion for the Tutorial authors.

Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).

ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment, but viewed through the lens of a region’s wall-clock time.
ZonedDateTime zdtLater = zdt.plusHours( 1 ) ;

Instant versus ZonedDateTime

Let's look at an example of an anomaly in adding hours. When zoned, we add an hour to the particular moment of 1 AM on March 23, 2017 and of course expect 2 AM, but we are surprised to see 3 AM. Yet when we consider the very same moment in UTC rather than that particular time zone, the very same point on the timeline, adding an hour behaves as expected.

This particular anomaly is due to the adoption of Daylight Saving Time (DST) in most of North America, in particular here, the time zone America/New_York. In the Spring, the clocks "spring-forward" an hour. As the clocks strike 2 AM, they jump to 3 AM. So the hour of two o’clock never existed on that day.

// ZonedDateTime
LocalDate ld = LocalDate.of( 2017 , Month.MARCH , 12 ) ;
LocalTime lt = LocalTime.of( 1 , 0 ) ;
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z ) ;
ZonedDateTime zdtOneHourLater = zdt.plusHours( 1 ) ;

System.out.println( "zdt: " + zdt ) ;
System.out.println( "zdtOneHourLater: " + zdtOneHourLater ) ; 
System.out.println( "Yikes! 1 AM plus an hour is 3 AM? Yes, that is an anomaly known as Daylight Saving Time (DST)." ) ;
System.out.println( "" ) ;

// Instant
Instant instant = zdt.toInstant() ;  // Adjust into UTC. Same moment, same point on the timeline, but viewed by a different wall-clock.
Instant instantOneHourLater = instant.plus( 1 , ChronoUnit.HOURS ) ;

System.out.println( "instant: " + instant ) ;
System.out.println( "instantOneHourLater: " + instantOneHourLater ) ;  
System.out.println( "Instant is always in UTC. So no anomalies, no DST. Adding an hour to 1 AM results in 2 AM every time." ) ;

See this code run live at IdeOne.com.

zdt: 2017-03-12T01:00-05:00[America/New_York]

zdtOneHourLater: 2017-03-12T03:00-04:00[America/New_York]

Yikes! 1 AM plus an hour is 3 AM? Yes, that is an anomaly known as Daylight Saving Time (DST).

instant: 2017-03-12T06:00:00Z

instantOneHourLater: 2017-03-12T07:00:00Z

Instant is always in UTC. So no anomalies, no DST. Adding an hour to 1 AM results in 2 AM every time.