将 java.util.Date (01.01.0001) 转换为 java.time.LocalDate 返回 29.12.0000

Der*_*ill 0 java date java-time

我想解析我java.util.Date发现java.time.LocalDate 这个代码,当我搜索问题时:

Date date = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.0001");
date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Run Code Online (Sandbox Code Playgroud)

如果我有01.01.0001开始日期,我会遇到问题:

date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
Run Code Online (Sandbox Code Playgroud)

==> (java.time.LocalDate) 0000-12-29

29.12.0000并且01.01.0001不一样。

  1. 为什么实际结果与预期不同?
  2. 如果我也想收到这个LocalDate价值该怎么办01.01.0001?

时区信息:

ZoneId.systemDefault()
Run Code Online (Sandbox Code Playgroud)

==> (java.time.ZoneRegion) 欧洲/柏林

  1. 我认为,问题出在这一步:date.toInstant()
  2. 我不认为这(仅)是时区问题。如果我用不同的年份测试它。例如 1901 年,结束于 1900 年 12 月 31 日。
        Date date0001 = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.0001");
        System.out.println(date0001.toInstant());
Run Code Online (Sandbox Code Playgroud)

==> 0000-12-29T23:00:00Z

        Date date1901 = new SimpleDateFormat("dd.MM.yyyy").parse("01.01.1901");
        System.out.println(date1901.toInstant());
Run Code Online (Sandbox Code Playgroud)

==> 1900-12-31T23:00:00Z

Bas*_*que 5

java.time

\n

了解 Java 附带两种不同的日期时间框架。

\n
    \n
  • 其中一个有严重缺陷,现在已成为遗产。
  • \n
  • 另一个是行业领先的,在 JSR 310 中定义,所有类都可以在java.time.*包中找到。
  • \n
\n

让我们来看看你第一年的第一个时刻。

\n
Instant yearOneStartInUtc = Instant.parse ( "0001-01-01T00:00:00Z" );\n
Run Code Online (Sandbox Code Playgroud)\n
\n

yearOneStartInUtc.toString() = 0001-01-01T00:00:00Z

\n
\n

末尾Z的 发音为 \xe2\x80\x9cZulu\xe2\x80\x9d,表示距 UTC 时间子午线零时-分-秒的偏移。

\n

我们可以通过调用添加到旧类中的新方法来在遗留框架和现代框架之间自由地来回转换。

\n
java.util.Date judStart = java.util.Date.from ( yearOneStartInUtc );\n
Run Code Online (Sandbox Code Playgroud)\n
\n

judStart.toString() = 太平洋标准时间 1 月 2 日星期日 16:00:00 1

\n
\n

避免遗留日期时间类

\n

请注意,该java.util.Date#toString方法对我们撒谎。虽然java.util.Date代表 UTC 中的时刻(偏移量为零),但其toString方法在生成文本结果时动态应用 JVM\xe2\x80\x99s 当前默认时区。这是避免使用这个遗留类以及Calendar、SimpleDateFormat等的众多原因之一。

\n

现在我们可以查看其余的代码。

\n

区域之间的调整

\n

您应用了时区以Instant根据 UTC 进行调整。您忘记告诉我们那个时区是什么。那么我们就任意选择时区吧America/Edmonton。该时区比 UTC 晚几个小时。

\n
Instant yearOneStartInUtc = Instant.parse ( "0001-01-01T00:00:00Z" );\n
Run Code Online (Sandbox Code Playgroud)\n
\n

zdtYearOneStart.toString() = 0000-12-31T16:26:08-07:33:52[美国/埃德蒙顿]

\n
\n

请注意,日期与输入不同,0000-12-31 与 0001-01-01。时间也不同,16:26:08-07:33:52 与 00:00:00。这就是我们的解释。

\n

想象一下,就在那一刻,当日期和年份翻过时,爱丽丝站在皇家天文台未来的所在地格林威治。她观测到的当前时间是元旦00:00:00。但对于在加拿大艾伯塔省埃德蒙顿小酌一杯的鲍勃来说,同一时刻是 New Year\xe2\x80\x99s Eve,而不是 New Year\xe2\x80\x99s Day。当鲍勃抬头看墙上的时钟时,他会看到距离午夜还有几个小时的时间。Alice 在 \xe2\x80\x9cn 下一年 \xe2\x80\x9d 0001,而 Bob 同时在 \xe2\x80\x9c 去年\xe2\x80\x9d 0000。

\n

对于任何给定时刻,全球各地的时间和日期都会因时区而异。

\n

因此 1 月 1 日和 12 月 31 日的日期差异是有道理的。然而,你12月29日的结果没有意义。您忽略了提供MCVE,所以我怀疑您犯了一个错误。

\n

  • @user85421 在 Stack Overflow 上,读者不需要通过搜索评论来理解问题。作者有责任使用所有相关事实来编辑他们的问题。 (3认同)