Java Calendar类月份设置出现异常不一致现象
问题原因详解
这个问题其实是Java Calendar类的两个经典特性在“搞鬼”——0-based的月份索引,加上它特有的延迟计算+自动日期调整机制,咱们一步步拆解来看:
1. 先搞懂Calendar的月份计数
首先得明确一个容易踩坑的点:Calendar的月份是从0开始计数的!Calendar.JANUARY对应0,Calendar.FEBRUARY对应1,Calendar.MARCH对应2……所以你代码里写的set(Calendar.MONTH, 1),设置的是二月,不是一月。
2. 延迟计算+宽松模式的自动调整
Calendar默认是宽松模式,而且采用延迟计算逻辑:当你调用set()修改字段时,它不会立刻更新整个日历的时间戳,只有当你调用get()、getTime()这类需要读取实际日期的方法时,才会统一计算并处理无效的日期。
咱们把你的代码执行流程拆解开(假设当前系统日期是有31天的月份,比如3月31日):
- 第一步:
Calendar.getInstance()拿到当前日期:202X年3月31日。 - 第一次调用
calendar.set(Calendar.MONTH, 1):只是把月份字段标记为1(二月),但Calendar此时不会校验日期是否合法。 - 第一次调用
calendar.get(Calendar.MONTH):触发日期计算逻辑。这时候它发现,当前的日是31,但二月最多只有28或29天(平年28,闰年29),这个日期无效。在宽松模式下,Calendar会自动“修复”这个日期:把月份加1(变成三月,对应索引2),然后用31减去二月的最大天数(比如28),得到3,最终日期变成202X年3月3日。所以这时候get(MONTH)返回的是2。 - 第二次调用
calendar.set(Calendar.MONTH, 1):此时Calendar的当前日期是3月3日,设置月份为1(二月),二月肯定有3号,这个日期完全合法。 - 第二次调用
calendar.get(Calendar.MONTH):计算后日期是202X年2月3日,月份索引是1,所以返回1。
如何避免这类坑?
如果你想严格控制日期,不想让它偷偷调整,可以关闭宽松模式:
calendar.setLenient(false);
这样当你设置无效日期时,会直接抛出IllegalArgumentException,而不是默默调整。另外,更推荐你使用Java 8及以后的java.time包(比如LocalDate、Month枚举),这些类的设计更直观,没有0-based月份的坑,也不会有这种隐式的日期调整问题,代码可读性和安全性都高很多。
内容的提问来源于stack exchange,提问作者redochka
相关产品推荐
相关产品推荐

