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 hasisDaylightSavings()
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
Difference Between Static and Final
How to Get an Enum Based on the Value of Its Field
Export PDF Pages to a Series of Images in Java
How to Implement Infinity in Java
String Replacement in Java, Similar to a Velocity Template
How to Set Jvm Arguments in Intellij Idea
Java Try/Catch/Finally Best Practices While Acquiring/Closing Resources
Detect Internet Connection Using Java
Create Java Runtime Image on One Platform for Another Using Jlink
How to Delete a Folder with Files Using Java
How to Configure Hibernate Config File for SQL Server
JSON Gson.Fromjson Java Objects
Copying Text to the Clipboard Using Java
Print All the Spring Beans That Are Loaded
Find the Most Popular Element in Int[] Array
Can Add Extra Field(S) to @Manytomany Hibernate Extra Table