在Java里Calendar类如何操作日期_Java日期计算方式说明
发布时间 - 2026-02-02 00:00:00 点击率:次set() 是设成某值,add() 是加减若干单位;set() 不触发进位,add() 自动处理溢出;设每月1日需用 set(Calendar.DAY_OF_MONTH, 1);getActualMaximum() 比硬编码31更可靠;getTimeInMillis() 需先 get() 触发重算;Calendar 非线程安全,须每次新建或用 ThreadLocal;Java 8+ 应优先使用 LocalDateTime/ZonedDateTime。
Calendar 的 set() 和 add() 到底该用哪个
直接说结论:set() 是“设成某值”,add() 是“加减若干单位”。混淆两者是 Java 日期计算中最常见的逻辑错误来源。
比如想把一个 Calendar 对象的月份设为 12 月(即 Calendar.DECEMBER),用 set(Calendar.MONTH, 11) 没问题;但若误用 add(Calendar.MONTH, 11),就会在当前月份基础上加 11 个月,结果完全不可控。
-
set()不会触发自动进位或借位:调用cal.set(Calendar.DAY_OF_MONTH, 32)后,cal.get(Calendar.DAY_OF_MONTH)可能返回 1(下月1号),这取决于底层实现和时区,行为不直观 -
add()会自动处理溢出:如 1 月 31 日 + 1 个月 → 自动变成 2 月 28 日(或 29 日) - 如果要“清零某字段再设新值”,不能只靠
set();例如想设成每月 1 日,得先set(Calendar.DAY_OF_MONTH, 1),而不是set(Calendar.DATE, 1)(二者等价,但别混用别名)
为什么 getActualMaximum(Calendar.DAY_OF_MONTH) 比直接写 31 更可靠
因为不是每个月都有 31 天。硬编码 31 在 4 月、6 月、9 月、11 月或 2 月会出错——尤其是跨年、跨闰年时。
getActualMaximum() 返回当前 Calendar 所处月份的实际最大天数,它考虑了年份、月份、甚至时区(极少数情况下影响月末判断)。
Calendar cal = Calendar.getInstance(); cal.set(2025, Calendar.FEBRUARY, 15); // 注意:月份从 0 开始 int lastDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH); // 返回 29 cal.set(Calendar.DAY_OF_MONTH, lastDay); // 安全设为当月最后一天
- 别用
getMaximum()——它返回该字段理论最大值(如DAY_OF_MONTH总是返回 31) - 调用
getActualMaximum()前,确保Calendar的年/月已明确设定,否则可能基于当前时间,导致意外结果 - 这个方法不修改日历状态,只读取,可放心多次调用
Calendar.getTimeInMillis() 和 new Date().getTime() 的精度陷阱
两者都返回毫秒数,但关键区别在于:前者依赖 Calendar 内部字段是否已“计算完成”。如果刚调用 set() 就立刻取时间戳,可能拿到过期缓存值。
典型表现:设了年月日,但没设时分秒,getTimeInMillis() 返回的时间却包含旧的时分秒甚至毫秒值,导致时间偏移。
- 安全做法是调用
cal.getTimeInMillis()前,先执行cal.get(Calendar.YEAR)或任意get()——这会强制触发内部重算(computeTime()) - 更稳妥的是直接调用
cal.getTime().getTime(),getTime()方法内部已保证时间同步 - 注意:
Calendar默认时区是 JVM 启动时确定的,跨时区操作必须显式cal.setTimeZone(TimeZone.getTimeZone("UTC"))
Calendar 的线程不安全性怎么避坑
Calendar 实例不是线程安全的。多个线程共用同一个实例,同时调用 set()、add() 或 get(),会导致字段错乱、时间计算错误,且极难复现。
这不是“尽量避免共享”的建议,而是“必须隔离”的硬性

- 不要将
Calendar设为静态变量或单例成员 - 每次需要时用
Calendar.getInstance()创建新实例(开销极小) - 如果频繁创建,可用
ThreadLocal缓存,但需注意内存泄漏风险(尤其在 Web 容器中未清理) - Java 8+ 强烈建议迁移到
LocalDateTime/ZonedDateTime——它们不可变、无状态、天然线程安全
Calendar 类的设计初衷是作为“可变日期计算器”,但它把状态管理、时区、历法规则全揉在一起,稍有不慎就掉进坑里。真正复杂的日期逻辑,别硬扛,尽早切到 java.time 包。
# java
# 编码
# 区别
# 为什么
# lmax
# jvm
# date
# Calendar
# 线程
# 对象
# 设为
# 个月
# 加减
# 的是
# 都有
# 尤其是
# 多个
# 会在
# 这不是
# 当月
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
宙斯浏览器视频悬浮窗怎么开启 边看视频边操作其他应用教程
Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID
HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】
香港服务器如何优化才能显著提升网站加载速度?
小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像
jQuery中的100个技巧汇总
西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?
Laravel PHP版本要求一览_Laravel各版本环境要求对照
做企业网站制作流程,企业网站制作基本流程有哪些?
Laravel路由Route怎么设置_Laravel基础路由定义与参数传递规则【详解】
Windows驱动无法加载错误解决方法_驱动签名验证失败处理步骤
rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted
如何确保FTP站点访问权限与数据传输安全?
Linux后台任务运行方法_nohup与&使用技巧【技巧】
使用C语言编写圣诞表白程序
如何快速生成高效建站系统源代码?
Laravel如何实现密码重置功能_Laravel密码找回与重置流程
利用python获取某年中每个月的第一天和最后一天
香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化
Android仿QQ列表左滑删除操作
Laravel Livewire是什么_使用Laravel Livewire构建动态前端界面
微信h5制作网站有哪些,免费微信H5页面制作工具?
Laravel如何使用Vite进行前端资源打包?(配置示例)
php结合redis实现高并发下的抢购、秒杀功能的实例
如何快速搭建自助建站会员专属系统?
Laravel怎么使用Collection集合方法_Laravel数组操作高级函数pluck与map【手册】
JS中使用new Date(str)创建时间对象不兼容firefox和ie的解决方法(两种)
详解Android图表 MPAndroidChart折线图
php打包exe后无法访问网络共享_共享权限设置方法【教程】
详解Nginx + Tomcat 反向代理 如何在高效的在一台服务器部署多个站点
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?
香港服务器网站推广:SEO优化与外贸独立站搭建策略
如何在IIS中新建站点并解决端口绑定冲突?
如何快速生成凡客建站的专业级图册?
零服务器AI建站解决方案:快速部署与云端平台低成本实践
Laravel如何实现用户密码重置功能?(完整流程代码)
如何彻底删除建站之星生成的Banner?
网页设计与网站制作内容,怎样注册网站?
如何在阿里云服务器自主搭建网站?
网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?
制作电商网页,电商供应链怎么做?
如何快速搭建虚拟主机网站?新手必看指南
php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】
Laravel如何部署到服务器_线上部署Laravel项目的完整流程与步骤
*服务器网站为何频现安全漏洞?
Linux系统命令中tree命令详解
Laravel怎么为数据库表字段添加索引以优化查询
韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南
北京网站制作费用多少,建立一个公司网站的费用.有哪些部分,分别要多少钱?

