为什么不支持将周数添加到 java.time.Instant?

Why is adding weeks to java.time.Instant not supported?

下面这段代码:

Instant inFourWeeks = Instant.now().plus(4L, ChronoUnit.WEEKS);

抛出异常:

java.time.temporal.UnsupportedTemporalTypeException: Unsupported unit: Weeks

为什么不支持周? 我理解为什么不支持月和年,因为它们在较小单位中的持续时间可能会有所不同。但是 有固定的持续时间(7 天),我可以通过写来达到同样的目的:

Instant inFourWeeks = Instant.now().plus(4L * 7L, ChronoUnit.DAYS);

它抛出 UnsupportedTemporalTypeException 每周 7 天不是普遍且不变的。它可能因不同的日历系统而异。例如,查看每周使用 6 天的 Akan 日历系统。

如果您查看 plus(long, TemporalUnit) 的代码,它不支持 WEEK,

 @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);
     }

从代码中可以清楚地看出,结果是通过乘以单位的秒表示来计算的,Week/Month/year 不能在逻辑上和一致地用秒表示,因为根据 javadoc,这些不是通用常量。

Instant class 处理绝对时间,并尽量避免与不同日历系统、地区和文化 group解释它。

有些日历系统有不同的星期长度,有些有不同的月份分组,年份从不同的日期开始,并以不同的方式调整闰年和闰秒(如果有的话,就像儒略历有太多的闰年,偏离了它们本应与之同步的 'physical' 现象,例如季节、至日和春分)。

为了避免这些问题,Instant class 允许您使用更精确定义和标准化的单位,例如秒、分钟、小时和天。

闰秒 'smoothened' 在 Java 出现的那一天的最后 1000 秒内,因此从程序员的角度来看它们不存在。 (反正电脑时钟不是那么准确,需要经常和NTP同步。)

假设 1 天为 24 SI 小时,1 SI 小时定义为 60 SI 分钟,1 SI 分钟定义为 60 SI 秒,1 SI 秒为 Caesium-133 的 9,192,631,770 个辐射周期。 24小时实际上是平均太阳日(两个连续'noons'之间经过的时间),因为由于椭圆轨道、太阳本身的轨道和轨道速度的变化,每个太阳日可能会稍微长一些或短一些。

您必须注意的一件重要事情是夏令时。在那些特殊的日子里,一天是 25 小时或 23 小时,这取决于时钟移动的方向。然而,Instant class 并不关心这个,如果你在夏令时边界上增加 1 天,它仍然会移动 24 小时。它不包含任何时区或区域信息(DST 是特定于国家/地区的)。

ChronoUnit.WEEKS 可以在除 ISO 日历之外的其他日历系统中使用数周。这样的周可能长达 6 天或 10 天。因此,虽然 可能 认为 Instant 支持天数是有道理的,但对于数周来说情况并非如此。

来自文档:

Unit that represents the concept of a week. For the ISO calendar system, it is equal to 7 days.

When used with other calendar systems it must correspond to an integral number of days.

由此可见,WEEKS通常不采用 ISO 日历系统,也可以与其他日历一起使用。

论点的另一部分是 Instant 不假定一个日历系统,但也可以与不同的日历系统一起使用。 (相比之下,例如,ZonedDateTime 假设 ISO-8601 日历系统支持周。)

PS 我宁愿反过来问这个问题:为什么 Instant 支持天数?一天可能是 23、23.5、24、24.5 或 25 小时,历史上也可能是其他持续时间。

Link: Documentation of ChronoUnit.WEEKS.

其他答案正确。我要补充一点说明。

Instant 是基本积木

Instant class 是 java.time class 中的基本构建块。它代表一个时刻,时间轴上的一个点。在内部,它只是自 UTC 1970 年第一时刻的纪元参考以来的整秒计数。所以这个 class 不应该有什么功能。

此构建块可用于在许多可能的日历系统中的任何一个中跟踪时刻。理解 Instant,将其视为日期、周、月等取决于特定日历系统的定义。日历系统可以定义一周中的任意天数,或一年中的任意月数,等等,或者甚至没有这样的概念 或月份。

最明显的日历系统是在西方和世界其他地区使用的现代 ISO 8601。 OffsetDateTime & ZonedDateTime classes 建立在 Instant 之上,构成了这个 ISO 日历系统的关键部分。这些 classes 与 Instant 捆绑在一起仅仅是因为它们预计会被许多 Java 程序员普遍使用。但它们绝不是唯一的日历系统。

查看这些不同日历系统的 java.time.chrono 包:

  • HijrahChronology
    Hijrah calendar是支持伊斯兰历的农历。
  • IsoChronology
  • JapaneseChronology
    日本皇历系统。
  • MinguoChronology
    Minguo calendar系统。
  • ThaiBuddhistChronology
    泰国佛历。

ThreeTen-Extra 项目为 java.time class 提供了额外的功能。这包括更多日历系统:

  • AccountingChronology
    符合美国国税局第 538 号出版物和国际财务报告标准的 52/53 周会计日历系统。
  • BritishCutoverChronology
    英国儒略-格里高利转换日历系统。
  • CopticChronology
    Coptic calendar系统。
  • DiscordianChronology
    Discordian calendar系统。
  • InternationalFixedChronology
    International Fixed calendar系统。也称为伊士曼柯达日历。
  • JulianChronology
    先进的儒略历系统,现代公历和 ISO 日历的先驱。
  • PaxChronology
    Pax calendar系统。
  • Symmetry010Chronology
  • Symmetry454Chronology
    Symmetry454 calendar系统。

可能还有更多我不知道的第三方。