Java8日期时间:从ZoneDateTime开始一天
这两者之间有什么区别吗Java8日期时间:从ZoneDateTime开始一天,java,datetime,java-8,java-time,Java,Datetime,Java 8,Java Time,这两者之间有什么区别吗 zonedDateTime.truncatedTo(ChronoUnit.DAYS); zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone()); 有什么理由选择一个而不是另一个 谢谢为了更正而更新: 在大多数情况下是相同的,从冬季切换到夏季时,请参见以下巴西示例: ZonedDateTime zdt = ZonedDateTime.of(2015, 10, 18, 0, 30, 0, 0
zonedDateTime.truncatedTo(ChronoUnit.DAYS);
zonedDateTime.toLocalDate().atStartOfDay(zonedDateTime.getZone());
有什么理由选择一个而不是另一个
谢谢为了更正而更新: 在大多数情况下是相同的,从冬季切换到夏季时,请参见以下巴西示例:
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]
截断发生在本地时间线上。如果你选择白天,那么你选择午夜。根据truncate()
-方法最终转换回新的ZoneDateTime
,并将时间向前移动间隙的大小(1小时)
首先将zdt转换为LocalDate
(切断时间部分),然后在给定时区中查找其ZonedDateTime
-部分,在这种情况下实际上是相同的
然而,对于从夏季时间切换回冬季时间的相反情况,有一个例外(非常感谢@Austin给出了一个反例)。问题是在重叠期间,何时决定使用哪个偏移。通常,类ZoneDateTime
设计/指定为使用上一个偏移量,另请参见以下摘录:
对于重叠,一般策略是如果本地日期时间
在重叠的中间落下,那么前面的偏移将是
保留。如果没有上一个偏移,或上一个偏移为
无效,则使用较早的偏移量,通常为“夏季”时间
如果类ZonedDateTime
因此遵循其自身的规范,则这两个过程仍然具有同等意义:
zdt.truncatedTo(ChronoUnit.DAYS);
应该相当于
zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withEarlierOffsetAtOverlap();
但根据@Austin的例子,我在自己的测试中确认的真实行为是:
zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone()).withLaterOffsetAtOverlap();
看起来类ZoneDateTime
中隐藏的不一致,说话温和。如果你问我更喜欢哪种方法,那么我宁愿提倡第二种方法,尽管它要长得多,需要更多的击键。但它有一个很大的优势,那就是对它所做的事情更加透明。选择第二种方法的另一个原因是:
它确实获得了第一个本地时间等于一天开始的时刻。否则,在使用第一种方法时,您必须编写:
zdt.truncatedTo(ChronoUnit.DAYS).withEarlierOffsetAtOverlap();
它们略有不同。根据javadocs的说法,在发生重叠的情况下,将试图保留时区,但会发现第一个发生在午夜 例如,古巴在凌晨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]
注意,还有另一种方法:
zonedDateTime.with(LocalTime.MIN);
这会产生与截断到相同的结果,难道他们不能将方法
atStartOfDay()
放在ZonedDataTime
类中吗?这并不总是正确的!“为什么不看我的答案呢?”奥斯汀你的答案似乎有道理。我会调查并据此更正我的答案。你是说第二种方法<代码>zdt.toLocalDate().atStartOfDay().atZone(zdt.getZone())。带有早期偏移量verlap()@Dr.jacky是的,你已经理解了第二种方法的含义。@MenoHochschild好吧,我已经遵循了这一点:。你认为这可能有问题吗?非常感谢你找到了一个反例。我已经向你投了赞成票,也更新了我的答案。如果夏季时间(DST)从午夜开始,即一天从01:00开始,情况会如何?在任何情况下,代码都不会表达这种情况下的期望行为。它将按照其应有的行为-即在该时区(即适当的DST时区)产生午夜00:00,例如2018-01-27T00:00+11:00【澳大利亚/悉尼】vs 2018-06-27T00:00+10:00【澳大利亚/悉尼】您将从所有3种方法中得到相同的结果-原始问题中的2种方法和这个较短的版本-实际上,为了澄清,这个方法产生的结果与角落案例的ChronoUnit.DAYS版本相同