gpt4 book ai didi

与 java.time.Instant 对象一起使用时的 Java SE 8 TemporalAccessor.from 问题

转载 作者:行者123 更新时间:2023-12-01 19:38:14 24 4
gpt4 key购买 nike

java.time有一个 Instant封装时间轴上的位置(或“时刻”)的类。虽然我知道这是一个秒/纳秒值,所以与时区或时间偏移没有直接关系,但它的 toString返回格式化为 UTC 日期/时间的日期和时间,例如 2014-05-13T20:05:08.556Z。还有 anInstant.atZone(zone)anInstant.atOffset(offset)两者都产生与处理 Instant 一致的值因为具有隐含的 UTC 时区/“零”偏移量。

因此,我会期望:

  • ZoneOffset.from(anInstant)产生一个“零”ZoneOffset
  • OffsetDateTime.from(anInstant)生成具有“零”偏移量的日期/时间
  • ZoneId.from(anInstant) (可能)产生一个UTC ZoneId
  • ZonedDateTime.from(anInstant) (可能)产生一个 ZonedDateTime带有 UTC ZoneId

  • ZonedDateTime.from 的文档,当我读到它时,似乎赞同这一点。

    事实上 ZoneOffset.from(anInstant)失败 DateTimeException ,我想是因为这个原因 OffsetDateTime.from(anInstant)也失败了,其他两个也是如此。

    这是预期的行为吗?

    最佳答案

    简答:

    JSR-310 设计者不希望人们通过像 ZoneId 类型的静态 from() 方法在机器时间和人类时间之间进行转换。 , ZoneOffset , OffsetDateTime , ZonedDateTime等等。这是明确指定的,如果您仔细研究 javadoc。而是使用:

    OffsetDateTime#toInstant():Instant
    ZonedDateTime#toInstant():Instant
    Instant#atOffset(ZoneOffset):OffsetDateTime
    Instant#atZone(ZoneId):ZonedDateTime

    静态 from() 方法的问题在于,否则人们可以在 Instant 之间进行转换。例如 LocalDateTime不考虑时区。

    长答案:

    是否考虑 Instant作为计数器或字段元组,JSR-310-team 给出的答案是所谓的机器时间和人类时间之间的严格分离。事实上,他们打算进行严格的分离——参见他们的 guidelines .所以最后他们想要 Instant仅被解释为机器时间计数器。所以他们故意设计了一个你不能问 Instant 的设计。对于年份、小时等字段。

    但事实上,JSR-310 团队根本不是一致的。他们已经实现了方法 Instant.toString()作为字段元组 View ,包括年份、...、小时、... 和偏移符号 Z(用于 UTC 时区)(脚注:在 JSR-310 之外,在此类机器上具有基于字段的外观是很常见的次 - 例如参见维基百科或其他网站上关于 TAI and UTC 的信息)。一旦规范负责人 S. Colebourne 在对 threeten-github-issue 的评论中说:

    “如果我们真的强硬,那么 Instant 的 toString 将只是从 1970-01-01Z 开始的秒数。我们选择不这样做,并输出一个更友好的 toString 来帮助开发人员,但它不会改变Instant 只是秒数的基本事实,如果没有某种时区,就无法转换为年/月/日。”

    人们可以喜欢或不喜欢这个设计决定(像我一样),但结果是你不能问 Instant对于年、...、小时、...和偏移量。另请参阅支持字段的文档:
    NANO_OF_SECOND 
    MICRO_OF_SECOND
    MILLI_OF_SECOND
    INSTANT_SECONDS

    有趣的是缺少什么,最重要的是缺少与区域相关的字段。 作为一个原因,我们经常听到像 Instant 这样的对象的说法。或 java.util.Date没有时区。 在我看来,这是一个过于简单化的观点。虽然这些对象在内部确实没有时区状态(并且也不需要具有这样的内部值),但这些对象必须与 UTC 时区相关,因为这是每个时区偏移计算和转换为本地类型的基础.所以正确答案是:An Instant是一个机器计数器,它在时区 UTC(根据规范)中计算自 UNIX 纪元以来的秒数和纳秒数。最后一部分 - 与 UTC 区域的关系 - JSR-310-team 没有很好地说明,但他们不能否认。 设计师希望从 Instant 中取消时区方面因为它看起来与人类时间有关。 但是,他们不能完全废除它,因为这是任何内部偏移计算的基本部分。所以你的观察

    “还有一个 Instant.atZone(zone) 和一个 Instant.atOffset(offset) 都会产生一个与将 Instant 视为具有隐含的 UTC 时区/'零'偏移量一致的值。”

    是对的。

    虽然 ZoneOffset.from(anInstant) 可能非常直观可能会产生 ZoneOffset.UTC ,它抛出异常,因为它的 from() 方法搜索不存在的 OFFSET_SECONDS-field . JSR-310 的设计者出于同样的原因决定在规范中这样做,即让人们认为 Instant与 UTC 时区正式无关,即“没有时区”(但在内部,他们必须在所有内部计算中接受这个基本事实!)。

    出于同样的原因, OffsetDateTime.from(anInstant)ZoneId.from(anInstant)也失败

    关于 ZonedDateTime.from(anInstant)我们 read :

    “转换将首先从时间对象获取 ZoneId,必要时回退到 ZoneOffset。然后它会尝试获取 Instant,如有必要回退到 LocalDateTime。结果将是 ZoneId 或 ZoneOffset 与即时或本地日期时间。”

    因此,由于相同的原因,此转换将再次失败,因为 ZoneId也不是 ZoneOffset可以从 Instant 获得.异常消息如下:

    “无法从 TemporalAccessor 获取 ZoneId:1970-01-01T00:00:00Z,类型为 java.time.Instant”

    最后,我们看到所有静态 from() 方法都无法在人类时间和机器时间之间进行转换,即使这看起来很直观。在某些情况下,我们可以说 LocalDate 之间的转换和 Instant值得怀疑。此行为已指定,但我预测您的问题不是此类问题的最后一个,许多用户将继续感到困惑。

    我认为真正的设计问题是:

    a) 人的时间和机器的时间之间不应有明显的区别。时间对象,如 Instant应该更好地表现得像两者。量子力学中的一个类比:您可以将电子视为粒子和波。

    b) 所有静态 from() 方法都太公开了。我认为 Ihat 太容易访问了,最好从公共(public) API 中删除,或者使用比 TemporalAccessor 更具体的参数。 .这些方法的弱点在于人们可能会忘记在此类转换中考虑相关的时区,因为它们以本地类型开始查询。考虑例如: LocalDate.from(anInstant) (在哪个时区???)。但是,如果您直接询问 Instant其日期如 instant.getDate() ,我个人认为 UTC 时区中的日期是有效答案,因为这里查询是从 UTC 角度开始的。

    c) 总结:我绝对与 JSR-310 团队分享了避免在本地类型和全局类型之间进行转换的好主意,例如 Instant不指定时区。我只是在 API 设计方面有所不同,以防止用户进行这种无时区转换。我的首选方法是限制 from() 方法,而不是说全局类型不应与人类时间格式(例如日历日期或挂墙时间或 UTC 时区偏移)有任何关系。

    无论如何,由于保持向后兼容性,这种(无关紧要的)分离机器时间和人类时间的设计现在已经一成不变,每个想要使用新 java.time-API 的人都必须接受它。

    抱歉回答太长,但很难解释 JSR-310 的所选设计。

    关于与 java.time.Instant 对象一起使用时的 Java SE 8 TemporalAccessor.from 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23641846/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com