Java 8 日期时间:从 ZonedDateTime 开始一天

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29143910/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:26:38  来源:igfitidea点击:

Java 8 date-time: get start of day from ZonedDateTime

javadatetimejava-8java-time

提问by Nazaret K.

Is there any difference between these:

这些有什么区别吗:

zonedDateTime.truncatedTo(ChronoUnit.DAYS);

zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());

Any reason to prefer one against the other?

有什么理由更喜欢一个而不是另一个?

Thanks

谢谢

采纳答案by Meno Hochschild

Updated for sake of correction:

为了更正而更新:

In most cases yes the same, see following example for Brazil when switching from winter to summer time:

在大多数情况下是相同的,当从冬季切换到夏季时间时,请参阅以下巴西示例:

ZonedDateTime zdt = 
  ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0, 
    ZoneId.of("America/Sao_Paulo")); // switch to summer time
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt); // 2015-10-18T01:30-02:00[America/Sao_Paulo]
System.out.println(zdt1); // 2015-10-18T01:00-02:00[America/Sao_Paulo]
System.out.println(zdt2); // 2015-10-18T01:00-02:00[America/Sao_Paulo]

Truncating happens on the local timeline. If you choose DAYS then you opt for midnight. According to javadocthe truncate()-method finally converts back to the new ZonedDateTimeand shifts the time forward by the size of the gap (1 hour).

截断发生在本地时间线上。如果您选择 DAYS,则您选择午夜。根据javadoctruncate()-method 最终转换回新的ZonedDateTime,并将时间向前移动间隙的大小(1 小时)。

Converting the zdt first to LocalDate(cutting off the time part) and then looking for its ZonedDateTime-part in given timezone is effectively the same for this situation.

在这种情况下,首先将 zdt 转换为LocalDate(切断时间部分)然后ZonedDateTime在给定时区中查找它的-part 实际上是相同的。

However, for the reverse case of switching back from summer time to winter time there is one exception(thanks very much to @Austin who gave a counter example). The problem is during overlap when to decide which offset to be used. Usually the class ZonedDateTimeis designed/specified to use the previous offset, see also this excerpt from Javadoc:

但是,对于从夏季时间切换回冬季时间的相反情况,有一个例外(非常感谢@Austin 提供了一个反例)。问题是在重叠期间决定使用哪个偏移量。通常该类ZonedDateTime被设计/指定为使用先前的偏移量,另请参阅Javadoc 的摘录:

For Overlaps, the general strategy is that if the local date-time falls in the middle of an Overlap, then the previous offset will be retained. If there is no previous offset, or the previous offset is invalid, then the earlier offset is used, typically "summer" time.

对于 Overlaps,一般的策略是,如果本地日期时间落在 Overlap 的中间,那么将保留之前的偏移量。如果没有先前的偏移量,或者先前的偏移量无效,则使用较早的偏移量,通常是“夏季”时间。

If the class ZonedDateTimewould consequently follow its own specification then both procedures would still be equivalent meaning:

如果类ZonedDateTime因此遵循它自己的规范,那么两个过程仍然是等效的含义:

zdt.truncatedTo(ChronoUnit.DAYS);

should be equivalent to

应该相当于

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap();

But the real behaviour according to the example of @Austin and confirmed by me in own testing is:

但根据@Austin 的例子,我在自己的测试中证实的真实行为是:

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap();

Looks like a hidden inconsistency in the class ZonedDateTime, mildly spoken. If you ask me which method to be preferred then I would rather advocate the second method although it is much longer and requires more keystrokes. But it has the big advantage to be more transparent about what it does. Another reason to prefer the second approach is:

看起来像是课堂上隐藏的矛盾ZonedDateTime,说话温和。如果你问我更喜欢哪种方法,那么我宁愿提倡第二种方法,尽管它更长,需要更多的击键。但它有一个很大的优势,那就是它的行为更加透明。更喜欢第二种方法的另一个原因是:

It really obtains the FIRST instant at which the local time is equal to the start of day. Otherwise, when using first method, you have to write:

它真正获得了本地时间等于一天开始的第一个瞬间。否则,在使用第一种方法时,您必须编写:

zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap();

回答by Austin

They are slightly different. According to the javadocs, truncatedTo()will try to preserve the time zone in the case of overlap, but atStartOfDay()will find the first occurrence of midnight.

它们略有不同。根据javadocs,truncatedTo()会在重叠的情况下尝试保留时区,但atStartOfDay()会找到第一个出现的午夜。

For example, Cuba reverts daylight savings at 1am, falling back to 12am. If you begin with a time after that transition, atStartOfDay()will return the first occurence of 12am, while truncatedTo()will return the second occurence.

例如,古巴在凌晨 1 点恢复夏令时,回到凌晨 12 点。如果您从该转换之后的时间开始,atStartOfDay()将返回第一次出现的 12am,而truncatedTo()将返回第二次出现。

ZonedDateTime zdt = ZonedDateTime.of(2016, 11, 6, 2, 0, 0, 0, ZoneId.of("America/Havana"));
ZonedDateTime zdt1 = zdt.truncatedTo(ChronoUnit.DAYS);
ZonedDateTime zdt2 = zdt.toLocalDate().atStartOfDay(zdt.getZone());

System.out.println(zdt);  // 2016-11-06T02:00-05:00[America/Havana]
System.out.println(zdt1); // 2016-11-06T00:00-05:00[America/Havana]
System.out.println(zdt2); // 2016-11-06T00:00-04:00[America/Havana]

回答by nevster

Note there's also another way of doing it:

请注意,还有另一种方法:

zonedDateTime.with(LocalTime.MIN);

which produces the same result as truncatedTo

产生与 truncatedTo 相同的结果