Determine Whether Daylight Savings Time (Dst) Is Active in Java for a Specified Date

How to show the difference in time after the daylight saving started in Java?

I'll add a very brief answer. It shows that 1 day is not equal to 24 hours, i.e. DST changed. I also stepped over to Java 8 because I'm more familiar with it.

ZoneId timezone = ZoneId.of("Brazil/East");

ZonedDateTime t = ZonedDateTime.of(2018, 10, 20, 7, 52, 16, 0, timezone);

System.out.println(t);
System.out.println(t.plus(1, ChronoUnit.DAYS));
System.out.println(t.plus(24, ChronoUnit.HOURS));

Output:

2018-10-20T07:52:16-03:00[Brazil/East]

2018-10-21T07:52:16-02:00[Brazil/East]

2018-10-21T08:52:16-02:00[Brazil/East]

Get Daylight Saving Transition Dates For Time Zones in Java

Joda Time (as ever) makes this really easy due to the DateTimeZone.nextTransition method. For example:

import org.joda.time.*;
import org.joda.time.format.*;

public class Test
{
public static void main(String[] args)
{
DateTimeZone zone = DateTimeZone.forID("Europe/London");
DateTimeFormatter format = DateTimeFormat.mediumDateTime();

long current = System.currentTimeMillis();
for (int i=0; i < 100; i++)
{
long next = zone.nextTransition(current);
if (current == next)
{
break;
}
System.out.println (format.print(next) + " Into DST? "
+ !zone.isStandardOffset(next));
current = next;
}
}
}

Output:


25-Oct-2009 01:00:00 Into DST? false
28-Mar-2010 02:00:00 Into DST? true
31-Oct-2010 01:00:00 Into DST? false
27-Mar-2011 02:00:00 Into DST? true
30-Oct-2011 01:00:00 Into DST? false
25-Mar-2012 02:00:00 Into DST? true
28-Oct-2012 01:00:00 Into DST? false
31-Mar-2013 02:00:00 Into DST? true
27-Oct-2013 01:00:00 Into DST? false
30-Mar-2014 02:00:00 Into DST? true
26-Oct-2014 01:00:00 Into DST? false
29-Mar-2015 02:00:00 Into DST? true
25-Oct-2015 01:00:00 Into DST? false
...

With Java 8, you can get the same information using ZoneRules with its nextTransition and previousTransition methods.

Determining the hour in daylight saving time

Count from epoch

Your java.util.Date objects actually are in UTC but their toString method confusingly applies a time zone when generating the string output.

You can differentiate two Date objects by interrogating for their count from epoch. Internally the date-time is tracked as a number of milliseconds since first moment of 1970 in UTC. Call the badly-named method java.util.Date::getTime to get a long.

UTC

Record moments in UTC. Every programmer should learn to think in UTC, work in UTC, do logging in UTC, and keep a second clock on their desk and screen set to UTC.

UTC is the One True Time. All others are mere variations, every time zone being a deviation from UTC.

Let me repeat the acronym one more time to be clear: UTC

Instant

The Instant class is your new best friend in this arena, your go-to class for date-time work. It represents a moment on the timeline in UTC with a resolution of nanoseconds.

Instant instant = Instant.now() ;

You need not worry about Daylight Saving Time (DST) cut-overs, politicians redefining DST ( often with little notice), nor other anomalies particular to any one time zone. Just use UTC.

To generate a String representing this moment, call toString for a string in standard ISO 8601 format. This string is always in UTC, so you don't have the problem of Date::toString applying a time zone while generating the string. The standard format has a Z on the end, short for Zulu, and means UTC.

instant.toString():
2016-01-23T12:34:56.123456789Z

Converting Date

Convert your java.util.Date objects to Instant. New conversion methods have been added to the old classes.

Instant instant = myUtilDate.toInstant();

Zoned

I do not care about Berlin time. You, as a programmer, do not care about Berlin time. Your network and server admins do not care about Berlin time. We care about UTC.

The only people who care about Berlin time are end-users. For them, you can assign a time zone for presentation of data.

ZoneId z = ZoneId.of( "Europe/Berlin" );
ZonedDateTime zdt = instant.atZone( z );

Call toString to generate a String in standard ISO 8601 format but wisely extended by appending the name of the time zone in square brackets.

2016-07-07T08:00:15.768+02:00[Europe/Berlin]

Use DateTimeFormatter class to generate Strings representing the date-time value in other formats.

DST in effect?

You can interrogate to determine if Daylight Saving Time (DST) is in effect for any particular ZonedDateTime. See this Question.

ZoneRules rules = zdt.getZone().getRules();
Boolean dstInEffect = rules.isDaylightSavings( zdt.toInstant() );

Java API to get daylight saving boundaries for a year

Daylight Saving changes occur at different dates in each country/region, so the first thing to know is the name of the timezone you're checking.

I'm writing this answer using both Joda-Time and the new Java Date/Time API and both use the IANA's list of timezone names (in the format Continent/City). Both API's also avoid to use the 3-letter names because they are ambiguous and not standard.

For the code below I'm gonna use America/Sao_Paulo (the timezone where I live, which has DST changes every year), but you can replace it with the timezone you want.

The code below shows you how to check if a date is in DST and find the next date when a DST change will occur. So, if you have a start and end dates and want to know if both are in within a DST change, you can check if both are in DST or not and also find the next and previous DST changes (and check if the dates are between those changes - it's not clear to me how your check should be done).


Also be aware that Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".



Joda-Time

You can use the org.joda.time.DateTimeZone class. To know all the available timezones, call DateTimeZone.getAvailableIDs().

The code below checks if a date is in DST and also finds the next date when a DST change will occur:

// create timezone object
DateTimeZone zone = DateTimeZone.forID("America/Sao_Paulo");

// check if a date is in DST
DateTime inDst = new DateTime(2017, 1, 1, 10, 0, zone);
// isStandardOffset returns false (it's in DST)
System.out.println(zone.isStandardOffset(inDst.getMillis()));
// check when it'll be the next DST change
DateTime nextDstChange = new DateTime(zone.nextTransition(inDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-02-18T23:00:00.000-03:00

// check if a date is in DST
DateTime noDst = new DateTime(2017, 6, 18, 10, 0, zone);
// isStandardOffset returns true (it's not in DST)
System.out.println(zone.isStandardOffset(noDst.getMillis()));
// check when it'll be the next DST change
nextDstChange = new DateTime(zone.nextTransition(noDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-10-15T01:00:00.000-02:00

If you want to find the previous DST change (instead of the next), call previousTransition() instead of nextTransition().



Java new Date/Time API

If you're using Java 8, the new java.time API already comes natively.

If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).

The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.

The code is very similar to Joda-Time's version. The main differences:

  • While Joda-Time has isStandardOffset() to check if the date is not in DST, the new API has isDaylightSavings() to check if the date is in DST.
  • Joda-Time provides the methods directly in the DateTimeZone class, but the new API has a dedicated class to its DST rules (java.time.zone.ZoneRules)
  • The methods for next and previous transitions return a java.time.zone.ZoneOffsetTransition instead of directly returning a date (this object provides more information about the DST change, as showed below).

Despite all those differences, the idea is very similar:

// create timezone object
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// get the timezone's rules
ZoneRules rules = zone.getRules();

// check if a date is in DST
ZonedDateTime inDST = ZonedDateTime.of(2017, 1, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns true (it's in DST)
System.out.println(rules.isDaylightSavings(inDST.toInstant()));
// check when it'll be the next DST change
ZoneOffsetTransition nextTransition = rules.nextTransition(inDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-02-18T23:00-03:00[America/Sao_Paulo]

// you can also check the date/time and offset before and after the DST change
// in this case, at 19/02/2017, the clock is moved 1 hour back (from midnight to 11 PM)
ZonedDateTime beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-02-19T00:00-02:00
ZonedDateTime afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-02-18T23:00-03:00

// check if a date is in DST
ZonedDateTime noDST = ZonedDateTime.of(2017, 6, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns false (it's not in DST)
System.out.println(rules.isDaylightSavings(noDST.toInstant()));
// check when it'll be the next DST change
nextTransition = rules.nextTransition(noDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-10-15T01:00-02:00[America/Sao_Paulo]

// you can also check the date/time and offset before and after the DST change
// in this case, at 15/10/2017, the clock is moved 1 hour forward (from midnight to 1 AM)
beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-10-15T00:00-03:00
afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-10-15T01:00-02:00

If you want to find the previous DST change instead of the next, you can call rules.previousTransition() instead of rules.nextTransition().

How to tackle daylight savings using TimeZone in Java

This is the problem to start with:

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));

The 3-letter abbreviations should be wholeheartedly avoided in favour of TZDB zone IDs. EST is Eastern Standard Time - and Standard time never observes DST; it's not really a full time zone name. It's the name used for part of a time zone. (Unfortunately I haven't come across a good term for this "half time zone" concept.)

You want a full time zone name. For example, America/New_York is in the Eastern time zone:

TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);

System.out.println(format.format(new Date()));


Related Topics



Leave a reply



Submit