Java Time Zone Database vs IANA data - java

There is a Daylight Savings Time discrepancy between the IANA database and the Java tzdb.dat 2019c
database in the Africa/Cassablanca time zone that has me very confused. There may be others but I found this one. From what I can tell the IANA time zone database clearly shows that DST is supported in Morocco (Africa/Casablanca) unfortunately the Java time zone database tzdb.dat in the 2019c release does not agree. This has and will cause me infinite grief. What am I missing here, or have others seen this kind of thing
The IANA table 2019c for Africa/Casablanca
Note: the part of the table below shows that the normal time is UTC+1 and Day light savings time is UTC a slash (/) separates standard and daylight abbreviations
Zone NAME STDOFF RULES FORMAT [UNTIL]
Zone Africa/Casablanca -0:30:20 - LMT 1913 Oct 26
0:00 Morocco +00/+01 1984 Mar 16
1:00 - +01 1986
0:00 Morocco +00/+01 2018 Oct 28 3:00
1:00 Morocco +01/+00
From Oct 28 2018 till present offset is +1 for standard and +0 for daylight savings (a slash (/) separates standard and daylight abbreviations.)
STDOFF 1:00 so The amount of time to add to UT to get standard time, without any adjustment for daylight saving this corresponds to UTC +1 that is the current Morocco time.
So we take Zone Africa/Casablanca which is UTC and add the offsets +01/+00 depending on Ramadan.'
The test
I wrote a simple Java class to check the 2019c TZDB. This class (shown below) shows that something is wrong with the latest Java time zone data file tzdb.dat file. This test was run using IBM SR5FP40 with the time zone 2019c data file. I had the same results with OpenJDK using a 2019c datafile.
First line from tzdb.dat shows 2019c
TZDB 2019cX Africa/Abidjan Africa/Accra Africa/Addis_Ababa Africa/Algiers
Test that shows the problem
Time Zone = Africa/Casablanca
Supports Day light Savings time = false
Date Mon May 20 00:00:00 WET 2019 is currently in DST false
Time zone name Western European Time
Time zone ID Africa/Casablanca
A baseline test was also run to show if DST is supported the code will show it.
Time Zone = Europe/Rome
Supports Day light Savings time = true
Date Mon May 20 00:00:00 CEST 2019 is currently in DST true
Time zone name Central European Time
Time zone ID Europe/Rome
The code is here for reference
import java.util.*;
import java.text.SimpleDateFormat;
import java.text.ParseException;
public class checkdaylight{
public static void main(String[] args)
{
// Create TimeZone object
//Europe/Rome
//Pacific/Pago_Pago
//Africa/Casablanca
String TimezoneToTest = "Africa/Casablanca";
System.out.println("Time Zone = " + TimezoneToTest);
TimeZone obj = TimeZone.getTimeZone(TimezoneToTest);
TimeZone.setDefault(TimeZone.getTimeZone(TimezoneToTest)); //to avoid confusion
// Checking day light time
// and displaying the result
System.out.println("Supports Day light Savings time = "
+ obj.useDaylightTime());
String pattern = "yyyy-MM-dd";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
try{
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(TimezoneToTest));
Date checkdate = simpleDateFormat.parse("2019-05-20");
System.out.println("Date " + checkdate.toString()+ " is currently in DST "+ obj.inDaylightTime(checkdate));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("Time zone name " +obj.getDisplayName());
System.out.println("Time zone ID " + obj.getID());
}
}

Morocco now on DST permanently
As of October 26, 2018, Morocco switched to DST permanently†.
The Morocco government gave only 2 days notice(!), in Decree 2.18.855. Apparently the government intends to stop all clock-shifting, with no more changes for DST nor for Ramadan. This decree means an offset of +01:00 year-round.
This decree also means Morocco is no longer “on DST”. The new-normal is an offset one hour ahead of UTC, whereas in the old days the offset was normally at UTC (an offset of zero hours-minutes-seconds). So notice in the code below that calling ZoneRules::isDaylightSavings returns false nowadays (early 2020).
See Wikipedia for details: Daylight saving time in Morocco.
†When I say “permanently”, take that with a grain of salt. Politicians around the world have shown a penchant for frequently changing the offset of their respective time zone(s). This "permanently on DST" is only the latest fad to have caught the fancy of politicians. Always expect further changes.
Avoid legacy date-time classes
You are using terrible date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310. There is no longer any reason to use those awful legacy classes.
java.time
Specify your intended time zone.
ZoneId zCasablanca = ZoneId.of( "Africa/Casablanca" ) ;
Fetch the zone rules.
ZoneRules rulesCasablanca = zCasablanca.getRules() ;
Interrogate the rules that apply for a specific moment in that zone.
ZoneOffset offset = rulesCasablanca.getOffset( Instant.now() ) ;
boolean isDst = rules.isDaylightSavings( instant ) ;
Or collapse that to a single line.
ZoneOffset offset = ZoneId.of( "Africa/Casablanca" ).getRules().getOffset( Instant.now() ) ;
Verify your version of Java.
System.out.println( "Java vendor and version:" ) ;
System.out.println( " " + System.getProperty("java.vendor") ) ;
System.out.println( " " + Runtime.version() ) ;
String tzdataVersion =
java.time.zone.ZoneRulesProvider
.getVersions("UTC")
.lastEntry()
.getKey()
;
System.out.println( "tzdata: " + tzdataVersion ) ;
System.out.println( "" ) ;
See this code run live at IdeOne.com.
Java vendor and version:
Oracle Corporation
12.0.1+12
tzdata: 2018g
offset.toString(): +01:00
isDst: false
Specific date
Let's try your specific date.
LocalDate localDate = LocalDate.parse( "2019-05-20" ) ;
ZonedDateTime zdt = localDate.atStartOfDay( z ) ;
System.out.println( "zdt.toString(): " + zdt ) ;
System.out.println(
"offset: " + rules.getOffset( zdt.toInstant() ) +
" | is in DST: " + rules.isDaylightSavings( zdt.toInstant() )
);
zdt.toString(): 2019-05-20T00:00+01:00[Africa/Casablanca]
offset: +01:00 | is in DST: false
tzdata
Oracle lists the tzdata files built into Java runtimes.
That list shows that the Morocco switch to permanent DST was accounted for in tzdata2018g. That tzdata file was bundled with Java versions 11.0.2, 8u201, and 7u211. At least Oracle bundled it, while I assume the OpenJDK project did so as well (I did not verify).
Morocco switches to permanent +01 on 2018-10-27.
Morocco switches from +00/+01 to permanent +01 effective 2018-10-27, so its clocks will not fall back on 2018-10-28 as previously scheduled.
To get the version of the tzdata data file in use by your JVM, see this Answer on the Question, Java - find tzdata version in use regardless of JRE version.
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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Related

Past date increased by one hour when converted to Europe/Moscow timezone

Could some one explain why this past date getting increased by one hour , when I convert it to Moscow Timezone ?
I'm using JDK 1.6.0_12 version. .
2011-04-02T11:39:46+0300 --> Sat Apr 02 12:39:46 MSK 2011 // 11:39 --> 12:39
My current system time-zone is "Europe/Moscow" UTC+3 .
Also please note that this past date is in DST(Daylight Saving ) time-zone period UTC+4 , earlier used in Russia.
There was a legislative change of Russian time-zone definitions in October 2014 . Since then Russia uses UTC+3 all through out a year .
I already checked
this old post of 2014 . But I think this issue looks different.
Our developers expect that every past date (like "2011-04-02T11:39:46+0300" and which is in DST period ), should contain current time zone offset value i.e +0300 , not +0400 . And they think JRE is converting it incorrectly to UTC+4 , though "Default Time Zone Offset" shows +3 here . Is this way of handling time-zone offset value for past dates correct?
Same output is given on JRE 1.8 , which I think is an updated version ,there shouldn't be any issue in TZ definition in JRE 1.8.
Thanks in Advance !
Java Code:
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Date;
public class HelloWorld{
public static void main(String []args)
{
String dateInString = "2011-04-02T11:39:46+0300";
System.out.println(dateInString);
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date = dateFormat.parse(dateInString);
System.out.println(date);
} catch (Exception e) {
System.out.println(e);
}
final TimeZone tzone = TimeZone.getDefault();
System.out.println("Default Time Zone ID - " + tzone.getID());
System.out.println("Default Time Zone Offset - (" + (tzone.getRawOffset() / 60 / 60 / 1000) + ") hour.");
}
}
Output :
2011-04-02T11:39:46+0300
Sat Apr 02 12:39:46 MSK 2011
Default Time Zone ID - Europe/Moscow
Default Time Zone Offset - (3) hour.
12:39 is the correct time
You are getting the correct result. In your string, 2011-04-02T11:39:46+0300, the trailing +0300 is an offset from UTC. So the point in time is the same as 2011-04-02T08:39:46+00:00 (UTC). As you say yourself, Moscow was at UTC offset +04:00 from 27 March 2011 to 26 October 2014. So to get the correct time for Moscow Java needs to add 1 hour to the hour in the string. Or 4 hours to the UTC hour of 08:39:46. In any case the time in Moscow was 12:39:46 at this point in time.
Or to answer your question:
… why this past date getting increased by one hour , when I convert it
to Moscow Timezone ?
Because Moscow on that date was 1 hour ahead of the time in the string.
java.time
That said I agree with those who recommend java.time, the modern Java date and time API, for the job. SimpleDateFormat is a notorious troublemaker of a class, and Date and TimeZone are poorly and confusingly designed too. All are long outdated. The modern API is so much nicer to work with.
For example:
ZoneId zone = ZoneId.of("Europe/Moscow");
ZonedDateTime zdt = ZonedDateTime.of(2011, 4, 2, 11, 39, 46, 0, zone);
System.out.println(zdt);
Output:
2011-04-02T11:39:46+04:00[Europe/Moscow]
You can also see from the output that Java knows that Moscow was at offset +04:00 back then.
Your question very well illustrates why java.time (opposite the old TimeZone class) makes the distinction between a time zone and an offset. A time zone includes all historic, the present and all known future offsets from UTC. This is what you need to represent historic times in Moscow correctly. In java.time a time zone is identified by a ZoneId object and obeys a ZoneRules object (most often we need not concern ourselves with the latter and can just trust Java to make the right conversions). A UTC offset is represented by a ZoneOffset object.
Question: how could I use java.time with Java 1.6?
This is your lucky day. java.time exactly requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Time Changes in Moscow Over the Years
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Both modern java date/time api and legacy one (that is used in jdk1.6) rely on system unix time and the tzdata file bundled with the JRE. Looks like the developers are right and your java is using a very old one version of tzdata and your developers are right.
Also, the tzdata keeps information about legal changes and if you are trying to convert date/time in the past, it will apply conversion rules that were relevant at that time.
Regarding JDK 1.8: there was an update to Russian timezone information in 8u101, so you should use at least 8u101 for a better timezone conversion.
The best decision for you would be to use modern java or update your JREs tzdata manually if you really need to use an old one.
You need to set time-zone to SimpleDateFormat as shown below:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String dateInString = "2011-04-02T11:39:46+0300";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));// Set time-zone
Date date = dateFormat.parse(dateInString);
System.out.println(dateFormat.format(date));
}
}
Output:
2011-04-02T12:39:46+0400
Note that java.util.Date does not have time-zone information. It's simply the number of milliseconds from the standard Java epoch of 1970-01-01T00:00:00Z where Z stands for UTC (0 hour offset), also known as Zulu time-zone. At any given moment, you will get the same number of milliseconds on the JVMs sitting in any part of the word. When you try to print an object of java.util.Date, the date-time string for the JVM's time-zone is calculated from this milliseconds value and the same is displayed. If you want to get the date-time String in a specific time-zone, you need to set it explicitly to the SimpleDateFormat and use the same to format the java.util.Date.

Java time different from OS time

When I print date in Unix, it show the UTC time
[app#host ~]$ date
Thu Sep 6 21:16:07 UTC 2018
When I print the date from Java on the same machine
public static void main(String[] args) {
System.out.println("date=" + new Date());
System.out.println("date from mills=" + new Date(System.currentTimeMillis()));
System.out.println(TimeZone.getDefault().getDisplayName());
Instant instant = Instant.now();
System.out.println("instant=" + instant);
System.out.println("instant from mills=" + new Date(instant.toEpochMilli()));
}
It prints PST time
[app#host ~]$ java TimeTest
date=Thu Sep 06 14:17:09 PDT 2018
date from mills=Thu Sep 06 14:17:09 PDT 2018
Pacific Standard Time
instant=2018-09-06T21:17:09.030Z
instant from mills=Thu Sep 06 14:17:09 PDT 2018
How does Java get the PST timezone?
Also, the logback file rotation happens at UTC time and times printed in the log file show PST time.
tl;dr
Use only java.time classes.
Never use Date class.
Use UTC when logging.
Instant.now().toString()
2018-01-23T01:23:45.123456Z
Details
This has been addressed many times already on Stack Overflow.
The terrible old legacy date-time classes are rife with poor design choices. Among those poor choices is the Date::toString method’s behavior of dynamically applying the JVM’s current default time zone while generating the string. Well-intentioned but misleading as a java.util.Date, like a java.time.Instant, represents a moment in UTC.
On September 6 of this year, 2 PM on west coast of much of North America is simultaneously 9 PM in UTC, with an offset-from-UTC of seven hours behind UTC during Daylight Saving Time (DST). Same moment, same point on the timeline, different wall-clock time.
Why PDT?
Why PDT, Pacific Daylight Saving Time, in particular? Your JVM always has a current default time zone. Apparently your JVM is set to a current default of a zone such as America/Los_Angeles (PDT is not a real time zone).
How that default gets set depends on your JVM implementation and your settings. Usually a JVM on launch picks up on the host operating-system’s current default zone. You can pass arguments to the launch of the JVM to specify a zone rather than pick up the host OS’ default.
After launch, any code in any thread of any app within the JVM can, at any moment, change the current default time zone with a call to TimeZone.setDefault to affect immediately all other code in that JVM.
This means you should never rely on the current default zone for anything critical as its value is out of your control as a programmer. Always specify your desired/expected time zone explicitly. Even when you want to use the current default, make an explicit call to ZoneId.systemDefault.
Bonus tip: Ditto for Locale. Always a current default. But specify explicitly rather than rely implicitly on default.
Using java.time
Never use the legacy date-classes. Use only java.time classes.
When logging, always use UTC. Render text in standard ISO 8601 format as seen in Instant::toString.
Instant instant = Instant.now() ;
If you want to view that moment in the wall-clock time used by the people of a particular region, apply a time zone (ZoneId) to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Simple Java String to java.util.Date conversion adds unwanted daylight saving

This is my program snippet
import java.lang.Math;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class Main
{
public static void main(String[] args)
{
String dateTime = "2017-03-12 02:46:00";
// convert string to java.util.Date
try {
SimpleDateFormat e = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = e.parse(dateTime);
System.out.println(d);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
This is the output of that program
Sun Mar 12 03:46:00 PDT 2017
Expected Output
Sun Mar 12 02:46:00 PDT/PST 2017
Apparently, it is adding daylight saving time which occurs on PST at 2017-03-12 02:00:00
Few things I am bounded.
I cannot change server default timezone or anything specific to JVM
I must return back java.util.Date as final value.
Edit:
To some comment pointing me out how java.util.Date only stores long timestamp. Can you please give me a way where this function works
java.util.Date convertStringToDate(String str) {
// code to convert String to Date
}
convertStringToDate("2017-03-12 02:46:00");
should give me 2017-03-12 02:46:00 value in Date class? I don't care about what timezone it provides. It should have that value, whatever timezone it is while printing. Again my JVM is in PST.
Use java.time, not legacy date-time classes
You are using troublesome old date-time classes such as java.util.Date that are now legacy, supplanted by the java.time classes.
LocalDateTime
2016-03-12 02:46:00 value …I don't care about what timezone it provides. It should have that value, whatever timezone it is…
If you truly want to represent that date and time-of-day without regard for time zone, use the LocalDateTime class. This class purposely ignores time zone.
To parse, adjust your input string to comply with the ISO 8601 standard formats used by the java.time classes for parsing/generating strings.
String input = "2016-03-12 02:46:00".replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( input );
But beware: By ignoring time zone you lose the meaning of this date+time. Without the context of a time zone, we do not know if you mean the 2 AM in Auckland NZ, or 2 AM in Kolkata India (some hours later), or 2 AM in Paris France (more hours later), or 2 AM in Montréal Québec (still more hours later). A LocalDateTime is a rough idea about possible moments, but is not actually a point on the timeline.
ZonedDateTime
This is the output of that program Sun Mar 12 03:46:00 PDT 2017
Expected Output Sun Mar 12 02:46:00 PDT/PST 2017
Now you contradict yourself.
By including the PDT or PST with your expected output, you mean a specific moment on the timeline perceived through the lens of a particular region’s wall-clock time. This contradicts your statement that you want "2016-03-12 02:46:00" regardless of time zone. It is crucial that you understand this distinction to properly handle date-time work.
If indeed the intent of the string 2016-03-12 02:46:00 is to represent a moment in the wall-clock time of the left coast of north America (as I guess you meant by PDT), then we must parse that string firstly as a LocalDateTime as it lacks any indicator of time zone, but then immediately adjust it into a time zone to get a ZonedDateTime object.
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 or PDT or PST as they are not true time zones, not standardized, and not even unique(!).
Here I arbitrarily chose America/Los_Angeles as the time zone, as your Question does not mention a specific time zone, only “PDT”.
String input = "2017-03-12 02:46:00".replace( " " , "T" );
LocalDateTime ldt = LocalDateTime.parse( input );
ZoneId z = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = ldt.atZone( z );
But it just so happens that March 12 of 2017 has an anomaly. That is the day when the craziness known as Daylight Saving Time (DST) kicks in. The clocks in much of the left coast of north America at 2 AM jump to 3 AM. There is no two o’clock hour. The day is 23 hours long rather than the usual 24 hours. So your request for 2:46 is asking for a nonexistent moment, an invalid value. The design choice in java.time to resolve this conundrum is to jump forward, following the "Spring Forward" of DST. The result is in the 3 AM hour, 03:46.
See this code run live in IdeOne.com.
input: 2017-03-12T02:46:00
ldt.toString(): 2017-03-12T02:46
zdt.toString(): 2017-03-12T03:46-07:00[America/Los_Angeles]
Note the 2 AM hour becomes the 3 AM hour in that output.
A reasonable person could make arguments for a different design choice in handling this anomaly, such as throwing an Exception. But this is how java.time works. Study the class doc and be sure you understand the behavior on this important topic.
If you want to detect such an anomaly, call toLocalDateTime on the ZonedDateTime object, and compare to the first LocalDateTime. With no anomaly, the pair of LocalDateTime objects will be equal; with an anomaly they will not be equal.
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 ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
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.

Does Java 8's new Java Date Time API take care of DST?

I am thinking of using the new java 8 Date Time API. I googled a bit and found jodaTime as good choice for java but still kind of interested to see how this new API works.
I am storing all time in UTC values in my datastore and will be converting them to Local Time Zone specific value based on user's timezone. I can find many articles showing how to use new Java Date Time API. However I am not sure if the API will take care of DST changes ?
Or do we have any better way of handling Date ?
I am just learning the new Date API , so thought of hearing your thoughts on handling the DateTime and displaying it on the basis of Users TimeZone.
It depends on which class you use:
Instant is an instantaneous point on the global time-line (UTC), and is unrelated to time-zone.
LocalDate and LocalDateTime have no concept of time-zone, but calling now() will of course give you your correct time.
OffsetDateTime has a time-zone, but doesn't support Daylight Savings Time.
ZonedDateTime has full time-zone support.
Converting between them usually requires a time-zone, so to answer your question:
Yes, Java 8 Date/Time can take care of DST, if you use it right.
The Answer by Andreas is spot-on correct.
Example Code
Let's test it with some code. DST in the United States & Canada expires this year at 02:00 on November 1, 2015.
Let‘s start with 1 AM in “local” date-time, meaning not tied to the timeline and ignoring the issue of time zones. Add an hour, and we get 2 AM. Makes sense.
LocalDateTime localDateTime = LocalDateTime.of( 2015 , Month.NOVEMBER , 1 , 1 , 0 ); // 1 AM anywhere. Not tied the timeline nor to any time zone.
LocalDateTime localDateTimeOneHourLater = localDateTime.plusHours( 1 ); // 2 AM anywhere, in no particular time zone, ignoring DST.
Next we get specific, with a particular time zone. We take that 1 AM anywhere and put it into the time zone of America/Los_Angeles (west coast of United States).
ZoneId zoneId_LosAngeles = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime before = localDateTime.atZone( zoneId_LosAngeles ); // Assign a time zone, tying this vague date-time idea/generality to an actual moment on the time line.
Now add an hour, and see what we get. If DST is ignored, we’ll get 2 AM. If DST is respected, we’ll get 1 AM… when reaching 2 AM the wall-clock time jumps back to 1 AM but with a new offset-from-UTC. This is colloquially known as "fall back" in the fall (autumn).
ZonedDateTime after = before.plusHours( 1 ); // 2 AM? Nope, 1 AM because DST Daylight Saving Time expires at 2 AM Nov 1, 2015.
Dump to console.
System.out.println( "localDateTime : " + localDateTime );
System.out.println( "localDateTimeOneHourLater : " + localDateTimeOneHourLater );
System.out.println( "before : " + before );
System.out.println( "after : " + after );
When run, we get this output. Without a time zone, 1 AM + 1 hour = 2 AM. Remember these are "local" date-time values, not UTC. They represent only the vague idea of a date-time, not an actual moment on the timeline.
localDateTime : 2015-11-01T01:00
localDateTimeOneHourLater : 2015-11-01T02:00
But with time zones applied on the day DST expires, we get different results. Note how the time-of-day remains 01:00 but the offset-from-UTC changes from -07:00 to -08:00.
before : 2015-11-01T01:00-07:00[America/Los_Angeles]
after : 2015-11-01T01:00-08:00[America/Los_Angeles]
Perhaps this would more clear and easier to verify if we adjust into UTC. We can do that simply by accessing the before and after objects as Instant objects. The System.out.println then implicitly calls the toString method.
System.out.println( "before.toInstant : " + before.toInstant() );
System.out.println( "after.toInstant : " + after.toInstant() );
When run.
before.toInstant : 2015-11-01T08:00:00Z
after.toInstant : 2015-11-01T09:00:00Z
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.
Yes, the Java API will take DST changes into account.
This tutorial explains quite well how to convert dates between timezones and how to choose the right class to represent a date:
https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html
You can also look at this class which represents the rules for each zone:
http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html
In particular, this method can tell you if a particular instant is in daylight savings:
http://docs.oracle.com/javase/8/docs/api/java/time/zone/ZoneRules.html#isDaylightSavings-java.time.Instant-

Algorithm to determine Daylight Saving Time of a date?

Originally I am looking for a solution in Actionscript. The point of this question is the algorithm, which detects the exact Minute, when a clock has to switch the Daylight Saving Time.
So for example between the 25th and the 31th of October we have to check, if the actual date is a sunday, it is before or after 2 o'clock...
There is no real algorithm for dealing with Daylight Saving Time. Basically every country can decide for themselves when -and if- DST starts and ends. The only thing we can do as developers is using some sort of table to look it up. Most computer languages integrate such a table in the language.
In Java you could use the inDaylightTime method of the TimeZone class. If you want to know the exact date and time when DST starts or ends in a certain year, I would recommend to use Joda Time. I can't see a clean way of finding this out using just the standard libraries.
The following program is an example: (Note that it could give unexpected results if a certain time zone does not have DST for a certain year)
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
public class App {
public static void main(String[] args) {
DateTimeZone dtz = DateTimeZone.forID("Europe/Amsterdam");
System.out.println(startDST(dtz, 2008));
System.out.println(endDST(dtz, 2008));
}
public static DateTime startDST(DateTimeZone zone, int year) {
return new DateTime(zone.nextTransition(new DateTime(year, 1, 1, 0, 0, 0, 0, zone).getMillis()));
}
public static DateTime endDST(DateTimeZone zone, int year) {
return new DateTime(zone.previousTransition(new DateTime(year + 1, 1, 1, 0, 0, 0, 0, zone).getMillis()));
}
}
The Answer by Richters is correct and should be accepted.
As Richters noted, there is no logic to Daylight Saving Time (DST) or other anomalies. Politicians arbitrarily redefine the offset-from-UTC used in their time zones. They make these changes often with little forewarning, or even no warning at all as North Korea did a few weeks ago.
java.time
Here are some further thoughts, and example code using the modern java.time classes that succeeded the Joda-Time classes shown in his Answer.
These changes are tracked in a list maintained by ICANN, known as tzdata, formerly known as the Olson Database. Your Java implementation, host operating system, and database system likely all have their own copies of this data which must be replaced as needed when changes are mode to zones you care about. There is no logic to these changes, so there is no way to predict the changes programmatically. Your code must call upon a fresh copy of tzdata.
So for example between the 25th and the 31th of October we have to check, if the actual date is a sunday, it is before or after 2 o'clock...
Actually, you need not determine the point of the cut-over. A good date-time library handles that for you automatically.
Java has the best such library, the industry-leading java.time classes. When you ask for a time-of-day on a certain date in a certain region (time zone), if that time-of-day is no valid an adjustment is made automatically. Read the documentation for the ZonedDateTime to understand the algorithm used in that adjustment.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2018 , Month.MARCH , 11 ); // 2018-03-11.
LocalTime lt = LocalTime.of( 2 , 0 ); // 2 AM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
Notice the result is 3 AM rather than the 2 AM requested. There was no 2 AM on that date in that zone. So java.time adjusted to 3 AM as the clock “Springs ahead” an hour.
zdt.toString(): 2018-03-11T03:00-04:00[America/Montreal]
If you feel the need to investigate the rules defined for a time zone, use the ZoneRules class.
Get the amount of DST shift used in the present moment.
Duration d = z.getRules().getDaylightSavings​( Instant.now() ) ;
Get the next planned change, represented as a ZoneOffsetTransition object.
ZoneId z = ZoneId.of( "America/Montreal" );
ZoneOffsetTransition t = z.getRules().nextTransition( Instant.now() );
String output = "For zone: " + z + ", on " + t.getDateTimeBefore() + " duration change: " + t.getDuration() + " to " + t.getDateTimeAfter();
For zone: America/Montreal, on 2018-11-04T02:00 duration change: PT-1H to 2018-11-04T01:00
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(!).
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.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, 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 Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
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.

Categories