java - ZonedDateTime 返回某个日期到另一个结束日期的错误月数

标签 java android time java-time

使用 ZonedDateTime.until 返回给定日期到给定结束日期的错误月数。看起来像是与二月有关;)

这是我写的测试

    @Test
    fun `three months from end of november till first of march`() {
        val dateOfNow = LocalDate.of(2022, 11, 30)
        val timeOfNow = LocalTime.of(0, 0, 0, 1)
        val dateTimeOfNow = LocalDateTime.of(dateOfNow, timeOfNow)
        val timeZoneOfTestland = ZoneOffset.of("+00:00")
        val zonedDateTimeOfNow = dateTimeOfNow.atZone(timeZoneOfTestland)

        val dateEnd = LocalDate.of(2023, 3, 1)
        val timeEnd = LocalTime.of(0, 0, 0, 0)
        val dateTimeEnd = LocalDateTime.of(dateEnd, timeEnd)
        val zonedDateEnd = dateTimeEnd.atZone(timeZoneOfTestland)

        val until = zonedDateTimeOfNow.until(zonedDateEnd, ChronoUnit.MONTHS)
        assertEquals(3, until)
    }

它返回 2,而不是预期的 3。

当我更改 dateTimeOfNow 的纳秒时测试成功

    val timeOfNow = LocalTime.of(0, 0, 0, 0)

但是当我将日期设置为 11 月 29 日时,它再次失败

    val dateOfNow = LocalDate.of(2022, 11, 29)
    val timeOfNow = LocalTime.of(0, 0, 0, 1)

在我看来,距离 2023 年 3 月 1 日显然还有 3 个月的时间。无论如何。

我使用这些日期尝试了没有更改年份的情况

    val dateOfNow = LocalDate.of(2022, 1, 31)
    val timeOfNow = LocalTime.of(0, 0, 0, 1)
    val dateTimeOfNow = LocalDateTime.of(dateOfNow, timeOfNow)
    val timeZoneOfTestland = ZoneOffset.of("+00:00")
    val zonedDateTimeOfNow = dateTimeOfNow.atZone(timeZoneOfTestland)

    val dateEnd = LocalDate.of(2022, 5, 1)
    val timeEnd = LocalTime.of(0, 0, 0, 0)
    val dateTimeEnd = LocalDateTime.of(dateEnd, timeEnd)
    val zonedDateEnd = dateTimeEnd.atZone(timeZoneOfTestland)

    val until = zonedDateTimeOfNow.until(zonedDateEnd, ChronoUnit.MONTHS)
    assertEquals(3, until)

但它也会失败,并使用 until == 2 而不是 3

对此有何解释?

最佳答案

查看 OffsetDateTime#until 中的以下文档(强调我的):

The calculation returns a whole number, representing the number of complete units between the two date-times. For example, the amount in months between 2012-06-15T00:00Z and 2012-08-14T23:59Z will only be one month as it is one minute short of two months.

在您的情况下,差异是由于 1 纳秒造成的。请记住,2023-02-29 和 2023-02-30 不存在。

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

public class Main {
    public static void main(String[] args) {
        // 2 months
        // 2022-11-30T0:0:0:1 to 2022-12-30T0:0:0:1 - complete
        // 2022-12-30T0:0:0:1 to 2023-01-30T0:0:0:1 - complete
        // 2023-01-30T0:0:0:1 to 2023-03-01T0:0:0:1 would have been one month but
        // the endtime is 2023-03-01T0:0:0:0, 1 nanosecond short
        System.out.println(LocalDateTime.of(2022, 11, 30, 0, 0, 0, 1).until(LocalDateTime.of(2023, 3, 1, 0, 0, 0, 0),
                ChronoUnit.MONTHS));

        // 3 months as explained above
        System.out.println(LocalDateTime.of(2022, 11, 30, 0, 0, 0, 1).until(LocalDateTime.of(2023, 3, 1, 0, 0, 0, 1),
                ChronoUnit.MONTHS));

        // 3 months
        // 2022-11-30T0:0:0:0 to 2022-12-30T0:0:0:0 - complete
        // 2022-12-30T0:0:0:0 to 2023-01-30T0:0:0:0 - complete
        // 2023-01-30T0:0:0:0 to 2023-03-01T0:0:0:0 - complete
        System.out.println(LocalDateTime.of(2022, 11, 30, 0, 0, 0, 0).until(LocalDateTime.of(2023, 3, 1, 0, 0, 0, 0),
                ChronoUnit.MONTHS));

        // 3 months
        // 2022-11-28T0:0:0:1 to 2022-12-28T0:0:0:1 - complete
        // 2022-12-28T0:0:0:1 to 2023-01-28T0:0:0:1 - complete
        // 2023-01-28T0:0:0:1 to 2023-02-28T0:0:0:1 - complete
        System.out.println(LocalDateTime.of(2022, 11, 28, 0, 0, 0, 1).until(LocalDateTime.of(2023, 3, 1, 0, 0, 0, 0),
                ChronoUnit.MONTHS));
    }
}

输出:

2
3
3
3

关于java - ZonedDateTime 返回某个日期到另一个结束日期的错误月数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74689728/

相关文章:

java - 错误 : (-13:Image step is wrong) Step must be a multiple of esz1 in function 'cv::Mat::Mat'

Java:跟踪用户登录 session - session EJB 与 HTTPSession

JavaFX 独立启动应用程序或从另一个应用程序启动

android - 无法获取 httpPost 参数但可以从 php 获取 httpGet

java - SQLite 数据库 : Android studio custom auto incrementation

java - Android 7 - 以编程方式设置代理

time - 时间标签中的今天时间

java - jOOQ 转换器和类型

c++ - 在 C++ 中将 `time_t` 转换为十进制年份

java - 时差忽略时区差异