在Java里Calendar类如何进行日期计算_Java时间操作方式说明
发布时间 - 2026-02-02 00:00:00 点击率:次Calendar.add()会自动进位/借位并传播溢出,而set()和roll()不会;必须调用getTime()获取结果;现代Java应优先使用java.time API。
Calendar.add() 是最常用也最容易出错的日期计算方式
直接修改 Calendar 实例的字段(如 set())不会触发自动进位或借位,而 add() 会——比如给 1 月 31 日加 1 个月,结果是 2 月 28/29 日(取决于闰年),不是 2 月 31 日报错。但很多人误以为它和 roll() 一样只影响当前字段。
-
add()会“溢出传播”:加天数可能影响月、年;加月可能影响年;加小时可能影响日 -
roll()不传播:对 1 月 31 日roll(Calendar.MONTH, 1),结果仍是 1 月 28/29/30/31 日(只在 1 月内滚动) - 必须调用
getTime()获取计算后的Date,否则字段变更未生效(Calendar是可变对象,但内部状态需显式提取)
Calendar cal = Calendar.getInstance(); cal.set(2025, Calendar.JANUARY, 31); // 注意:月份从 0 开始 cal.add(Calendar.MONTH, 1); // 得到 2025-02-28 Date result = cal.getTime(); // 必须调用!
为什么 new GregorianCalendar().add() 后 getTime() 还是旧时间?
常见错误是重复使用同一个 Calendar 实例却忘记重置或未正确初始化。更隐蔽的问题是时区和默认 Locale 导致的隐式行为差异——比如在某些 JVM 环境下,getInstance() 返回的 GregorianCalendar 可能启用 lenient 模式,允许非法日期临时存在,直到你调用 getTime() 才真正校正。
- 默认
lenient = true:设 2025-02-30 会被静默转为 2025-03-02,不报错但结果意外 - 设
cal.setLenient(false)后,非法日期设置会立即抛IllegalArgumentException - 构造后立刻
clear()再set(),避免残留字段干扰(尤其复用实例时)
Calendar 计算跨月/跨年时的时区陷阱
Calendar 的所有计算都基于其内部 TimeZone,但 add() 对小时、分钟的操作受 DST(夏令时)影响。例如在 CEST 时区(UTC+2),3 月最后一个周日凌晨 2:00 会跳到 3:00,此时对那个时刻加 1 小时,结果不是 3:00 而是 4:00(跳过了不存在的 3:00–4:00 区间)。
- 用
cal.getTimeZone().getOffset(cal.getTimeInMillis())查当前毫秒值对应的时区偏移 - 跨 DST 边界计算建议先转成 UTC 时间(用
SimpleDateFormat配合TimeZone.getTimeZone("UTC"))再操作 - 避免用
add(Calendar.HOUR, 24)代替:前者受 DST 影响,后者按日历日推进
add(Calendar.DAY_OF_MONTH, 1)
替代方案:Java 8+ 应该优先用 LocalDate / LocalDateTime
Calendar 是遗留 API,线程不安全、设计反直觉、时区处理隐晦。现代代码中,除非维护老系统或对接旧接口,否则应直接用 java.time 类型。
-
LocalDate.plusMonths(1)行为明确:1 月 31 日 → 2 月 28 日(非异常) -
ZonedDateTime.withEarlierOffsetAtOverlap()显式控制 DST 重叠行为 -
Duration和Period分离了“时间量”与“日历量”,避免混淆
LocalDate date = LocalDate.of(2025, 1, 31);
LocalDate nextMonth = date.plusMonths(1); // 2025-02-28
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Berlin"));
ZonedDateTime tomorrow = zdt.plusDays(1); // 自动处理 DST
用 Calendar 做跨月加减时,务必确认 lenient 模式和时区设置;如果逻辑涉及 DST、长期调度或需要不可变语义,java.time 不是“升级选项”,而是唯一合理选择。
# java
# go
# 为什么
# jvm
# date
# Calendar
# 接口
# 线程
# 对象
# 很多人
# 仍是
# 不存在
# 到你
# 问题是
# 只在
# 报错
# 跳到
# 最容易
# 个月
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
Laravel怎么导出Excel文件_Laravel Excel插件使用教程
Laravel怎么实现验证码(Captcha)功能
高防服务器:AI智能防御DDoS攻击与数据安全保障
Claude怎样写约束型提示词_Claude约束提示词写法【教程】
香港服务器WordPress建站指南:SEO优化与高效部署策略
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
Java垃圾回收器的方法和原理总结
网站优化排名时,需要考虑哪些问题呢?
LinuxShell函数封装方法_脚本复用设计思路【教程】
Linux系统命令中tree命令详解
韩国服务器如何优化跨境访问实现高效连接?
JavaScript如何实现倒计时_时间函数如何精确控制
Python数据仓库与ETL构建实战_Airflow调度流程详解
Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面
利用 Google AI 进行 YouTube 视频 SEO 描述优化
常州企业网站制作公司,全国继续教育网怎么登录?
Laravel怎么配置S3云存储驱动_Laravel集成阿里云OSS或AWS S3存储桶【教程】
如何快速搭建高效简练网站?
个人网站制作流程图片大全,个人网站如何注销?
移动端手机网站制作软件,掌上时代,移动端网站的谷歌SEO该如何做?
利用python获取某年中每个月的第一天和最后一天
悟空识字怎么关闭自动续费_悟空识字取消会员自动扣费步骤
Laravel队列由Redis驱动怎么配置_Laravel Redis队列使用教程
Laravel如何生成URL和重定向?(路由助手函数)
php 三元运算符实例详细介绍
Swift中switch语句区间和元组模式匹配
图册素材网站设计制作软件,图册的导出方式有几种?
如何在七牛云存储上搭建网站并设置自定义域名?
JavaScript中的标签模板是什么_它如何扩展字符串功能
如何安全更换建站之星模板并保留数据?
如何为不同团队 ID 动态生成多个“认领值班”按钮
Bootstrap整体框架之JavaScript插件架构
java ZXing生成二维码及条码实例分享
使用Dockerfile构建java web环境
如何快速辨别茅台真假?关键步骤解析
大连企业网站制作公司,大连2025企业社保缴费网上缴费流程?
javascript读取文本节点方法小结
如何快速生成高效建站系统源代码?
网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?
Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】
Laravel怎么定时执行任务_Laravel任务调度器Schedule配置与Cron设置【教程】
Laravel如何使用Blade模板引擎?(完整语法和示例)
Laravel如何实现数据导出到PDF_Laravel使用snappy生成网页快照PDF【方案】
如何在 Pandas 中基于一列条件计算另一列的分组均值
BootStrap整体框架之基础布局组件
创业网站制作流程,创业网站可靠吗?
微信小程序 HTTPS报错整理常见问题及解决方案
Win11怎么开启自动HDR画质_Windows11显示设置HDR选项
今日头条AI怎样推荐抢票工具_今日头条AI抢票工具推荐算法与筛选【技巧】
laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法


