I have the below code to add time to a DateTime instance:
DateTime d1 = new DateTime();
d1 = d1.withZone(DateTimeZone.forID("Europe/London"));
ArrayList<String> timeList = new ArrayList<String>();
for(int x = 1; x <= 10; x++) {
//Adds six hours to the DateTime instance.
d1 = d1.plusHours(6);
d1 = d1.plusMinutes(0);
d1 = d1.plusSeconds(0);
timeList.add(d1.toString());
}
This will create a set of 10 times to add to an arraylist. However say there was a daylight saving change when the 6 hours were added. How can I generate the correct time when the extra hour is added/removed due to the timezone change? At the moment it does not remove/add the extra hour using this method.
For example I would expect the below times to be generated if I was to begin running the code on the 24th Oct 2015 at 10:00am. Note that the timezone changes at 02:00am on 25/10/2015.
24/10/2015 10:00:00 BST
24/10/2015 16:00:00 BST
24/10/2015 22:00:00 BST
25/10/2015 05:00:00 GMT
25/10/2015 11:00:00 GMT
25/10/2015 17:00:00 GMT
25/10/2015 23:00:00 GMT
26/10/2015 05:00:00 GMT
26/10/2015 11:00:00 GMT
26/10/2015 17:00:00 GMT
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.
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?
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.