为什么 Instant 不支持 ChronoUnit.YEARS 的操作?
Why Instant does not support operations with ChronoUnit.YEARS?
这出乎我的意料:
> 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 方法是最后被调用的方法)。
我正在试一试在我看来非常合乎逻辑的东西。
这里是方法 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
。常量仅定义以天为单位的单位。没有定义以上天数的常量(在 LocalDate
和 LocalDateTime
中都没有)。
我猜这是因为 Instant 不包含有关时区的信息。这意味着相同的 Instant 在不同的时区可以解释为不同的 date-time 值。假设我们有 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.
这出乎我的意料:
> 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 方法是最后被调用的方法)。
我正在试一试在我看来非常合乎逻辑的东西。
这里是方法 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
。常量仅定义以天为单位的单位。没有定义以上天数的常量(在 LocalDate
和 LocalDateTime
中都没有)。
我猜这是因为 Instant 不包含有关时区的信息。这意味着相同的 Instant 在不同的时区可以解释为不同的 date-time 值。假设我们有 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.