Calendar#add(Calendar.MONTH, months) 和 LocalDate#plusMonth(months) 之间有什么不同的行为吗?

Is there any different behavior between Calendar#add(Calendar.MONTH, months) and LocalDate#plusMonth(months)?

我正在处理一些遗留代码,其中 java.util.Calendar 用于与日期相关的计算(基本上是添加月份)。现在我想在代码中用 java.time.LocalDate 替换 java.util.Calendar 但我不想改变行为。所以,我一直在寻找一个来源,它澄清了它们对任何情况下的相同计算都会产生相同的结果,但我找不到任何来源。

特别是我想知道是否有一个日期使它们产生不同的结果:

Calendar#add(Calendar.MONTH, months)

LocalDate#plusMonth(months)

我测试了一些极端情况(例如与闰年相关的日期),它们似乎产生了相同的结果,但我不能 100% 确定这一点。是否有关于此的任何官方信息或它们之间的一些已知差异?

TL;DR

如果:

  • 你确定你的Calendar is really a GregorianCalendar(目前最常用的subclass),以及...
  • 你的约会不会超过 100 年前,那么……

…你可以安全地使用LocalDate#plusMonth(months) instead of Calendar#add(Calendar.MONTH, months).

详情

祝贺您决定从旧的和设计不佳的 Calendar class 迁移到 java.time 的 LocalDate,现代的 Java 日期和时间API。这将改进您的代码库。

你是对的,你说的方法是同一个目的,大体上是一样的。因此,当您从 Calendar 迁移到 java.time 时,如果您发现 LocalDate 是正确的新 class 使用,那么您将在您使用的地方使用 LocalDate#plusMonth(months) Calendar#add(Calendar.MONTH, months)之前。

差异包括:

  • Calendar class is an abstract superclass for classes representing dates (and times) in many different calendar systems (Gregorian, Buddhist 及更多),LocalDate 总是在公历中。由于每个日历系统都有自己对月份的定义,因此在公历以外的日历中添加月份数可能会得出与 LocalDate.plusMonths 给出的结果截然不同的结果。
  • 如果您的日期可以追溯到历史上,那么 LocalDateproleptic Gregorian calendar. This means that it doesn’t use the Julian calendar 用于几个世纪前使用的日期也会有细微差别。
  • 虽然 Calendar.add 修改了您调用它的 Calendar 对象,但 LocalDate.plusMonths returns a new LocalDate 具有新日期的对象。
  • 虽然要在日历中倒退,您需要将负数的月份传递给 Calendar::add, LocalDate has a convenient minusMonths 方法,您通常希望使用该方法而不是 plusMonths(尽管两者都有效)。
  • 每个class可以表示的日期范围是不同的。我不太记得每个日期的最小和最大日期。在 Calendar/GregorianCalendar 上,查看他们的各种方法,例如 getGreatestMinimum​getLeastMaximum​。对于 LocalDate,请参阅常量:MAX & MIN