简述:
您的日期差异问题可能与MongoDB无关,也与Java版本无关。问题很可能源于使用了不同的时区。
同一时刻在不同时区下显示的日期是不同的。
您的代码:
println("Date: ${date.toInstant()?.atZone(ZoneId.systemDefault())!!.toLocalDate()}")
使用的是默认时区。我猜测运行时默认时区发生了变化。
不要这样做,请勿依赖此类默认设置。👉 指定您期望/需要的时区。例如:
Instant.ofEpochMilli(x).atZone(ZoneId.of("Europe/Paris")).toLocalDate()
详情:
我们最近将应用程序从Java 11升级到了Java 17。
时区规则经常发生变化。大多数Java版本和更新都包含了最新的tzdata数据。
部署后,我们注意到某些记录存在日期显示差异,表现为相差一天(+1天)。
这听起来像是一个时区问题。
顺便提一下,1970年以后的时区规则有详细的回溯性文档记录,即便如此,这些规则仍有一些漏洞和不准确之处。追溯到更早的几十年,其准确度会更低。通过后期版本的tzdata进行修复总是可能的。
实际上没有“CEST”时区这个概念。
像CEST
这样的文本是一种伪时区,它提供了一个关于可能的意图时区及其是否处于夏令时状态的提示。伪时区并未标准化,甚至不是唯一的!永远不要在存储、交换或处理日期时间值时使用伪时区。只在向用户展示时使用伪时区。
真实的时区有一个“Continent/Region”的格式名称,如Europe/Paris
、America/Edmonton
和Pacific/Auckland
。
您并未在问题中说明具体使用了MongoDB的哪种数据类型。
提供的Kotlin代码片段在Java 11环境下表现令人满意。然而,在Java 17环境下执行时未能按预期工作。
最可能的解释是,您的问题(日期差异)与Java版本无关,而是与您的JVM当前的默认时区有关。
对于任何给定的时刻,👉 日期在全球范围内因时区而异。同一个时刻在东京可能是“明天”,而在洛杉矶则可能同时是“昨天”。
运行以下代码来验证当前默认时区(Java语法):
System.out.println(ZoneId.systemDefault());
依赖于默认设置是导致测试混乱的好方法。相反,请明确指定您的期望/所需时区。
System.out.println(Runtime.version());
Instant instant = Instant.ofEpochMilli(-1_118_625_572_000L); // 始终与UTC相差零小时分钟秒。
ZoneId zLosAngeles = ZoneId.of("America/Los_Angeles");
ZoneId zTokyo = ZoneId.of("Asia/Tokyo");
ZonedDateTime zdtLosAngeles = instant.atZone(zLosAngeles);
ZonedDateTime zdtTokyo = instant.atZone(zTokyo);
System.out.println("同一时刻,不同日期。");
System.out.println(zdtLosAngeles);
System.out.println(zdtTokyo);
在<a href="https://ideone.com/TlHv1v" rel="nofollow noreferrer">Ideone.com</a>上查看此代码的运行结果。请注意,对于相同的时间点,由于时区不同,显示的日期也会不同。Alice在洛杉矶看到墙上的日历显示是21号,与此同时,Bob在东京看到他的墙上挂钟/日历显示的是22号。
12.0.1+12
同一时刻,不同日期。
1934-07-21T14:40:28-08:00[America/Los_Angeles]
1934-07-22T07:40:28+09:00[Asia/Tokyo]
验证输入:
让我们将您的示例通过Java 12在<a href="https://ideone.com/1u6My8" rel="nofollow noreferrer">Ideone.com</a>上运行一遍。
System.out.println(Runtime.version());
String v1934_input = "1934-07-21T22:40:28.000+00:00";
String v1897_input = "1897-08-06T23:40:28.000+00:00";
Instant v1934_instant = Instant.parse(v1934_input);
Instant v1897_instant = Instant.parse(v1897_input);
long v1934_millis = v1934_instant.toEpochMilli();
long v1897_millis = v1897_instant.toEpochMilli();
System.out.println(v1934_input + " = " + v1934_instant + " = " + v1934_millis);
System.out.println(v1897_input + " = " + v1897_instant + " = " + v1897_millis);
12.0.1+12
1934-07-21T22:40:28.000+00:00 = 1934-07-21T22:40:28Z = -1118625572000
1897-08-06T23:40:28.000+00:00 = 1897-08-06T23:40:28Z = -2284762772000