当我尝试创建两个日期时,我刚刚发现了 Java 的 Date 类的一个非常奇怪的行为:
Date startDate = new Date(1282863600000L);
System.out.println(startDate);
Date endDate = new Date(1321919999000L);
System.out.println(endDate);
输出分别为:
2010 年 8 月 27 日星期五 00:00:00 BST 2011 年 11 月 21 日星期一 23:59:59 GMT
有人见过这样的事情吗?两个日期都以相同的方式初始化,但打印时第一个显示为 BST,后者显示为 GMT?
我试图找到对此的解释,但我没有。有人可以帮助我吗?
提前致谢!
这是有记录的行为。
Date.toString()
:
将此日期对象转换为以下形式的字符串:
dow mon dd hh:mm:ss zzz yyyy
是时区(可能反映夏令时)。标准时区缩写包括那些由方法解析识别的缩写。如果时区信息不可用,则zzz
为空 - 也就是说,它根本不包含任何字符。zzz
您使用的区域设置使用英国夏令时,并创建一个适用夏令时规则的日期。这将是本地用户当时期望的日期形式。
对我来说这段代码的输出是
2010 年欧洲夏令时间 8 月 27 日星期五 01:00:00 欧洲中部时间 2011 年 11 月 22 日星期二 00:59:59
确切的结果取决于您系统上使用的默认 Java 语言环境。
区别在于CEST是欧洲中部夏令时间,而CET是欧洲中部时间(即不是夏令时)。
您似乎在英国语言环境中运行(
en_GB
或类似语言),因此您的输出分别显示英国夏令时间和格林威治标准时间。
您指定的第一个日期属于各自的夏季时间,而第二个日期则不然。因此 Java 会为每个区域/时间组合选择适当的时区。
在尝试不同的
long
值之后,我得到了这个:
Date startDate1 = new Date(1284245999999L);
Date startDate2 = new Date(1284246000000L);
System.out.println(startDate1);
System.out.println(startDate2);
Date endDate = new Date(1321919999000L);
System.out.println(endDate);
输出是:
Sun Sep 12 01:59:59 IDT 2010
Sun Sep 12 01:00:00 IST 2010 <-- Long value is greater, but due to DST changes, actual time is one hour earlier
Tue Nov 22 01:59:59 IST 2011
请注意,将 long 从
1
增加 1284245999999L
到 1284246000000L
会让我们“回到过去”,因为从标准时间过渡到夏令时。java.util.Date
不保存时区信息。它存储自 UTC 1970 年 1 月 1 日午夜以来的毫秒数,并且 Date#toString
将 JVM 的默认时区应用于它以形成输出文本。由于您的 JVM 将欧洲/伦敦设置为时区,因此 Date#toString
使用相同的时区。java.time
2014 年 3 月,Java 8 引入了现代的
java.time
日期时间 API,取代了容易出错的旧版java.util
日期时间 API。任何新代码都应使用 java.time
API。
java.time.ZonedDateTime
保存时区信息以及日期和时间。以下是其文档的摘录:
ISO-8601 日历系统中带有时区的日期时间,例如
。2007-12-03T10:15:30+01:00 Europe/Paris
它最好的一点是它会根据 DST 自动调整区域偏移,如下面的演示所示。
ZonedDateTime
要求您在将 ZoneId
转换为 Instant
时指定 ZonedDateTime
。
演示:
class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.of("Europe/London");
ZonedDateTime zdt1 = Instant.ofEpochMilli(1282863600000L)
.atZone(zoneId);
ZonedDateTime zdt2 = Instant.ofEpochMilli(1321919999000L)
.atZone(zoneId);
System.out.println(zdt1);
System.out.println(zdt2);
}
}
输出:
2010-08-27T00:00+01:00[Europe/London]
2011-11-21T23:59:59Z[Europe/London]
Z
表示 +00:00
的时区偏移量,即 UTC 的时区偏移量。
从 Trail:日期时间了解有关现代日期时间 API 的更多信息。