有一个问题,当时钟由于夏时制(每年两次)而移动时,Java中的日期不正确(我在中欧:EDOCX1,0在夏天,EDOCX1,1)在冬天。
如果时间提前1小时移动,new Date()仍返回旧时间(比当前时间晚1小时)。
在Java 7中,可以在不重启JBASE应用服务器的情况下解决这个问题吗?
如果在Windows中手动更改时间,则会重现问题:除非重新启动JBoss,否则Date不会更新到系统日期。
- 这种行为意味着您可能没有使用正确的时区,因此您可能希望彻底检查应用程序如何处理时间戳。据我所知,您可能希望完全从Date迁移出去,因为该类不支持时区或任何类型的DST转换。使用java.time包中的类,或者如果还没有java8,至少使用java.util.Calendar包。
- 日期对象没有时区信息,它只是一个时代以来的毫秒数。打印时会显示默认时区,但不会影响其状态。
- 正在使用日历和设置时间(new date())。只想获取当前系统日期而不重新启动。如果系统日期是手动更新的,则当前日历日期不会在不重新启动的情况下更新。
- 什么是当前日历日期没有更新?预期的行为是您在更新系统时间之前创建的Calendar对象应该保持其值。更新系统时间后创建的新Calendar对象应该会给您新的时间(我不确定缓存问题是否会阻止它,但对我来说似乎不太可能)。
- 使用jboss在Windows中做了一些测试,在更新本地时间之后,一个新的日历对象返回了旧的小时。只有重新启动jboss之后,它才返回当前的Windows时间。
- 正如assylias所评论的,不要相信toString方法。该方法在生成字符串时应用JVM的当前默认时区。Date本身始终是UTC。避免这些可怕的旧遗留日期时间类的原因之一。改为使用java.time。
在Java <=7中,可以使用StuteTeN后端,这是Java 8新的日期/时间类的一个很大的后端。
有了这个,您可以轻松地处理DST更改。
首先,您可以使用org.threeten.bp.DateTimeUtils从Calendar转换为Calendar。
下面的代码将Calendar转换为org.threeten.bp.Instant,这是一个表示"UTC即时"(与时区无关的时间戳)的类:现在,世界上的每个人都在同一时刻,尽管他们的本地日期和时间可能不同,但取决于他们在哪里)。
然后,Instant转换为org.threeten.bp.ZonedDateTime(意思是:此时此刻,这个时区的日期和时间是什么?).I还使用org.threeten.bp.ZoneId获得时区:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Calendar c = Calendar. getInstance();
c. setTime(new Date());
// get the current instant in UTC timestamp
Instant now = DateTimeUtils. toInstant(c );
// convert to some timezone
ZonedDateTime z = now. atZone(ZoneId. of("Europe/Berlin"));
// today is 08/06/2017, so Berlin is in DST (GMT+2)
System. out. println(z ); // 2017-06-08T14:11:58.608+02:00[Europe/Berlin]
// testing with a date in January (not in DST, GMT+1)
System. out. println(z. withMonth(1)); // 2017-01-08T14:11:58.608+01:00[Europe/Berlin] |
我刚刚选择了一些使用中欧时区的时区(Europe/Berlin):您不能使用这些3个字母的缩写,因为它们不明确且不标准。您可以将代码更改为最适合您的系统的时区(您可以使用ZoneId.getAvailableZoneIds())获得所有可用时区的列表。
我更喜欢这个解决方案,因为它明确了我们用来向用户显示的时区(Date和Calendar的toString()方法在后台使用默认时区,而您永远不知道它们在做什么)。
在内部,我们可以继续使用Instant,它是在UTC中,所以它不受时区的影响(并且您可以随时转换到时区和从时区转换到时区),如果您想将ZonedDateTime转换回Instant,只需使用toInstant()方法。
实际上,如果你想得到当前的日期/时间,只需忘记旧的类(Date和Calendar并只使用Instant:
1 2
| // get the current instant in UTC timestamp
Instant now = Instant.now(); |
但是如果仍然需要使用旧类,只需使用DateTimeUtils进行转换。
上述示例的输出是ZonedDateTime.toString()方法的结果。如果要更改格式,请使用org.threeten.bp.format.DateTimeFormatter类(查看javadoc以了解有关所有可能格式的更多详细信息):
1 2 3 4 5
| DateTimeFormatter formatter = DateTimeFormatter. ofPattern("dd/MM/yyyy HH:mm:ss z X");
// DST (GMT+02)
System. out. println(formatter. format(z )); // 08/06/2017 14:11:58 CEST +02
// not DST (GMT+01)
System. out. println(formatter. format(z. withMonth(1))); // 08/01/2017 14:11:58 CET +01 |
使用jdk 8 java.time中的ZonedDateTime类。它适应夏令时的变化。详情请访问:https://docs.oracle.com/javase/8/docs/api/java/time/zoneddatetime.html