Java SE 8 TemporalAccessor.from与java.time.Instant对象一起使用时出现问题 [英] Java SE 8 TemporalAccessor.from issues when used with a java.time.Instant object

查看:105
本文介绍了Java SE 8 TemporalAccessor.from与java.time.Instant对象一起使用时出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

java.time has an Instant class which encapsulates a position (or 'moment') on the timeline. While I understand that this is a seconds/nanoseconds value so not directly related to time zones or times offsets, its toString returns a date and time formatted as a UTC date/time, eg 2014-05-13T20:05:08.556Z. Also anInstant.atZone(zone) and anInstant.atOffset(offset) both produce a value that is consistent with treating the Instant as having an implied UTC time-zone/'zero' offset.

因此我原以为:


  • ZoneOffset.from(anInstant)产生'零' ZoneOffset

  • OffsetDateTime.from(anInstant)生成一个'为零的日期/时间'offset

  • ZoneId.from(anInstant)(可能)生成UTC ZoneId

  • ZonedDateTime.from(anInstant)(可能)生成 ZonedDateTime 使用UTC ZoneId

  • ZoneOffset.from(anInstant) to produce a 'zero' ZoneOffset
  • OffsetDateTime.from(anInstant) to produce a date/time with a 'zero' offset
  • ZoneId.from(anInstant) (probably) to produce a UTC ZoneId
  • ZonedDateTime.from(anInstant) (probably) to produce a ZonedDateTime with a UTC ZoneId

ZonedDateTime.from ,正如我读到的那样,似乎赞同这一点。

The documentation for ZonedDateTime.from, as I read it, appears to endorse this.

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

In fact ZoneOffset.from(anInstant) fails with DateTimeException, and I suppose for that reason OffsetDateTime.from(anInstant) also fails, as do the other two.

这是预期的行为吗?

推荐答案

简答:

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

The JSR-310-designers don't want people to do conversions between machine time and human time via static from()-methods in types like ZoneId, ZoneOffset, OffsetDateTime, ZonedDateTime etc. This is explicitly specified if you carefully study the javadoc. Instead use:

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

问题使用静态from() - 方法是否则人们能够在 Instant 之间进行转换,例如 LocalDateTime 不考虑时区。

The problem with the static from()-methods is that otherwise people are able to do conversions between an Instant and for example a LocalDateTime without thinking about the timezone.

长答案:

是否考虑一个 Instant 作为计数器或字段元组,JSR-310团队给出的答案是所谓的机器时间和人类时间之间的严格分离。事实上,他们打算严格分离 - 参见他们的指南。所以最后他们希望 Instant 只被解释为机器时间计数器。所以他们故意有一个设计,你不能要求 Instant 来表示年,小时等字段。

Whether to consider an Instant as counter or as field tuple, the answer given by JSR-310-team was a strict separation between so-called machine time and human time. Indeed they intend to have a strict separation - see their guidelines. So finally they want Instant to be only interpreted as a machine time counter. So they intentionally have a design where you cannot ask an Instant for fields like year, hour etc.

但确实如此,JSR-310团队根本不一致。他们已经将方法 Instant.toString()实现为字段元组视图,包括年,...,小时,...和偏移符号Z(对于UTC时区(脚注:在JSR-310之外,这种机器时间基于现场的外观非常普遍 - 例如在维基百科或其他网站上查看 TAI和UTC )。一旦规范引导S. Colebourne在评论 threeten-github-issue 时说:

But indeed, the JSR-310-team is not consistent at all. They have implemented the method Instant.toString() as a field tuple view including year, ..., hour, ... and offset-symbol Z (for UTC-timezone) (footnote: Outside of JSR-310 this is quite common to have a field-based look on such machine times - see for example in Wikipedia or on other sites about TAI and UTC). Once the spec lead S. Colebourne said in a comment on a threeten-github-issue:

如果我们真的很强硬,瞬间的toString就是1970-01-01Z的秒数。我们选择不做并且输出一个更友好的toString以帮助开发人员,但它并没有改变一个基本事实,即Instant只是一个秒数,并且不能转换为年/月/日没有某种时区。

人们可以喜欢这个设计决定(不像我),但结果是你不能要求瞬发年份,...,小时,...和偏移量。另请参阅支持字段的文档:

People can like this design decision or not (like me), but the consequence is that you cannot ask an Instant for year, ..., hour, ... and offset. See also the documentation of supported fields:

NANO_OF_SECOND 
MICRO_OF_SECOND 
MILLI_OF_SECOND 
INSTANT_SECONDS 

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

Here it is interesting what is missing, above all a zone-related field is missing. As a reason, we often hear the statement that objects like Instant or java.util.Date have no timezone. In my opinion this is a too simplistic view. While it is true that these objects have no timezone state internally (and there is also no need for having such an internal value), those objects MUST be related to UTC timezone because this is the basis of every timezone offset calculation and conversion to local types. So the correct answer would be: An Instant is a machine counter counting the seconds and nanoseconds since UNIX epoch in timezone UTC (per spec). The last part - relationship to UTC zone - is not well specified by JSR-310-team but they cannot deny it. The designers want to abolish the timezone aspect from Instant because it looks human-time-related. However, they can't completely abolish it because that is a fundamental part of any internal offset calculation. So your observation regarding

还有 Instant.atZone(区域)和<$ c $>的观察c> Instant.atOffset(offset)都生成一个值,该值与将Instant视为具有隐含的UTC时区/'零'偏移量一致。

"Also an Instant.atZone(zone) and an Instant.atOffset(offset) both produce a value that is consistent with treating the Instant as having an implied UTC time-zone/'zero' offset."

是对的。

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

While it might be very intuitive that ZoneOffset.from(anInstant) might produce ZoneOffset.UTC, it throws an exception because its from()-method searches for a non-existent OFFSET_SECONDS-field. The designers of JSR-310 have decided to do that in the specification for the same reason, namely to make people think that an Instant has officially nothing to do with UTC timezone i.e. "has no timezone" (but internally they must accept this basic fact in all internal calculations!).

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

For the same reason, OffsetDateTime.from(anInstant) and ZoneId.from(anInstant) fail, too.

关于 ZonedDateTime.from(anInstant)我们阅读

转换将首先获得一个ZoneId时间对象,必要时回退到ZoneOffset。然后它将尝试获取一个Instant,如果需要,可以回退到LocalDateTime。结果将是ZoneId或ZoneOffset与Instant或LocalDateTime的组合。

所以这个由于相同的原因,转换将再次失败,因为 ZoneId ZoneOffset 都不能从即时。异常消息显示为:

So this conversion will fail again due to the same reasons because neither ZoneId nor ZoneOffset can be obtained from an Instant. The exception message reads as:

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

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

Finally we see that all static from()-methods suffer from being unable to do a conversion between human time and machine time even if this looks intuitive. In some cases a conversion between let's say LocalDate and Instant is questionable. This behaviour is specified, but I predict that your question is not the last question of this kind and many users will continue to be confused.

真正的设计问题在我看来是这样的:

a)人的时间和机器时间之间不应该有明显的分离。像 Instant 这样的时态对象应该更像两者。量子力学中的一个类比:你可以将电子视为粒子和波。

a) There should not be a sharp separation between human time and machine time. Temporal objects like Instant should better behave like both. An analogy in quantum mechanics: You can view an electron both as a particle and a wave.

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

b) All static from()-methods are too public. Ihat is too easily accessible in my opinion and should better have been removed from public API or use more specific arguments than TemporalAccessor. The weakness of these methods is that people can forget to think about related timezones in such conversions because they start the query with a local type. Consider for example: LocalDate.from(anInstant) (in which timezone???). However, if you directly ask an Instant for its date like instant.getDate(), personally I would consider the date in UTC-timezone as valid answer because here the query starts from an UTC perspective.

c)总之:我绝对与JSR-310团队分享这个好主意避免本地类型和全局类型之间的转换,例如 Instant ,而不指定时区。我只是在API设计方面有所不同,以防止用户进行 timezone-less 转换。我首选的方法是限制from() - 方法,而不是说全局类型不应该与人工时间格式有任何关系,如calendar-date或wall-time或UTC-timezone-offset。

c) In conclusion: I absolutely share with the JSR-310-team the good idea to avoid conversions between local types and global types like Instant without specifying a timezone. I just differ when it comes to the API-design to prevent users from doing such a timezone-less conversion. My preferred way would have been to restrict the from()-methods rather than saying that global types should not have any relation to human-time-formats like calendar-date or wall-time or UTC-timezone-offset.

无论如何,由于保留了向后兼容性,所以每个想要使用新的java.time-API的人都将这个(不相关的)机器时间和人类时间之间的分离设计固定下来。必须忍受它。

Anyway, this (inconsequent) design of separation between machine time and human time is now set in stone due to preserving backward compatibility, and everyone who wants to use the new java.time-API has to live with it.

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

Sorry for a long answer, but it is pretty tough to explain the chosen design of JSR-310.

这篇关于Java SE 8 TemporalAccessor.from与java.time.Instant对象一起使用时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆