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

Java SE 8 TemporalAccessor.from与Java.time.Instant对象一起使用时出现问题,java,java-8,java-time,Java,Java 8,Java Time,java.time有一个类,它封装了时间线上的位置(或“时刻”)。虽然我知道这是一个秒/纳秒值,因此与时区或时间偏移量没有直接关系,但它的toString返回一个格式化为UTC日期/时间的日期和时间,例如2014-05-13T20:05:08.556Z。另外,anistant.atZone(zone)和anistant.atOffset(offset)都会生成一个值,该值与将即时视为具有隐含的UTC时区/“零”偏移一致 因此,我原以为: ZoneOffset.from(instant)生成“零

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

因此,我原以为:

  • ZoneOffset.from(instant)
    生成“零”
    ZoneOffset
  • OffsetDateTime.from(一个实例)
    生成偏移量为“零”的日期/时间
  • ZoneId.from(暂时)
    (可能)生成UTC
    ZoneId
  • ZonedDateTime。从(一个实例)
    (可能)生成一个带有UTC
    ZoneId的
    ZonedDateTime
在我读到的文档中,似乎认可了这一点

事实上,
ZoneOffset.from(anistant)
会因
DateTimeException
而失败,我想正是由于这个原因,
OffsetDateTime.from(anistant)
也会失败,其他两个也一样


这是预期的行为吗?

即时
类没有时区。它像在UTC区域中一样打印,因为它必须在某个区域中打印(您不希望它以记号打印,是吗?),但这不是时区-如以下示例所示:

Instant instant=Instant.now();
System.out.println(instant);//prints 2014-05-14T06:18:48.649Z
System.out.println(instant.atZone(ZoneId.of("UTC")));//prints 2014-05-14T06:18:48.649Z[UTC]
ZoneOffset.from
OffsetDateTime.from
的签名接受任何时间对象,但对于某些类型,它们失败
java.time
似乎没有针对具有时区或偏移量的时间段的接口。这样的接口可以声明
getOffset
getZone
。由于我们没有这样的接口,这些方法在多个地方分别声明

如果您有一个
zoneDateTime
,您可以调用它的
getOffset
。如果您有一个
OffsetDateTime
,您也可以调用它的offset-但是这是两个不同的
getOffset
方法,因为这两个类不是从公共接口获取该方法的。这意味着,如果你有一个
时态的
对象,它可能是其中的一个,那么你必须测试它是否是这两个对象的
实例,以获得偏移量


OffsetDateTime.from通过为您这样做简化了过程,但由于它也不能依赖于公共接口,因此它必须接受任何
临时的
对象,并为那些没有偏移的对象抛出异常。

简短回答:

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

OffsetDateTime#toInstant():Instant
ZonedDateTime#toInstant():Instant
Instant#atOffset(ZoneOffset):OffsetDateTime
Instant#atZone(ZoneId):ZonedDateTime
静态from()方法的问题在于,否则人们可以在
即时
和例如
LocalDateTime
之间进行转换,而不考虑时区

长答案:

<>是否考虑“代码>即时/代码>作为计数器或字段元组,JSR-310团队给出的答案是所谓的机器时间和人类时间之间的严格分离。事实上,他们打算有一个严格的分离-看他们的。最后,他们希望
即时
仅被解释为机器时间计数器。因此,他们故意设计了一个不能要求年、小时等字段的
Instant

但事实上,JSR-310团队根本不一致。他们已经将方法
Instant.toString()
实现为一个字段元组视图,包括年、、小时、。。。和偏移符号Z(表示UTC时区)(脚注:在JSR-310之外,在此类机器时间上有基于字段的外观是很常见的-例如,请参见Wikipedia或其他网站上的关于)。规范负责人S.Colebourne曾在一篇评论中说:

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

人们可能喜欢或不喜欢这个设计决策(像我一样),但结果是你不能要求年、小时和偏移量的
即时
。另请参阅支持字段的文档:

NANO_OF_SECOND 
MICRO_OF_SECOND 
MILLI_OF_SECOND 
INSTANT_SECONDS 
有趣的是,这里缺少了什么,最重要的是缺少了一个与区域相关的字段。作为一个原因,我们经常听到这样的说法,像
Instant
java.util.Date
这样的对象没有时区。
在我看来,这是一个过于简单的观点。虽然这些对象在内部没有时区状态,这是事实(也不需要有这样的内在价值),这些对象必须与UTC时区相关,因为这是每个时区偏移计算和转换为本地类型的基础。因此正确的答案应该是:
Instant
是一个机器计数器,以UTC时区计算UNIX历元以来的秒数和纳秒数(根据规范)。最后一部分——与UTC区域的关系——JSR-310-team没有明确规定,但他们无法否认。设计师希望从
即时
取消时区方面,因为它看起来与人类时间相关。
但是,他们不能完全取消它,因为这是任何内部偏移计算的基本部分.那么你的观察
LocalDateTime.ofInstant(myDate.toInstant(), ZoneId.systemDefault())