Algorithm to determine Daylight Saving Time of a date? - java

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.

Related

Rrule Until tag data value

I'm working on a project which takes rrule to generate next occurrences. But I'm not able to understand what i need to put in UNTIL tag of rrule.
String str="RRULE:FREQ=MONTHLY;UNTIL=20190625T000000Z;INTERVAL=2;";
Idk how to convert date into "20190625T000000Z".I'm using rfc 2445 java library. If user enters the date as a string for example :25/06/2019......i need to set this value in UNTIL tag as shown above. If I set the default value in UNTIL then it works but not when i make it user friendly.. I'm taking all the values from user as start date, end date, interval, Byday,Until... But idk what value to set in UNTIL.
If someone can help.. Thanks in advance.
Parsing basic ISO 8601 format
Your input 20190625T000000Z is the “basic” variation of standard ISO 8601 format to represent a moment in UTC. The word “basic” means minimizing the use of delimiters (I do not recommend this, as it makes the string less readable by humans).
Defining a formatting pattern to match input.
String input = "20190625T000000Z";
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssX" );
OffsetDateTime odt = OffsetDateTime.parse( input , f );
Dump to console.
System.out.println("odt.toString(): " + odt);
See this code run live at IdeOne.com.
odt.toString(): 2019-06-25T00:00Z
Translating date to moment
If user enters the date as a string for example :25/06/2019......i need to set this value in UNTIL tag as shown above
First, parse that input string into a LocalDate, representing a date-only value, without time-of-day and without time zone.
DateTimeFormatter fDateOnly = DateTimeFormatter.ofPattern( "dd/MM/uuuu" );
LocalDate ld = LocalDate.parse( "25/06/2019" , fDateOnly );
ld.toString(): 2019-06-25
As for translating that date into a moment (a date with time-of-day in a zone or offset-from-UTC), that is trickier than it sounds intuitively.
A date such as the 25th of June 2019 represents an entire day. And a theoretical date at that. The moments when a day begins and ends varies around the globe by time zone. A new day begins much earlier in Tokyo Japan than in Paris France, and even later in Montréal Québec.
Another issue is that the day does not always begin at 00:00:00. Because of anomalies such as Daylight Saving Time (DST), the first moment of a day on some dates in some zones may be something like 01:00:00. Let the java.time classes determine first moment.
ZoneId z = ZoneId.of( "Africa/Tunis" );
ZonedDateTime zdt = ld.atStartOfDay( z );
zdt.toString(): 2019-06-25T00:00+01:00[Africa/Tunis]
That ZonedDateTime object represents a specific moment. But it uses the wall-clock time adopted by the people of a particular region (a time zone). Your goal is a moment in UTC. Fortunately, we can adjust from the zone to UTC by converting to an OffsetDateTime (a date and time with a context of offset-from-UTC rather than a time zone). We can specify UTC (an offset of zero) by the ZoneOffset.UTC constant.
OffsetDateTime odt = zdt.toOffsetDateTime().withOffsetSameInstant( ZoneOffset.UTC );
odt.toString(): 2019-06-24T23:00Z
Note how 00:00 on the 25th in Tunisia is 11 PM “yesterday” the 24th in UTC. Same moment, same simultaneous point on the timeline, but two different wall-clock times.
Lastly, we need a string in that “basic” ISO 8601 format. Use the same formatter we defined above.
DateTimeFormatter fIso8601DateTimeBasic = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssX" );
String output = odt.format( fIso8601DateTimeBasic );
output: 20190624T230000Z
See this code run live at IdeOne.com.
Just what is the difference between a time zone and an offset-from-UTC? An offset is merely a number of hours-minutes-seconds. Nothing more, nothing less, just a number (well, three numbers). A time zone is much more. A time zone is a history of past, present, and future changes to the offset used by the people of a particular region. For example, in most of North America, the offset changes twice a year, springing ahead an hour and then falling back an hour (the lunacy of Daylight Saving Time (DST)).
Tip: Date-time handling is surprisingly tricky and slippery. If you are working with calendars and the iCalendar spec for data exchange, I suggest you take a long while to study the concepts and practice with the industry-leading java.time classes.
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.

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-

Date Time Conversion based on the TimeZone Java/Groovy

I am in MST and I want my Date in PST. I set the timeZone that I want.
Now if i do c.getTime() I always get my server time.
Instead I want Pacific Date time. Please help
How to get the date time Object in the specified timezone.
Calendar c= Calendar.getInstance();
TimeZone timezone= TimeZone.getTimeZone("PST");
c.setTimeZone(timezone)
Or, use JodaTime
#Grab( 'joda-time:joda-time:2.3' )
import org.joda.time.*
def now = new DateTime()
println now.withZone( DateTimeZone.forTimeZone( TimeZone.getTimeZone( "PST" ) ) )
​TimeZone.setDefault(TimeZone.getTimeZone('PST'))
println new Date() //PST time
You can set the default timezone to PST/MST according to your need and then get the date. I would do this in a test method, if possible.
UPDATE: The Joda-Time project has been succeeded by the java.time classes. See this other Answer.
(a) Use Joda-Time (or new JSR 310 built into Java 8). Don't even think about using the notoriously bad java.util.Date/Calendar.
(b) Your question is not clear. Your comments on answers talk about comparing, but you say nothing about comparing in your question.
(c) Avoid the use of 3-letter time zone abbreviations. Read note of deprecation in Joda-Time doc for TimeZone class.
(d) Avoid default time zone. Say what you mean. The time zone of your computer can change intentionally or not.
(e) Search StackOverflow for 'joda' for lots of code snippets and examples.
(f) Here's some Joda-Time example code to get you started.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
// Specify your time zone rather than rely on default.
org.joda.time.DateTimeZone californiaTimeZone = org.joda.time.DateTimeZone.forID( "America/Los_Angeles" );
org.joda.time.DateTimeZone denverTimeZone = org.joda.time.DateTimeZone.forID( "America/Denver" );
org.joda.time.DateTime nowDenver = new org.joda.time.DateTime( denverTimeZone );
org.joda.time.DateTime nowCalifornia = nowDenver.toDateTime( californiaTimeZone );
// Same moment in the Universe’s timeline, but presented in the local context.
System.out.println( "nowDenver: " + nowDenver );
System.out.println( "nowCalifornia: " + nowCalifornia );
When run…
nowDenver: 2013-11-21T18:12:49.372-07:00
nowCalifornia: 2013-11-21T17:12:49.372-08:00
About Joda-Time…
// Joda-Time - The popular alternative to Sun/Oracle's notoriously bad date, time, and calendar classes bundled with Java 7 and earlier.
// http://www.joda.org/joda-time/
// Joda-Time will become outmoded by the JSR 310 Date and Time API introduced in Java 8.
// JSR 310 was inspired by Joda-Time but is not directly based on it.
// http://jcp.org/en/jsr/detail?id=310
// By default, Joda-Time produces strings in the standard ISO 8601 format.
// https://en.wikipedia.org/wiki/ISO_8601
// About Daylight Saving Time (DST): https://en.wikipedia.org/wiki/Daylight_saving_time
// Time Zone list: http://joda-time.sourceforge.net/timezones.html
tl;dr
ZonedDateTime
.now(
ZoneId.of( "America/Los_Angeles" )
)
See this code run live at IdeOne.com. (Be aware the system clock on that site seems to be about a half-hour slow today.)
zdt.toString(): 2019-07-27T12:29:42.029531-07:00[America/Los_Angeles]
java.time
The modern approach uses the java.time classes built into Java 8 and later, defined in JSR 310.
I am in MST and I want my Date in PST. I set the timeZone that I want.
Never depend on the current default time zone of the JVM at runtime. As a programmer, you have no control over that default. So the results of your code may vary unexpectedly.
Always specify the optional time zone arguments to date-time methods.
Now if i do c.getTime() I always get my server time.
Learn to think not of client-time or server-time, but rather UTC. Most of your business logic, data storage, data exchange, and logging should be done in UTC. Think of UTC as the One True Time™, and all other offsets/zones are but mere variations.
For UTC, use Instant.
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Generate text representing that moment in standard ISO 8601 format.
String output = instant.toString() ;
Instead I want Pacific Date time. Please help How to get the date time Object in the specified timezone.
None of your terms (Pacific, MST, or PST) are true time zones.
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
To adjust from UTC to a time zone, apply a ZoneId to get a ZonedDateTime.
ZoneId z = ZoneId.of( "America/Edmonton" ) ; // https://time.is/Edmonton
ZonedDateTime zdt = instant.atZone( z ) ;
And try one of the time zones on the west coast of North America.
ZoneId z = ZoneId.of( "America/Los_Angeles" ) ; // https://time.is/Los_Angeles
ZonedDateTime zdt = instant.atZone( z ) ;
To generate strings in formats other than ISO 8601, use the DateTimeFormatter class. Search Stack Overflow as this has been covered many many times already.
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.
The Java Date object do not have a timezone -- it just represents a point in time.
If you would like to format a date into a timezone, you can set it in the DateFormat class. For example:
Date date = new Date ();
DateFormat df = DateFormat.getDateTimeInstance();
df.setTimeZone(TimeZone.getTimeZone("PST"));
System.out.println(df.format(date));
df.setTimeZone(TimeZone.getTimeZone("EST"));
System.out.println(df.format(date));
will display a time in PST, then a time in EST.
I had to a similar issue myself recently, and setting the timezone to a locale worked better for me (i.e. not EST/EDT, but America/New_York). I tried EST then tried to do the daylight savings time offset stuff for EDT and this turned out to be a heck of lot easier. Set your timezone to whatever you want it to be then make use of the Date object to create a new date and it will for that timezone. Then you can use the format method to take a timestamp however you please.
TimeZone.setDefault(TimeZone.getTimeZone("America/New_York"));
Date date = new Date();
timeStamp = date.format('yyyy-MM-dd HH:mm:ss.SSSZ');
System.out.println(timeStamp);
Returns
"2019-07-25 17:09:23:626-0400"

Assigning java.sql.Timestamp with daylight savings time

I am having trouble understanding java.sql.timestamp.
If I run the java deprecated constructors:
java.sql.Timestamp(106,2,26,1,0,0,0)
java.sql.Timestamp(106,2,26,2,0,0,0)
java.sql.Timestamp(106,2,26,3,0,0,0) //<-- Separated by one hour
I get:
2006-03-26 01:00:00.0
2006-03-26 03:00:00.0
2006-03-26 03:00:00.0 //<--These last two are the same
Daylight savings occurs (at least in my country) around these times. But the dates before and after the time are not moved. Why are two separate hours returning the same time?
I would like to get the timestamp just as my input, How can I force this?
Don't use this deprecated constructor, which is deprecated precisely because it uses the default time zone.
Use a Calendar (or a DateFormat) with the appropriate time zone (CET), set the fields of the calendar (or parse a string containing the date you want to insert), get the milliseconds from the calendar/date, and construct a Timestamp from the milliseconds.
Using System.currentTimeMillis(); gives you Greenwich Mean Time which is unaffected by daylight savings, leap seconds and other surprise adjustments to the date.
long now = System.currentTimeMillis();
Or Specify the timezone manually:
long ms = Calendar.getInstance(TimeZone.getTimeZone("GMT")).getTimeInMillis();
Source: Get GMT Time in Java
tl;dr
The Daylight Saving Time (DST) cut-over means the 2 AM hour never existed. So you are giving invalid inputs.
The ZonedDateTime class tries to help by adjusting your time-of-day input, jumping to 3 AM just as the clock jumped an hour than morning when striking 02:00.
ZonedDateTime
.of( 2006 , 3 , 26 , 2 , 0 , 0 , 0 , ZoneId.of( "Africa/Tunis" ) )
.toString()
2006-03-26T03:00+02:00[Africa/Tunis]
Avoid legacy date-time classes
java.sql.Timestamp is a terrible class, along with its sibling classes such as java.util.Date and Calendar/GregorianCalendar. Among its many design problems is is messy handling of time zones.
Instead, use only the modern java.time classes.
java.time
For moments (a date, a time-of-day, and a time zone or offset-from-UTC), use one of these classes:
Instant — a moment always in UTC.
OffsetDateTime — a moment with an offset-from-UTC (a number of hours-minutes-seconds) but an unknown time zone
ZonedDateTime — a moment with an assigned time zone.
It sounds like you were intending to use a date-time in your own zone.
ZoneId
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
ZonedDateTime
Specify a time and a date as seen in the wall-clock time used by the people of a particular region (a time zone).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt_1 = ZonedDateTime.of( 2006, 3 , 26 , 1 , 0 , 0 , 0 , z ) ;
ZonedDateTime zdt_2 = ZonedDateTime.of( 2006, 3 , 26 , 2 , 0 , 0 , 0 , z ) ;
ZonedDateTime zdt_3 = ZonedDateTime.of( 2006, 3 , 26 , 3 , 0 , 0 , 0 , z ) ;
System.out.println("zdt_1.toString(): " + zdt_1);
System.out.println("zdt_2.toString(): " + zdt_2);
System.out.println("zdt_3.toString(): " + zdt_3);
zdt_1.toString(): 2006-03-26T01:00+01:00[Africa/Tunis]
zdt_2.toString(): 2006-03-26T03:00+02:00[Africa/Tunis]
zdt_3.toString(): 2006-03-26T03:00+02:00[Africa/Tunis]
Daylight Saving Time (DST)
We see a surprise on the third item, where we ask for 2 AM but get 3 AM back. This is understandable, because of a Daylight Saving Time (DST) cut-over or “Spring ahead”. Starting in 2005, Tunisia adopted DST. Later in 2009 they came to their senses and returned to standard time only.
The 2 AM hour does not exist
So there is no 2 AM on that date in Tunisia. When the clock struck 2 AM, it jumped to 3 AM. The 2 AM hour never existed. That day is only 23-hours long rather than the usual 24 hours long. So our code above asked for an invalid date-time. The ZonedDateTime class, rather than throw an Exception, tries to help us out by adjusting to a valid time-of-day. The JavaDoc for ZonedDateTime.of spells this out:
Obtains an instance of ZonedDateTime from a year, month, day, hour, minute, second, nanosecond and time-zone.
This creates a zoned date-time matching the local date-time of the seven specified fields as closely as possible. Time-zone rules, such as daylight savings, mean that not every local date-time is valid for the specified zone, thus the local date-time may be adjusted.
The local date-time is resolved to a single instant on the time-line. This is achieved by finding a valid offset from UTC/Greenwich for the local date-time as defined by the rules of the zone ID.
In most cases, there is only one valid offset for a local date-time. In the case of an overlap, when clocks are set back, there are two valid offsets. This method uses the earlier offset typically corresponding to "summer".
In the case of a gap, when clocks jump forward, there is no valid offset. Instead, the local date-time is adjusted to be later by the length of the gap. For a typical one hour daylight savings change, the local date-time will be moved one hour later into the offset typically corresponding to "summer".
So the behavior is a feature, not a bug.
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.

Java GregorianCalendar change TimeZone

I'm trying to set HOUR_OF_DAY field and change Timezone of the GregorianCalendar date object.
GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
date.set(Calendar.HOUR_OF_DAY, 23);
//date.get(Calendar.HOUR_OF_DAY);
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
Output:
HOUR: 16
HOUR: 23
For some reason value of HOUR_OF_DAY does not change after setting different timezone. But if I uncomment date.get for HOUR_OF_DAY, everything works exactly as it should
GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
date.set(Calendar.HOUR_OF_DAY, 23);
date.get(Calendar.HOUR_OF_DAY); // uncommenting this line will is changing the output
date.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY));
Output:
HOUR: 16
HOUR: 13
How is this possible? Why .get method is changing object behaviour?
The GregorianCalendar class inherits its get method from Calendar, which has the following side effect:
In lenient mode, all calendar fields are normalized.
This means that the time value and all fields are recomputed when get is called on a Calendar object. This can lead to some unpredictable behavior, particularly when coupled with setTimeZone, which has some documented buggy behavior of its own.
tl;dr
OffsetDateTime.now( ZoneOffset.ofHours( 10 ) ).withHour( 23 )
Avoid legacy date-time classes
The legacy date-time classes including GregorianCalendar are a confusing. awkward, poorly-design mess. Avoid them. Now supplanted by the java.time classes. Specifically, GregorianCalendar is replaced by ZonedDateTime.
Offset-from-UTC
You apparently want a moment with an offset-from-UTC of ten hours ahead of UTC. Define your desired offset.
ZoneOffset offset = ZoneOffset.ofHours( 10 ) ;
offset.toString(): +10:00
Get the current moment as an OffsetDateTime with that offset.
OffsetDateTime odt = OffsetDateTime.now( offset ) ;
odt.toString(): 2018-02-15T16:44:44.216642+10:00
You want to override the hour to be 23.
OffsetDateTime odt23 = odt.withHour( 23 ) ;
odt23.toString(): 2018-02-15T23:44:44.216642+10:00
Time zone
I'm trying to set HOUR_OF_DAY field and change Timezone of the GregorianCalendar date object.
Nope, you are changing the offset-from-UTC, not the time zone.
Always better to use a time zone rather than a mere offset, if you know for certain the intended zone. A time zone is a history of past, present, and future changes to the offset used by the people of a certain region. With a time zone you can always determine the offset, but not vice-versa.
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(!).
ZoneId z = ZoneId.of( "Australia/Brisbane" ) ;
Capture the current moment in a wall-clock time seen by the people of that zone.
ZonedDateTime zdt = ZonedDateTime.now( z ) ;
Override the hour-of-day.
ZonedDateTime zdt23 = zdt.withHour( 23 ) ;
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.
Using a JDBC driver compliant with JDBC 4.2 or later, you may exchange java.time objects directly with your database. No need for strings nor java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java 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 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, 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