问题
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?
回答1:
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.
回答2:
The problem was solved by adding the definition of correct timezone.
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Moscow"));
回答3:
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
来源:https://stackoverflow.com/questions/26674248/what-is-wrong-with-java-zoneinfo