使用 IsoChronology 的闰年天数

问题描述

公元 2000 年是闰年,有 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,date2);

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

编辑

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

编辑

修改了使用公元 2000 年、公元 2001 年和公元 2002 年的示例,以使用(非预兆的)公历中的年份。

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

编辑

Period.toString() 包括它们不为 0 的天数。Period.of(1 /* year /,0 / month /,1 / days */) 呈现为 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,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,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-01-01 和 2001-01-01 之间是“1 年”(“P1Y”)期间。在 2001-01-01 和 2002-01-01 之间,它是也是“1 年”(“P1Y”)的时期。 无处是否说 365 或 366 。您实际上无法从您拥有的 period 中获得数字 365 或 366。

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

Period.between(date1,date2)

您要求的是句号。

A Period 是年、月和日的数量,而您恰好将“1 年 0 月 0 天”作为输出。

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

您可能想知道为什么 Period.between 不给您日期之间的天数,而只是说“1 年”。首先,请注意“1 年”和“365 天”是非常不同的时期。将“1 年”添加到 2020-01-01 将得到 2021-01-01,但将“365 天”添加到 2020-01-01 将得到 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))

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...