我有以下代码来计算从今天起 6 个月后的星期几。
// Java code
Date currentDate = (new SimpleDateFormat("yyyy-MM-dd")).parse("2024-08-30");
Calendar calendar = Calendar.getInstance();
calendar.setTime(currentDate);
calendar.add(Calendar.MONTH, 6);
Date sixMonthsLaterDate = calendar.getTime();
String sixMonthsLaterDateString = new SimpleDateFormat("yyyy-MM-dd").format(sixMonthsLaterDate);
System.out.println("sixMonthsLaterDateString: " + sixMonthsLaterDateString); // returns 2025-02-28
在 Java 中,它返回“2025-02-28”
// PHP code
$currentDate = date_create_from_format('Y-m-d', '2024-08-30');
$sixMonthsLaterDate = $currentDate->modify('+6 month');
$sixMonthsLaterDateString = date_format($sixMonthsLaterDate, 'Y-m-d');
echo "sixMonthsLaterDateString: $sixMonthsLaterDateString"; // returns 2025-03-02
在 PHP 中,它返回“2025-03-02”
为什么它们不同?有人能解释一下吗?谢谢!
总结
请参阅在 Ideone.com 上运行的此代码。
避免使用遗留的日期时间类
您使用的日期时间类存在严重缺陷,现已过时。几年前,它们已被JSR 310 中定义的现代java.time类取代。
LocalDate
对于仅限日期的值,请使用
java.time.LocalDate
。指定六个月的
Period
课程。添加。
解释与 PHP 的区别
正如评论中所述,计算月份是一个棘手的问题。在ISO 8601日历系统中,现代月份的长度分别为 28、29、30 和 31 天。
Java 方法
java.time框架尝试考虑日历月份,而不是添加任意数量的天数,例如
( 6 * 30 )
。该算法在的 Javadoc 中有描述
LocalDate#plusMonths
。引用如下:就您的示例输入而言
2024-08-30
,八月之后的第六个月是二月。然后我们考虑月份中的日期。但是二月没有 30 日。那一年的二月也没有 29 日。二月的最后一个有效日期是 28 日。瞧,2025-02-28 就是解决方案。PHP 方法
我不知道你的 PHP 库在做什么。它没有考虑日历月。它没有添加 6 * 30 天,也没有添加 6 * 31 天。
C3roe 的此评论对 PHP 行为进行了解释,但我尚未研究过。引用如下:
在这种方法中,“溢出”的两天是不存在的 29 和 30。将这两天添加到 2025 年 2 月 28 日,您将得到 3 月 2 日。
如果这确实是 PHP 方法的算法,那么在我看来这很奇怪。这将是一个混杂的混合方法,既不完全考虑日历月份,也不精确计算天数。这种方法解决了上个月(本例中为二月)的“额外”天数,但忽略了中间月份(本例中为九月至一月)长度的变化。
正确的解决方案
我们已经看到了以下按月向前/向后移动时间的方法:
可能还存在其他方法。那么哪种方法才是正确的呢?
正确的方法是……无论你的应用项目中的堆栈持有者怎么说。你应该始终向项目中的领域专家提出此类日期时间问题。他们可能是运输代理、物流协调员、会计师等。让他们指定月份计数应如何操作。我建议让他们以书面形式这样做。然后将这些规则复制到代码库的注释中。