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

ale*_*oid 32 java openjdk java-8

这对我来说意外:

> 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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Yas*_*jaj 15

我对它看起来很合逻辑,对此感到不安。

这是该方法的代码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);
     }
Run Code Online (Sandbox Code Playgroud)

我们可以看到结果是通过乘以秒的秒数表示来计算的,出于明显的原因,一年在逻辑上不能始终如一地用秒数表示。


加成

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

  • @Jens在定义自己的时间刻度时,无论如何每天都有86400秒,是什么使您无法进一步定义每年有365天,无论如何?这就是全部,因为此时标已经使用了伪秒数,所以这不能解释为什么不支持YEARS单位。 (6认同)
  • @AlexeyRomanov Instant 定义了它自己的 Java 时间尺度。在这个时间尺度里,每天无论如何都有86400秒。这些秒始终与 SI 秒不匹配。只要你留在这个系统里,一天就被精确地定义了。 (2认同)

And*_*kyy 5

我猜这是因为 Instant 不包含有关时区的信息。这意味着同一个 Instant 可以被解释为不同时区的不同日期时间值。假设我们有 Instant 表示为 2016.01.01 00:30:00,比方说,UTC+2 时区。相同的 Instant 表示 UTC+1 时区中的 2015.12.31 23:30:00。2016 年是闰年,它的长度是 366 天,所以为了得到 Instant 减 1 年,我们必须从中减去 366 天。但是 2015 年不是闰年,它的长度是 365 天,所以我们必须从 Instant 中减去 365 天。这种歧义导致 Instant 不支持 ChronoUnit.YEARS。类似的问题导致 Instant 不支持 ChronoUnit.MONTHS。并且可能缺少 DST 信息导致 Instant 不支持 ChronoUnit.WEEKS。