为什么 Instant 不支持 ChronoUnit.YEARS 的操作?

2022-08-31 17:02:57

这让我很意外:

> 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不支持YESTURE。开发人员只是放弃了吗?

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


答案 1

我正在尝试一下,在我看来,这是非常合乎逻辑的东西。

下面是该方法的代码(用于):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);
}

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


加法

我可以看到另一个明显的原因:上述方法中使用的常量来自。这些常量仅定义最多为天数的单位。没有定义高于天数的常量(in 和两者都不是)。java.time.LocalTimeLocalDateLocalDateTime


答案 2

我想发生这种情况是因为即时不包含有关时区的信息。这意味着同一即时可以解释为不同时区中的不同日期时间值。假设我们有 Instant,它表示为 2016.01.01 00:30:00,比方说 UTC+2 时区。相同的即时表示 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。


推荐