将Period添加到startDate不会产生endDate

Ily*_*lya 8 period date-difference kotlin java-time localdate

我有两个LocalDate声明如下:

val startDate = LocalDate.of(2019, 10, 31)  // 2019-10-31
val endDate = LocalDate.of(2019, 9, 30)     // 2019-09-30
Run Code Online (Sandbox Code Playgroud)

然后我使用Period.between函数计算它们之间的周期:

val period = Period.between(startDate, endDate) // P-1M-1D
Run Code Online (Sandbox Code Playgroud)

此处的期间为负数的月份和天数,如果endDate早于,则可以预期startDate

但是,当我将其添加period回时startDate,得到的结果不是endDate,而是前一天的日期:

val endDate1 = startDate.plus(period)  // 2019-09-29
Run Code Online (Sandbox Code Playgroud)

所以问题是,为什么不不变

startDate.plus(Period.between(startDate, endDate)) == endDate

保留这两个日期?

Period.between谁返回了不正确的期限,还是LocalDate.plus谁添加了不正确的期限?

Evg*_*kin 6

如果您看如何plus实现LocalDate

@Override
public LocalDate plus(TemporalAmount amountToAdd) {
    if (amountToAdd instanceof Period) {
        Period periodToAdd = (Period) amountToAdd;
        return plusMonths(periodToAdd.toTotalMonths()).plusDays(periodToAdd.getDays());
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

你会看到plusMonths(...)plusDays(...)那里。

plusMonths处理一个月有31天,另一个有30天的情况。因此,将输出以下代码,2019-09-30而不是不存在的代码2019-09-31

println(startDate.plusMonths(period.months.toLong()))
Run Code Online (Sandbox Code Playgroud)

之后,减去一天将得出2019-09-29。这是正确的结果,因为2019-09-292019-10-31相隔1个月1天

Period.between计算是奇怪,在这种情况下,可以归结为

    LocalDate end = LocalDate.from(endDateExclusive);
    long totalMonths = end.getProlepticMonth() - this.getProlepticMonth();
    int days = end.day - this.day;
    long years = totalMonths / 12;
    int months = (int) (totalMonths % 12);  // safe
    return Period.of(Math.toIntExact(years), months, days);
Run Code Online (Sandbox Code Playgroud)

其中getProlepticMonth是从00-00-00的月份总数。在这种情况下,是1个月零1天。

从我的理解,这是一个错误Period.between,并LocalDate#plus为正负周期的互动,因为下面的代码具有相同的含义

val startDate = LocalDate.of(2019, 10, 31)
val endDate = LocalDate.of(2019, 9, 30)
val period = Period.between(endDate, startDate)

println(endDate.plus(period))
Run Code Online (Sandbox Code Playgroud)

但是它打印正确2019-10-31

问题在于LocalDate#plusMonths归一化日期总是“正确的”。在下面的代码中,您可以看到从2019-10-31结果中减去1个月后2019-09-31,将其标准化为2019-10-30

public LocalDate plusMonths(long monthsToAdd) {
    ...
    return resolvePreviousValid(newYear, newMonth, day);
}

private static LocalDate resolvePreviousValid(int year, int month, int day) {
    switch (month) {
        ...
        case 9:
        case 11:
            day = Math.min(day, 30);
            break;
    }
    return new LocalDate(year, month, day);
}
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

194 次

最近记录:

5 年,10 月 前