How to manually set the Daylight Saving (DST) shift date in Java - java

My country changed the the Daylight Saving shift date from "October 21" to "November 4" and we need to apply this in our back-end.
The appropriate solution is to update the Operating System configuration, but we have restrictions to do so (legacy dependencies). We are looking for a workaround.
Is it possible to use code and change the DST shift date programmatically?
GregorianCalendar gc = new GregorianCalendar();
gc.setTimeInMillis(0);
gc.set(2018, Calendar.OCTOBER, 21, 0, 0, 0);
gc.setTimeZone(TimeZone.getTimeZone("Brazil/East"));
XMLGregorianCalendar xml = DatatypeFactory.newInstance().newXMLGregorianCalendar(gc);
System.out.println("XML Date: " + xml.toString());
Output must be -03:00:
XML Date: 2018-10-21T01:00:00.000-02:00

OS irrelevent
Your operating system configuration is irrelevant. Most Java implementations by default pick up their initial default time zone from the host OS upon launch. But the definition of the time zones is stored within the Java implementation.
Java time zone updater
So you need to update the time zone definitions within your Java implementation. Most implementations use the tz database also known as tzdata.
For the Oracle-branded Java implementation, Oracle provides the Timezone Updater Tool. That landing page has an as-of date of 2018-08, so perhaps your time zone’s changes have been included. But I suggest you investigate more closely to verify.
For other implementations, check with the vendor. They may have provided an updated version of the JVM to include the fresh tzdata. Or perhaps they too provide an updater tool. Or perhaps you can replace the tzdata file manually.
Avoid mangling zone with code
I strongly suggest you avoid trying to make artificial adjustments to the offset yourself in code. You will likely get it wrong. Date-time work in surprisingly tricky and confusing.
But if you insist, firstly avoid the terrible old legacy date-time classes such as GregorianCalendar & Calendar & Date. These were supplanted years ago by JSR 310. If you must interoperate with old code not yet updated to java.time, do your work in the modern classes and then at the end convert via new methods added to the old classes.
Use the modern the java.time classes, specifically:
Instant (for a moment in UTC)
OffsetDateTime (for a moment with an offset-from-UTC of hours-minutes-seconds but no time zone)
ZonedDateTime (for a moment in a particular time zone)
You can search Stack Overflow for many existing examples and explanations using these classes. You should focus on OffsetDateTime, ZoneOffset (rather than ZoneId), and Instant since you must avoid ZonedDateTime if your know your tzdata file to be outdated.
Same moment, different wall-clock time
OffsetDateTime::withOffsetSameInstant​
OffsetDateTime odt = OffsetDateTime.parse( "2018-10-21T01:00:00.000-02:00" ) ;
ZoneOffset offset = ZoneOffset.ofHours( -3 ) ;
OffsetDateTime odt2 = odt.withOffsetSameInstant​( offset ) ; // Same moment, same point on the timeline, different wall-clock time.
odt.toString(): 2018-10-21T01:00-02:00
odt2.toString(): 2018-10-21T00:00-03:00
In that example, both odt and odt2 represent the same simultaneous moment, the same point on the timeline. If you extract an Instant (a value in UTC), your results will be the same moment. Only their wall-clock time is different.
Instant instant1 = odt.toInstant() ; // Adjust to UTC.
Instant instant2 = odt2.toInstant() ;
boolean sameMoment = instant1.equals( instant2 ) ;
instant1.toString(): 2018-10-21T03:00:00Z
instant2.toString(): 2018-10-21T03:00:00Z
sameMoment = true
The Z on the end means UTC, an offset-from-UTC of zero, +00:00. The Z is pronounced “Zulu”. Defined by the ISO 8601 standard.
Different moment, same wall-clock time
OffsetDateTime::withOffsetSameLocal​
In contrast, you may want to force the time-of-day thereby representing a different moment. For that, use withOffsetSameLocal method. Be very aware that you are changing the meaning of data, you are moving to another point on the timeline.
OffsetDateTime differentMomentButSameTimeOfDay = odt. withOffsetSameLocal( offset ) ;
differentMomentButSameTimeOfDay.toString(): 2018-10-21T01:00-03:00
Extract the instant to see we have a different moment.
Instant differentInstant = differentMomentButSameTimeOfDay.toInstant() ;
differentInstant.toString(): 2018-10-21T04:00:00Z
Notice the 4 AM UTC versus 3 AM UTC seen above. This moment here occurs an hour after the moment above. Two different points on the timeline.
Do not attempt this work until you fully comprehend the concept of points on the timeline, and changing between points being entirely different than adjusting offsets. Practice extensively before doing real work. Half-hearted guessing will land you in a world of hurt and headache.
And, as I suggested above, your time would be much better spent installing updated tzdata files rather than hacking these offsets.
Live code
See all the code above run live at IdeOne.com.
Update tzdata everywhere
For best results, you should be updating the tzdata (or equivalent) in all these various places:
Your operating systems
Your JVMs
Your database engines, such as Postgres
Any libraries bundling their own time zone info (ex: Joda-Time)
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. Hibernate 5 & JPA 2.2 support java.time.
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 brought 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 (26+) bundle implementations of the java.time classes.
For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. 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

LocalDateTime.now() wrong hour

I'm using LocalDateTime.now() to get the date and time of system, but the time is with an hour in past.
If the system has 14:52, now() return 13:52.
OS of system is Windows 10.
LocalDateTime is wrong class
Never use LocalDateTime to represent a moment, a specific point on the timeline. Purposely lacking any concept of time zone or offset-from-UTC, this type represents potential moments along the range of about 26-27 hours (range of time zones around the globe).
Current moment
To get the current moment in UTC, use Instant.
Instant instant = Instant.now() ;
To get the current moment as seen in the wall-clock time used by people in a particular region (a time zone), use ZonedDateTime.
I suspect your problem is that your expected time zone was not actually the current default zone when your code ran. In your code you failed to specify a time zone, and so the JVM’s current default time zone was silently applied. You could verify the current default by calling ZoneId.systemDefault().toString().
Relying implicitly on the JVM’s current default time zone is a bad practice in my opinion. Better to always specify your desired/expected time zone explicitly. Always pass the optional ZoneId argument.
ZoneId z = ZoneId.of( "America/Montreal" ) ; // Or get the JVM’s current default time zone: ZoneId.systemDefault()
ZonedDateTime zdt = ZonedDateTime.now( 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.
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. Hibernate 5 & JPA 2.2 support java.time.
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 brought 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 (26+) bundle implementations of the java.time classes.
For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
java.util.TimeZone.setDefault() is the method in java which is used to set the timeZone
in java. It takes TimeZone as input parameter. You can get an object of TimeZone by TimeZone.getTimeZone("id"); There are different id for different time Zone. For example id for me is "Asia/Calcutta" so passing that will return me the TimeZone of my region.
TimeZone tzone = TimeZone.getTimeZone("Asia/Calcutta");
TimeZone.setDefault(tzone);
Above line will change my timezone to calcutta region.

Timestamp.from not heeding timezone from Instant

When I try to convert a ZonedDateTime to a Timestamp everything is fine until I call Timestamp.from() in the following code:
ZonedDateTime currentTimeUTC = ZonedDateTime.now(ZoneOffset.UTC);
currentTimeUTC = currentTimeUTC.minusSeconds(currentTimeUTC.getSecond());
currentTimeUTC = currentTimeUTC.minusNanos(currentTimeUTC.getNano());
return Timestamp.from(currentTimeUTC.toInstant());
ZonedDateTime.now(ZoneOffset.UTC); -> 2018-04-26T12:31Z
currentTimeUTC.toInstant() -> 2018-04-26T12:31:00Z
Timestamp.from(currentTimeUTC.toInstant()) -> 2018-04-26 14:31:00.0
// (with Timezone of Europe/Berlin, which is currently +2)
Why is Timestamp.from() not heeding the timezone set in the instant?
The Instant class doesn't have a timezone, it just has the values of seconds and nanoseconds since unix epoch. A Timestamp also represents that (a count from epoch).
why is the debugger displaying this with a Z behind it?
The problem is in the toString methods:
Instant.toString() converts the seconds and nanoseconds values to the corresponding date/time in UTC - hence the "Z" in the end - and I believe it was made like that for convenience (to make the API more "developer-friendly").
The javadoc for toString says:
A string representation of this instant using ISO-8601 representation.
The format used is the same as DateTimeFormatter.ISO_INSTANT.
And if we take a look at DateTimeFormatter.ISO_INSTANT javadoc:
The ISO instant formatter that formats or parses an instant in UTC, such as '2011-12-03T10:15:30Z'
As debuggers usually uses the toString method to display variables values, that explains why you see the Instant with "Z" in the end, instead of the seconds/nanoseconds values.
On the other hand, Timestamp.toString uses the JVM default timezone to convert the seconds/nanos values to a date/time string.
But the values of both Instant and Timestamp are the same. You can check that by calling the methods Instant.toEpochMilli and Timestamp.getTime, both will return the same value.
Note: instead of calling minusSeconds and minusNanos, you could use the truncatedTo method:
ZonedDateTime currentTimeUTC = ZonedDateTime.now(ZoneOffset.UTC);
currentTimeUTC = currentTimeUTC.truncatedTo(ChronoUnit.MINUTES);
This will set all fields smaller than ChronoUnit.MINUTES (in this case, the seconds and nanoseconds) to zero.
You could also use withSecond(0) and withNano(0), but in this case, I think truncatedTo is better and more straight to the point.
Note2: the java.time API's creator also made a backport for Java 6 and 7, and in the project's github issues you can see a comment about the behaviour of Instant.toString. The relevant part to this question:
If we were really hard line, the toString of an Instant would simply be the number of seconds from 1970-01-01Z. We chose not to do that, and output a more friendly toString to aid developers
That reinforces my view that the toString method was designed like this for convenience and ease to use.
Instant does not hold the Timezone information. It only holds the seconds and nanos.
To when you convert your ZonedDateTime into an Instant the information is lost.
When converting into Timestamp then the Timestamp will hold the default Timezone, which is, in your case, Europe/Berlin.
tl;dr
You are being confused by the unfortunate behavior of Timestamp::toString to apply the JVM’s current default time zone to the objects internal UTC value.
➡ Use Instant, never Timestamp.
A String such as 2018-04-26T12:31Z is in standard ISO 8601 format, with the Z being short for Zulu and meaning UTC.
Your entire block of code can be replaced with:
Instant.now()
…such as:
myPreparedStatement.setObject( … , Instant.now() ) ;
Details
The Answer by wowxts is correct. Instant is always in UTC, as is Timestamp, yet Timestamp::toString applies a time zone. This behavior is one of many poor design choices in those troubled legacy classes.
I'll add some other thoughts.
Use Instant for UTC
ZonedDateTime currentTimeUTC = ZonedDateTime.now(ZoneOffset.UTC);
While technically correct, this line is semantically wrong. If you want to represent a moment in UTC, use Instant class. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now() ; // Capture the current moment in UTC.
Avoid legacy Timestamp class
Timestamp.from(currentTimeUTC.toInstant());
While technically correct, using my suggest above, that would be:
Timestamp.from( instant ); // Convert from modern *java.time* class to troublesome legacy date-time class using new method added to the old class.
Nothing is lost going between Instant and Timestamp, as both represent a moment in UTC with a resolution of nanoseconds. However…
No need to be using java.sql.Timestamp at all! That class is part of the troublesome old date-time classes that are now legacy. They were supplanted entirely by the java.time classes defined by JSR 310. Timestamp is replaced by Instant.
JDBC 4.2
As of JDBC 4.2 and later, you can directly exchange java.time objects with your database.
Insert/Update.
myPreparedStatement.setObject( … , instant ) ;
Retrieval.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
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.

How to maintain "-6" as UTC offset during CDT?

I want to retain CST time always with offset -6, at present I am getting as 2018-03-15T05:08:53-05:00.
But I want to change it as with offset -6 like 2018-03-15T05:08:53-06:00 through out the year.
TimeZone tz= TimeZone.getdefault();
if(tz.inDayLightTime())
{
getCSTDate(cal)
// I would like to change the logic here.
}
public XMLGregorianCalendar getCSTDate(Calendar cal)
{
return XMLGregorianCalendar;
}
my input type : calendar
output : XMLGregorianCalendar
Then don't use a timezone that tracks Daylight Saving Time changes (which is probably the case of yours TimeZone.getDefault()).
If you want a fixed offset, you can do:
TimeZone tz = TimeZone.getTimeZone("GMT-06:00");
Not sure why you want that, because if you're dealing with timezones, you must consider DST effects. And 2018-03-15T05:08:53-06:00 is not the same instant as 2018-03-15T05:08:53-05:00, so changing the offset while keeping all the other fields is usually wrong - as it's not clear why you want that and what you want to achieve, I can't give you more advice on that.
tl;dr
If you want the current moment as seen through a fixed offset-from-UTC, use OffsetDateTime with ZoneOffset.
OffsetDateTime.now(
ZoneOffset.ofHours( -6 )
)
Details
always with offset -6
The Answer by watssu is correct: If you don’t want the effects of Daylight Saving Time (DST), don’t use a time zone that respects DST.
If you always want an offset-from-UTC fixed at six hours behind UTC, use an OffsetDateTime.
ZoneOffset offset = ZoneOffset.ofHours( -6 ) ;
OffsetDateTime odt = OffsetDateTime.now( offset ) ; // Ignores DST, offset is fixed and unchanging.
Be clear that an offset is simply a number hours, minutes, and seconds displacement from UTC. In contrast, a time zone is a history of past, present, and future changes in offset used by the people of a particular region. So generally, you should be using a time zone rather than a mere offset. Your insistence on a fixed offset is likely unwise.
The 3-4 letter abbreviations such as CST are not time zones. They are used by mainstream media to give a rough idea about time zone and indicate if DST is in effect. But they are notstandardized. They are not even unique! For example, CST means Central Standard Time as well as China Standard Time or Cuba Standard Time.
Use real time zones with names in the format of continent/region.
Avoid all the legacy date-time classes such as TimeZone now supplanted by the java.time classes. Specifically, ZoneId.
ZoneId z = ZoneId.of( "America/Chicago" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Respects DST changes in offset.
If your real issue is wanting to detect DST to alter your logic, I suggest you rethink the problem. I suspect you are attacking the wrong issue. But if you insist, you can ask for the offset currently in effect on your ZonedDateTime, and you can ask a ZoneId if DST is in effect for any particular moment via the ZoneRules class.
ZoneOffset offsetInEffect = zdt.getOffset() ;
And…
Boolean isDstInEffect = zdt.getZone.getRules().isDaylightSavings( zdt.toInstant() ) ;
On that last line, note the incorrect use of plural with s on isDaylightSavings.
The XMLGregorianCalendar class is part of the troublesome old legacy date-time classes, now supplanted by the java.time classes, specifically ZonedDateTime. To inter-operate with old code not yet updated to java.time, convert to the modern class via the legacy class GregorianCalendar.
ZonedDateTime zdt = myXmlCal.toGregorianCalendar().toZonedDateTime() ;
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, 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.

What is wrong with java zoneinfo?

I have a Europe/Moscow timezone in my Mageia 4.
The code like this
System.out.println(new java.util.Date());
System.out.println(System.getProperty("user.timezone"));
returns
Fri Oct 24 13:43:22 GMT+03:00 2014
GMT+03:00
if I set the system date in 24.10.2014
and that code returns
Sun Oct 26 14:44:26 GMT+03:00 2014
GMT+03:00
if I set the system date in 26.10.2014
In my point of view it is wrong behavior of java zoneinfo system.
I downloaded the tzupdater and run it, the file Europe/Moscow was updated and now its size is 705 kB.
I try the code below:
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
System.out.println(new java.util.Date());
System.out.println(java.util.TimeZone.getDefault());
and it returns
Fri Oct 24 15:10:34 MSK 2014
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null]
and
Sun Oct 26 15:32:03 MSK 2014
sun.util.calendar.ZoneInfo[id="Europe/Moscow",offset=10800000,dstSavings=0,useDaylight=false,transitions=79,lastRule=null]
Why so? Why the offset is the same in these two cases?
tl;dr
Do not use an offset (+03:00) when you mean a time zone (Europe/Moscow)
Never rely on JVM’s current default time zone.
Never use java.util.Date.
For a moment in UTC, use java.time.Instant.
Instant.now()
For a moment in a time zone, use java.time.ZonedDateTime.
ZonedDateTime.now(
ZoneId.of( "Europe/Moscow" )
)
Offset versus time zone
As the comment by Jon Skeet notes, your JVM’s initial default time zone was not a time zone, it was merely an offset-from-UTC.
What is the difference? An offset is simply a number of hours, minutes, and seconds, positive (ahead of UTC) or negative (behind UTC). A time zone is much more. A time zone is a history of the past, present, and future changes to the offset used by the people of a particular region. The offset for a region can change whenever the politicians so deem. For example, many politicians buy into the lunacy of Daylight Saving Time (DST), and change the offset twice a year.
So if you set your time zone to a mere offset such as +03:00 (three hours ahead of UTC/GMT) rather than a time zone such as Europe/Moscow, your current date-time will always be reported as three hours ahead of UTC. Changes in offset for your region such as DST will be ignored, because you said so, you said "Always three hours ahead of UTC".
java.time
You are using terrible date-time classes that were supplanted years ago by the java.time classes defined in JSR 310.
Instead of TimeZone, use ZoneId.
ZoneId z = ZoneId.of( "Europe/Moscow" ) ;
ZonedDateTime zdt = ZonedDateTime.now( z ) ; // Capture the current moment as seen in the wall-clock time used by the people of a particular region (a time zone).
Avoid setting default time zone
You should only set the default time zone of your JVM as a last-ditch act of desperation.
Setting the default time zone (and default locale, by the way) immediately affects all code in all threads of all apps running within that JVM. You will be rudely changing the zone behind the backs of other programmers. You might even find that their code changes the zone behind your back, during runtime.
Better to write all your date-time handling to never rely on the current default zone (or locale). Specify explicitly your desired/expected time zone by passing optional arguments. Personally, I wish those time zone arguments were required rather than optional, to help educated programmers about date-time issue.
We can see an example of this in the code above. Notice how we pass a ZoneId for Russia to the now method. Otherwise, we would be capturing the current moment in the wall-clock time of whatever region happens to be the JVM’s current default time zone.
Tip: If critical, always confirm the time zone with the user.
java.util.Date::toString lies
Be aware that the toString method on the Date objects you were calling has the anti-feature of dynamically applying the JVM’s current default time zone while generating the text to represent that moment. While well-intentioned, this unfortunate design decision has confused countless programmers trying to wrangle date-time values in Java. A java.util.Date is actually in UTC, as a count of milliseconds since the first moment of 1970 in UTC. The time zone shown in the string is not actually in the Date object.
But this is moot, as this is one of many reasons to avoid this class entirely. Use java.util.Instant instead. Instead of GregorianCalendar, use ZonedDateTime.
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 problem was solved by adding the definition of correct timezone.
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
Your second test (26.10.2014) is after the change to wintertime so you probably need to correct the time as well by -1 hour

Joda-Time: DateTime, DateMidnight and LocalDate usage

Joda-Time library includes different datetime classes
DateTime - Immutable replacement
for JDK Calendar DateMidnight
- Immutable class representing a date where the time is forced to
midnight LocalDateTime -
Immutable class representing a local
date and time (no time zone)
I'm wondering how are you using these classes in your Layered Applications.
I see advantages in having almost all the Interfaces using LocalDateTime (at the Service Layer at least) so that my Application doesn't have to manage Timezones and can safely assume Times always in UTC. My app could then use DateTime to manage Timezones at the very beginning of the Execution's Flow.
I'm also wondering in which scenario can DateMidnight be useful.
I see advantages in having almost all
the Interfaces using LocalDateTime (at
the Service Layer at least) so that my
Application doesn't have to manage
Timezones and can safely assume Times always in UTC.
I'm not sure I understand your line of thinking here. LocalDateTime and DateTime represent two quite different concepts. It's not the case that a LocalDateTime has some implicit UTC timezone: it actually has no timezone (internally it may be represented as a DateTime with UTC timezone, but it's just a implementation detail, it does not matter to the programmer who uses it).
You can see in the API docs that, while a DateTime is a "Instant" (a point in the world time line, a physical concept), a LocalDateTime is NOT such a thing. The LocalDateTime is actually a Partial, (a "civil" concept), in a different class hierarchy. The classes names might -unfortunately- make you think that LocalDateTime is some specialization of DateTime: well, it isn't.
A LocalDateTime should be regarded as a pair {Date (Y/M/D) ; Time (hh:mm:ss.msec)}, a bunch of numbers which corresponds to the "civil" standard representation of time-related data. If we are given a LocalDateTime, we cannot convert it directly to a DateTime, we need to specify a timezone; and that conversion takes we to another kind of entity. (An analogy: Strings and byte streams in Java: to convert between them you must specify a charset encoding, because they are conceptually different things)
When to use one or the other in the application... it's sometimes arguable, but frequently is clear enough, once the Jodatime concepts are understood. And IMO is not much related to "layers", perhaps more to use cases or scenarios.
A non-trivial -borderline- example: You work at Google, programming the Calendar. You must let the user manage (add, see, modify) an event which includes a date-time (lets ignore recurrent events), say "I have an appointement with my doctor on 2019-July-3 at 10:00 am". What is the time-date entity to use in the software layer (for this usecase)? I'd say: a LocalDateTime. Because the user is not really dealing with a physical point in time, but with a civil time: the date and time that displays the clock in his wrist or in his home. He does not even think of timezones (lets ignore the special case of a user who is traveling around the world...) Then, in the bussiness and presentation layer, a LocalDateTime seems the right entity.
But suppose that you must also code a different scenario: a reminder. When the Google internal scheduler detects that the event stored by the user is N minutes in the future from now, it must send him a reminder. Here, "N minutes from now" is a totally "physical" concept of time, so here the "business layer" would deal with a DateTime. There are several alternatives, for example: the event was stored in the DB as a LocalDateTime (ie. just time and date without timezone - one frequently uses a UTC timestamp to represent that, but this an implementation detail). In this scenario (only in this) we must load it as a DateTime, we convert it using a Timezone, probably from the user's profile.
The Answer by leonbloy is correct and vitally important. I am merely translating to the java.time classes that replace the Joda-Time project.
java.time
Specific moment
For a specific moment on the timeline:
Always in UTC is represented by Instant.
Assigned an offset-from-UTC is represented by OffsetDateTime.
Assign a full time zone rather than mere offset is represented by ZonedDateTime.
These all replace the Instant & DateTime class in Joda-Time. These java.time classes all have a resolution of nanoseconds versus the milliseconds used by Joda-Time.
Midnight versus Start-of-day
For midnight, the Joda-Time project concluded “midnight” is a vague and unproductive concept. The midnight-related classes and midnights were all deprecated in later versions of Joda-Time, replaced with the practical concept of “first moment of the day”.
The java.time classes took the same lesson, using a "first moment of the day" approach. Look for atStartOfDay methods on java.time classes such as LocalDate.
Never assume a day starts at 00:00. Anomalies such as Daylight Saving Time (DST) mean the day may start at other times such as 01:00.
ZonedDateTime zdt =
LocalDate.of( 2017 , Month.MARCH , 12 ) // Instantiate a date-only value without time zone.
.atStartOfDay( ZoneId.of( "America/Havana" ) ) ; // Cuba jumps from 00:00 to 01:00 on Spring DST cut-over.
For example, see how Cuba starts the day at 1 AM on their Spring DST cut-over.
zdt: 2017-03-12T01:00-04:00[America/Havana]
Unzoned
For representing the vague idea of possible moments over a range of about 26-27 hours but not an actual moment on the timeline, use LocalDateTime. This class purposely lacks any offset-from-UTC or time zone.
LocalDateTime ldt = LocalDateTime.of( 2017 , Month.JANUARY , 23 , 1 , 2 , 3 , 0 ) ;
If your business context implies a specific time zone, you can apply it to get a ZonedDateTime.
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; // Determine a specific point on timeline by providing the context of a time zone.
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, 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
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.

Categories

Resources