在Java里Calendar类如何进行日期计算_Java时间操作说明
发布时间 - 2026-02-01 00:00:00 点击率:次Calendar.add()是日期计算主力方法,自动处理进位越界;roll()仅在当前单位内滚动不改变更大单位;set()需调用getTime()等才生效;Calendar线程不安全且已过时,但部分场景仍需谨慎使用。
Calendar.add() 是日期计算的主力方法
直接用 add() 方法增减年、月、日等字段,它会自

常见错误是传错字段常量:Calendar.MONTH 是从 0 开始的(0 表示 1 月),而 Calendar.DAY_OF_MONTH 和 Calendar.YEAR 是从 1 或自然年份开始的。加 1 个月 ≠ 加 30 天,尤其遇到 1 月、2 月、闰年时结果差异明显。
- 加 3 天:
calendar.add(Calendar.DAY_OF_MONTH, 3) - 减 1 年:
calendar.add(Calendar.YEAR, -1) - 加 2 个月(注意:不是固定天数):
calendar.add(Calendar.MONTH, 2)
Calendar.roll() 和 add() 的关键区别在哪
roll() 只在当前单位内“滚动”,不改变更大单位。比如对 2025-01-31 调用 roll(Calendar.MONTH, 1),结果是 2025-02-28(不是 2025-02-31,也不变成 2025-02-31 再进位到 3 月),年份不会变;而 add(Calendar.MONTH, 1) 会得到 2025-02-28,但如果是 2025-01-15,则两者结果一致。
适用场景很窄:仅当明确需要“不溢出上级单位”时才用 roll(),例如做月份选择器只在 1–12 间循环,或调试时临时调整某字段观察局部影响。
- 想让“2025-12-15 + 1 月”变成 2025-01-15?必须用
add() - 想让“12 月”按 +1 滚成 “1 月”,但年份卡死在 2025?才考虑
roll(Calendar.MONTH, 1) -
roll()对Calendar.DAY_OF_YEAR等字段行为也受限,别默认它和add()等价
为什么 set() 后要调用 getTime() 或 computeTime() 才生效
set() 方法只是把字段值记下来,并不立即重算时间戳(time 字段),直到你调用 getTime()、get() 或 computeTime() 才真正触发计算。这导致一个经典陷阱:连续 set() 多个字段后直接 getTimeInMillis(),可能拿到未同步的旧时间戳。
更隐蔽的问题是字段冲突:比如先 set(Calendar.MONTH, 1)(2 月),再 set(Calendar.DAY_OF_MONTH, 30),这时 2 月没有 30 日,但 Calendar 不会立刻报错或修正——它等到真正计算时才按规则回滚(变成 3 月 2 日),而这个时机不可控。
- 安全做法:每次
set()后,如需立刻获取时间值,紧跟calendar.getTime() - 避免混合使用
set()和add():前者延迟计算,后者立即更新内部状态,混用易引发时序 bug - 如果只是初始化 Calendar,优先用
GregorianCalendar(int year, int month, int day)构造器,比多次set()更可靠
Calendar 在 Java 8+ 中已被弃用,但有些场景绕不开
虽然 java.time(如 LocalDateTime、ZonedDateTime)是推荐替代方案,但仍有现实约束:老系统接口返回 Calendar、某些 Android API(尤其是低于 API 26 的版本)、遗留数据库驱动(如旧版 JDBC)仍以 Calendar 传时区时间。硬切 java.time 可能引入兼容性风险或额外转换开销。
若必须用 Calendar,务必注意:它的线程不安全,不能复用实例;SimpleDateFormat 配合 Calendar 解析时,时区行为依赖 Calendar.getTimeZone(),而非格式字符串里的 Z 或 z;Android 上部分机型对 Calendar.getInstance(TimeZone) 的夏令时支持不一致。
- 多线程环境:每次用都 new 一个
GregorianCalendar(),别共享 static 实例 - 和
java.time互转:用GregorianCalendar.from(ZonedDateTime)和calendar.toInstant().atZone(ZoneId.systemDefault()),别用毫秒戳中转丢失时区信息 - Android 开发者注意:
Calendar.getActualMaximum(Calendar.DAY_OF_MONTH)在某些厂商 ROM 上对 2 月返回错误值,建议用YearMonth.of(year, month).lengthOfMonth()替代
MONTH=0)、set() 的延迟求值机制,以及跨月计算时对“月末日”的隐式处理逻辑——这些细节不写测试很难暴露,一到生产环境就出错。
# java
# android
# go
# 区别
# 为什么
# lmax
# Static
# 常量
# Calendar
# 字符串
# int
# 循环
# 接口
# 线程
# 多线程
# 选择器
# 数据库
# bug
# 个月
# 更大
# 是从
# 只在
# 想让
# 时才
# 不安全
# 不改变
# 的是
# 也不
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何解决hover在ie6中的兼容性问题
html5audio标签播放结束怎么触发事件_onended回调方法【教程】
如何实现javascript表单验证_正则表达式有哪些实用技巧
Laravel怎么自定义错误页面_Laravel修改404和500页面模板
1688铺货到淘宝怎么操作 1688一键铺货到自己店铺详细步骤
EditPlus中的正则表达式实战(6)
Laravel如何实现邮箱地址验证功能_Laravel邮件验证流程与配置
晋江文学城电脑版官网 晋江文学城网页版直接进入
Laravel如何使用Contracts(契约)进行编程_Laravel契约接口与依赖反转
教你用AI将一段旋律扩展成一首完整的曲子
免费视频制作网站,更新又快又好的免费电影网站?
如何挑选优质建站一级代理提升网站排名?
如何制作一个表白网站视频,关于勇敢表白的小标题?
Firefox Developer Edition开发者版本入口
linux写shell需要注意的问题(必看)
如何快速查询域名建站关键信息?
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel Eloquent性能优化技巧_Laravel N+1查询问题解决
米侠浏览器网页背景异常怎么办 米侠显示修复
Win11关机界面怎么改_Win11自定义关机画面设置【工具】
开心动漫网站制作软件下载,十分开心动画为何停播?
浏览器如何快速切换搜索引擎_在地址栏使用不同搜索引擎【搜索】
如何打造高效商业网站?建站目的决定转化率
Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧
Android仿QQ列表左滑删除操作
香港服务器建站指南:外贸独立站搭建与跨境电商配置流程
C语言设计一个闪闪的圣诞树
Win10如何卸载预装Edge扩展_Win10卸载Edge扩展教程【方法】
Laravel如何实现多对多模型关联?(Eloquent教程)
Laravel如何生成API文档?(Swagger/OpenAPI教程)
Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制
如何在景安云服务器上绑定域名并配置虚拟主机?
LinuxShell函数封装方法_脚本复用设计思路【教程】
Laravel怎么防止CSRF攻击_Laravel CSRF保护中间件原理与实践
深入理解Android中的xmlns:tools属性
Laravel软删除怎么实现_Laravel Eloquent SoftDeletes功能使用教程
电视网站制作tvbox接口,云海电视怎样自定义添加电视源?
Laravel如何配置.env文件管理环境变量_Laravel环境变量使用与安全管理
如何用AWS免费套餐快速搭建高效网站?
PHP 实现电台节目表的智能时间匹配与今日/明日轮播逻辑
公司门户网站制作流程,华为官网怎么做?
零服务器AI建站解决方案:快速部署与云端平台低成本实践
Laravel 419 page expired怎么解决_Laravel CSRF令牌过期处理
Laravel怎么在Controller之外的地方验证数据
Win11怎么关闭透明效果_Windows11辅助功能视觉效果设置
Laravel控制器是什么_Laravel MVC架构中Controller的作用与实践
Windows家庭版如何开启组策略(gpedit.msc)?(安装方法)
PythonWeb开发入门教程_Flask快速构建Web应用
手机网站制作平台,手机靓号代理商怎么制作属于自己的手机靓号网站?
INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】

