You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调用getTime会改变Calendar值?求解释该异常日期计算行为

哇,这个问题戳中了Java老版Calendar类最反直觉的坑之一!让我给你掰扯清楚背后的原因:

核心根源:Calendar的延迟计算机制

Java的Calendar类采用**延迟计算(Lazy Evaluation)**设计:当你调用set()修改字段时,它不会立刻更新内部的时间戳,只是标记字段为“已修改”;只有当你调用getTime()、getTimeInMillis()这类需要获取实际时间的方法时,才会重新计算并同步所有日期字段。

结合Locale.GERMANY的周规则(一周从周一开始,而不是周日),两个示例的差异就源于这个机制:

示例1为什么会跳转到2018年?

看这段代码:

Calendar calendar = Calendar.getInstance(Locale.GERMANY);
calendar.set(2017, 11, 11); // 注意:Calendar月份是0基,11代表12月,即2017-12-11
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(calendar.getTime().toString());

你连续调用了两次set(),但没有触发计算。此时Calendar内部只记录了两个修改:DATE=11和DAY_OF_WEEK=SUNDAY,但这两个字段是冲突的(2017-12-11实际是周一)。

当最后调用getTime()触发计算时,Calendar需要解决这个冲突。由于延迟计算导致的字段不同步,它没有正确识别2017-12-11所在的周(周一到周日:12-11至12-17),反而因为Locale.GERMANY的周规则和字段优先级处理逻辑,错误地将日期调整到了下一年的第一个符合条件的周日——2018年1月7日。

示例2为什么正确?

Calendar calendar2 = Calendar.getInstance(Locale.GERMANY);
calendar2.set(2017, 11, 11);
calendar2.getTime(); // 关键!触发计算,同步所有字段
calendar2.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(calendar2.getTime().toString());

调用getTime()后,Calendar已经完成了计算,明确了2017-12-11是周一,属于12月11日到17日的周。此时再设置DAY_OF_WEEK=SUNDAY,它就会精准调整到该周的最后一天(周日,12-17)——因为所有字段已经同步,没有冲突。

这是预期行为吗?

严格来说,这是Calendar类文档中明确的行为,但完全不符合直观预期。Calendar的延迟计算和字段冲突处理逻辑一直是Java日期API的历史遗留问题,这也是Java 8引入全新java.time API(比如LocalDate、WeekFields)的重要原因之一。

如果用Java 8+的API实现你的需求,代码会更清晰且无歧义:

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        LocalDate date = LocalDate.of(2017, 12, 11);
        // 按德国周规则(周一为周起始),获取所在周的周日
        LocalDate sunday = date.with(TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));
        System.out.println(sunday); // 输出:2017-12-17
    }
}

内容的提问来源于stack exchange,提问作者mzl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 06:41:22