为什么Instant不支持使用ChronoUnit.YEARS进行操作?

时间:2016-10-07 01:15:21

标签: java java-8 openjdk

这对我来说意外:

> Clock clock = Clock.systemUTC();

> Instant.now(clock).minus(3, ChronoUnit.DAYS);
java.time.Instant res4 = 2016-10-04T00:57:20.840Z

> Instant.now(clock).minus(3, ChronoUnit.YEARS);
java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Years

作为一种解决方法,我必须这样做:

> Instant.now(clock).atOffset(ZoneOffset.UTC).minus(3, ChronoUnit.YEARS).toInstant();
java.time.Instant res11 = 2013-10-07T01:02:56.361Z

我很好奇为什么Instant不支持YEARS。开发人员是否放弃了它?

(在我的实际代码中,我试图减去Period.ofYears(3),但引用的Instant方法最终会被调用。)

2 个答案:

答案 0 :(得分:7)

我在看起来像是非常符合逻辑的东西。

以下是方法plus(long, TemporalUnit)的代码(在minus(...)中使用):

     @Override
     public Instant plus(long amountToAdd, TemporalUnit unit) {
         if (unit instanceof ChronoUnit) {
             switch ((ChronoUnit) unit) {
                 case NANOS: return plusNanos(amountToAdd);
                 case MICROS: return plus(amountToAdd / 1000_000, (amountToAdd % 1000_000) * 1000);
                 case MILLIS: return plusMillis(amountToAdd);
                 case SECONDS: return plusSeconds(amountToAdd);
                 case MINUTES: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_MINUTE));
                 case HOURS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_HOUR));
                 case HALF_DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY / 2));
                 case DAYS: return plusSeconds(Math.multiplyExact(amountToAdd, SECONDS_PER_DAY));
             }
             throw new UnsupportedTemporalTypeException("Unsupported unit: " + unit);
         }
         return unit.addTo(this, amountToAdd);
     }

我们可以看到结果是通过乘以秒的单位表示来计算的,由于显而易见的原因,一年不能在逻辑上和一致地用秒表示。

<强>加成

我可以看到另一个明显的原因:上面方法中使用的常量来自java.time.LocalTime。常量仅定义单位为天。没有定义上面的常数(仅LocalDateLocalDateTime)。

答案 1 :(得分:0)

我猜发生了,因为Instant不包含有关时区的信息。这意味着同一即时消息可以解释为不同时区中的不同日期时间值。假设我们有一个表示为2016.01.01 00:30:00的Instant(即UTC + 2时区)。相同的即时表示在UTC + 1时区的2015.12.31 23:30:00。 2016年是a年,其长度为366天,因此要获得Instant减去1年,我们必须从中减去366天。但是2015年不是a年,它的时长是365天,因此我们必须从Instant中减去365天。这种歧义导致Instant不支持ChronoUnit.YEARS。类似的问题导致Instant不支持ChronoUnit.MONTHS。可能缺少DST信息会导致Instant不支持ChronoUnit.WEEKS。