Don’t worry, use java.time
- Apparently you are using the Joda-Time library. Use java.time instead.
- The java.time classes automatically handle Daylight Saving Time (DST) cutovers.
- No need for you to do anything except keep your JVM up-to-date with tzdata time zone database changes that may affect your time zones of interest. See Oracle’s provided tool for tzdata updates.
java.time
Let's look at the results of adding six hours using the java.time classes.
Define the date and the time-of-day portions.
LocalDate ld = LocalDate.of ( 2015, Month.OCTOBER, 24 ); // 24th Oct 2015 at 10:00am per the Question.
LocalTime lt = LocalTime.of ( 10, 0 );
Define the time zone, a ZoneId
object, for Europe/London
.
ZoneId z = ZoneId.of ( "Europe/London" );
Combine to create a ZonedDateTime
object.
ZonedDateTime zdtStart = ZonedDateTime.of ( ld, lt, z );
Extract an Instant
from the ZonedDateTime
. The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instantStart = zdtStart.toInstant ( );
Define our span of time, six hours, as a Duration
. The java.time classes can perform date-time math by adding a Duration
object.
A Duration
is unattached to the timeline, and actually stores a number of seconds and a number of nanoseconds. So there are no smarts about “six hours” and the clock and DST etc. within this class. When we ask for a Duration
of six hours, that class immediately calculates ( 6 hours * 60 minutes per hour * 60 seconds per minute ) = 21,600 seconds in total.
Duration sixHours = Duration.ofHours ( 6 ); // 21,600 seconds = ( 6 hours * 60 minutes per hour * 60 seconds per minute ).
Loop ten times. First loop by adding the Duration
to ZonedDateTime
, and convert the result to an Instant
.
// Increment the `ZonedDateTime`.
ZonedDateTime zdt = zdtStart;
for ( int i = 1 ; i <= 10 ; i++ ) {
System.out.println ( ">zdt.toString() " + zdt + " | zdt.toInstant().toString(): " + zdt.toInstant ( ) + "\n");
// Set up next loop.
zdt = zdt.plus ( sixHours );
}
When run. Note the jump in the time-of-day in London time. This is the Daylight Saving Time (DST) cutover, the “Fall-back” time in the autumn when England switches back to standard time going from an offset-from-UTC of +01:00
to Zulu offset of +00:00
, where at 2 AM the clock jumps back to repeat the 1 AM hour. So where we would otherwise expect 22:00 plus six hours to result in 4 AM, we instead see 3 AM. You can see in the Instant
value that six hours did indeed elapse. The trick was that Londoners wound-back their clocks an hour around then.
See the history of DST cutovers for Europe/London
.
zdt.toString() 2015-10-24T10:00+01:00[Europe/London] | zdt.toInstant().toString(): 2015-10-24T09:00:00Z
zdt.toString() 2015-10-24T16:00+01:00[Europe/London] | zdt.toInstant().toString(): 2015-10-24T15:00:00Z
zdt.toString() 2015-10-24T22:00+01:00[Europe/London] | zdt.toInstant().toString(): 2015-10-24T21:00:00Z
zdt.toString() 2015-10-25T03:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-25T03:00:00Z
zdt.toString() 2015-10-25T09:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-25T09:00:00Z
zdt.toString() 2015-10-25T15:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-25T15:00:00Z
zdt.toString() 2015-10-25T21:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-25T21:00:00Z
zdt.toString() 2015-10-26T03:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-26T03:00:00Z
zdt.toString() 2015-10-26T09:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-26T09:00:00Z
zdt.toString() 2015-10-26T15:00Z[Europe/London] | zdt.toInstant().toString(): 2015-10-26T15:00:00Z
For fun we swap, adding the six hours successively to Instant
and convert the result to London time.
// Increment the `Instant`.
Instant instant = instantStart;
for ( int i = 1 ; i <= 10 ; i++ ) {
System.out.println ( ">instant.toString() " + instant + " | instant.atZone(z).toString(): " + instant.atZone ( z ) + "\n");
// Set up next loop.
instant = instant.plus ( sixHours );
}
When run, we see the same values output.
instant.toString() 2015-10-24T09:00:00Z | instant.atZone(z).toString(): 2015-10-24T10:00+01:00[Europe/London]
instant.toString() 2015-10-24T15:00:00Z | instant.atZone(z).toString(): 2015-10-24T16:00+01:00[Europe/London]
instant.toString() 2015-10-24T21:00:00Z | instant.atZone(z).toString(): 2015-10-24T22:00+01:00[Europe/London]
instant.toString() 2015-10-25T03:00:00Z | instant.atZone(z).toString(): 2015-10-25T03:00Z[Europe/London]
instant.toString() 2015-10-25T09:00:00Z | instant.atZone(z).toString(): 2015-10-25T09:00Z[Europe/London]
instant.toString() 2015-10-25T15:00:00Z | instant.atZone(z).toString(): 2015-10-25T15:00Z[Europe/London]
instant.toString() 2015-10-25T21:00:00Z | instant.atZone(z).toString(): 2015-10-25T21:00Z[Europe/London]
instant.toString() 2015-10-26T03:00:00Z | instant.atZone(z).toString(): 2015-10-26T03:00Z[Europe/London]
instant.toString() 2015-10-26T09:00:00Z | instant.atZone(z).toString(): 2015-10-26T09:00Z[Europe/London]
instant.toString() 2015-10-26T15:00:00Z | instant.atZone(z).toString(): 2015-10-26T15:00Z[Europe/London]
See this code run live at IdeOne.com.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
- Java SE 8 and SE 9 and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.