java - IsoChronology 闰年的天数

标签 java java-time days period date-difference

2000 CE 是闰年,有 366 天。 2001 CE 和 2002 CE 没有闰年,有 355 天。

从逻辑上讲,如果我询问公元 2000 年 1 月 1 日到公元 2001 年 1 月 1 日之间的天数,我应该比公元 2001 年 1 月 1 日到 2002 年 1 月 1 日之间多一天。

这不是我观察到的,请参阅下面的代码。

        IsoChronology isoc = IsoChronology.INSTANCE;

        LocalDate date1;
        LocalDate date2;
        Period period;

        // Between January 1st, 0 CE and January 1st, 1 CE

        date1 = isoc.dateYearDay(2000, 1);
        date2 = isoc.dateYearDay(2001, 1);
        period = Period.between(date1, date2);

        assertTrue(isoc.isLeapYear(2000L));
        assertFalse(isoc.isLeapYear(2001L));
        assertEquals("2000-01-01", date1.toString());
        assertEquals("2001-01-01", date2.toString());
        assertEquals("P1Y", period.toString());

        // Between January 1st, 1 CE and January 1st, 2 CE

        date1 = isoc.dateYearDay(2001, 1);
        date2 = isoc.dateYearDay(2002, 1);
        period = Period.between(date1, date2);

        assertFalse(isoc.isLeapYear(2001L));
        assertFalse(isoc.isLeapYear(2002L));
        assertEquals("2001-01-01", date1.toString());
        assertEquals("2002-01-01", date2.toString());
        assertEquals("P1Y", period.toString());

编辑

修改示例以使用 400 CE、401 CE 和 402 CE,因为 0 CE 不是“真实”年份(1 BCE 和 1 CE 是真实的,但 0 BCE = 1 CE 和 1 BCE = 0 CE)。

编辑

将示例修改为使用 2000 CE、2001 CE 和 2002 CE,以使用(非预见性)公历中的年份。

另外删除了不相关的信息。

编辑

Period.toString() 包括非 0 的天数。 Period.of(1/* 年/, 0/月/, 1/天 */) 呈现为 P1Y1D,因此我预计其中一个示例与另一个示例不同。

补充

根据ISO年表和周期,2001年1月28日之后的一个月零一天是2001年3月1日。但在该日期之前的一个月零一天是2001年1月31日。

因此,在这种情况下,我们的结束时间比开始时间晚了 3 天。

在本例中,在闰年,我们将在同一日期结束。

        IsoChronology chronology = IsoChronology.INSTANCE;

        Period oneMonthOneDay = Period.of(0, 1, 1);

        Temporal january28th2001 = chronology.date(2001, 1, 28);
        Temporal march1st2001 = oneMonthOneDay.addTo(january28th2001);
        Temporal january31th2001 = oneMonthOneDay.subtractFrom(march1st2001);
        Assert.assertEquals("2001-01-28", january28th2001.toString());
        Assert.assertEquals("2001-03-01", march1st2001.toString());
        Assert.assertEquals("2001-01-31", january31th2001.toString());

        Temporal january28th2004 = chronology.date(2004, 1, 28);
        Temporal february29th2004 = oneMonthOneDay.addTo(january28th2004);
        Temporal january28th2004Again = oneMonthOneDay.subtractFrom(february29th2004);
        Assert.assertEquals("2004-01-28", january28th2004.toString());
        Assert.assertEquals("2004-02-29", february29th2004.toString());
        Assert.assertEquals("2004-01-28", january28th2004Again.toString());

最佳答案

从技术上讲,这并没有错。 2000年1月1日至2001年1月1日期间,为“1年”(“P1Y”)期间。在2001-01-01和2002-01-01之间,也是“1年”(“P1Y”)期间。 没有任何地方说 365 或 366 。您实际上无法从您拥有的周期中获得数字 365 或 366。

您并不是在问这里的两个日期之间有多少:

Period.between(date1, date2)

您正在询问期间。

Period 是若干年、月和日,您恰好得到“1 年 0 月 0 天”的周期作为输出。

请注意,周期计算与您在数学中习惯的计算有很大不同。在 2 月 1 日上添加“1 个月”会增加 28 或 29 天,但在 3 月 1 日上添加“1 个月”会增加 30 天。这也意味着在一个日期中添加 10 次“1 个月”可能会与一次添加“10 个月”得到不同的结果。

您可能想知道为什么 Period. Between 不提供日期之间的天数,而只是显示“1 年”。首先,请注意“1 年”和“365 天”是非常不同的时期。在 2020-01-01 中添加“1 年”将得到 2021-01-01,但在 2020-01-01 中添加“365 天”将得到 2020-12-31。

如果 Period. Between 返回“365 天”或“366 天”,则您将无法这样做,例如轻松地要求用户输入两个日期,并继续以该间隔输出日期。考虑:

public void iterateDatesAtRegularInterval(LocalDate date1, LocalDate date2) {
    Period p = Period.between(date1, date2);
    LocalDate current = date2;
    while (some end condition) {
        current = current.plus(p);
        System.out.println(current);
    }
}

如果 Period. Between 返回“365 天”或“366 天”,而我碰巧经过了 2020-01-01 和 2021-01-01(366 天),那么接下来的事情是方法的输出将是 2022-01-02,IMO 对于大多数人来说是非常出乎意料的。

Period. Between 基本上会选择它可以选择的最大单位,因为如果您正在进行周期计算,这很可能对您最有用。

如果您想要 365/366 天的结果,请不要使用Period。使用类似的东西:

assertEquals(365L, ChronoUnit.DAYS.between(date1, date2))

关于java - IsoChronology 闰年的天数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67344410/

相关文章:

php - Codeigniter 剩余天数 mysql 查询

java - Java 中的天数转换

java - 无法通过 Windows 10 和 DLINK DIR-615 路由器中的 Java 代码获取 DNS 请求

java - @Immutable with @Entity and insertable=false and updateable=false on @Column

java - 是否有一个 java 类代表两个瞬间之间的范围?

java - 将 Joda 时间 Instant 转换为 Java 时间 Instant

java - 在 Android 中获取本周的日期

java - 如何在订阅开始时显示对话框?

java - 为什么下面的代码有死锁?

java - JSR-310 中两种不同的基于周的年定义的动机是什么?