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

Naz*_* K. 53 java datetime java-8 java-time

这些之间有什么区别:

zonedDateTime.truncatedTo(ChronoUnit.DAYS);

zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());
Run Code Online (Sandbox Code Playgroud)

有理由偏爱另一个吗?

谢谢

Men*_*ild 50

为更正而更新:

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

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]
Run Code Online (Sandbox Code Playgroud)

截断发生在本地时间轴上.如果您选择DAYS,那么您选择午夜.根据javadoc,truncate()-method最终转换回新方法ZonedDateTime,并将时间向前移动间隙的大小(1小时).

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

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

对于重叠,一般策略是如果本地日期时间落在重叠的中间,则将保留先前的偏移.如果没有先前的偏移,或者先前的偏移无效,则使用较早的偏移,通常是"夏天"时间.

如果该类ZonedDateTime因此遵循其自己的规范,则两个过程仍然是等同的意思:

zdt.truncatedTo(ChronoUnit.DAYS);
Run Code Online (Sandbox Code Playgroud)

应该相当于

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap();
Run Code Online (Sandbox Code Playgroud)

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

zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap();
Run Code Online (Sandbox Code Playgroud)

看起来像课堂上隐藏的不一致ZonedDateTime,温和地说.如果你问我哪种方法更受欢迎,那么我宁愿提倡第二种方法,虽然它更长,需要更多的击键.但它的最大优点是更加透明.更喜欢第二种方法的另一个原因是:

它确实获得当地时间等于一天开始的第一瞬间.否则,在使用第一种方法时,您必须写:

zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap();
Run Code Online (Sandbox Code Playgroud)


Aus*_*tin 35

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

例如,古巴在凌晨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]
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢您找到了一个反例。给你投了赞成票,也更新了我的答案。 (3认同)

nev*_*ter 6

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

zonedDateTime.with(LocalTime.MIN);
Run Code Online (Sandbox Code Playgroud)

它产生与truncatedTo相同的结果