使用 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/