0

0

在Java里Calendar类如何操作日期_Java日期计算方式说明

P粉602998670

P粉602998670

发布时间:2026-02-02 09:21:08

|

146人浏览过

|

来源于php中文网

原创

set() 是设成某值,add() 是加减若干单位;set() 不触发进位,add() 自动处理溢出;设每月1日需用 set(Calendar.DAY_OF_MONTH, 1);getActualMaximum() 比硬编码31更可靠;getTimeInMillis() 需先 get() 触发重算;Calendar 非线程安全,须每次新建或用 ThreadLocal;Java 8+ 应优先使用 LocalDateTime/ZonedDateTime。

在java里calendar类如何操作日期_java日期计算方式说明

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 所处月份的实际最大天数,它考虑了年份、月份、甚至时区(极少数情况下影响月末判断)。

立即学习Java免费学习笔记(深入)”;

Calendar cal = Calendar.getInstance();
cal.set(2024, 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() 就立刻取时间戳,可能拿到过期缓存值。

Monica Search
Monica Search

Monica推出的AI搜索引擎

下载

典型表现:设了年月日,但没设时分秒,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 包。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
java中calendar类的用法
java中calendar类的用法

Java Video类是JavaFX库中的一个类,用于创建和操作视频对象。它提供了方法来加载、播放、暂停、停止和控制视频的音量、速度和循环等属性。想了解更多Java中类的相关内容,可以阅读本专题下面的文章。

311

2024.02.29

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

546

2023.08.10

go语言 注释编码
go语言 注释编码

本专题整合了go语言注释、注释规范等等内容,阅读专题下面的文章了解更多详细内容。

59

2026.01.31

go语言 math包
go语言 math包

本专题整合了go语言math包相关内容,阅读专题下面的文章了解更多详细内容。

52

2026.01.31

go语言输入函数
go语言输入函数

本专题整合了go语言输入相关教程内容,阅读专题下面的文章了解更多详细内容。

25

2026.01.31

golang 循环遍历
golang 循环遍历

本专题整合了golang循环遍历相关教程,阅读专题下面的文章了解更多详细内容。

10

2026.01.31

Golang人工智能合集
Golang人工智能合集

本专题整合了Golang人工智能相关内容,阅读专题下面的文章了解更多详细内容。

7

2026.01.31

2026赚钱平台入口大全
2026赚钱平台入口大全

2026年最新赚钱平台入口汇总,涵盖任务众包、内容创作、电商运营、技能变现等多类正规渠道,助你轻松开启副业增收之路。阅读专题下面的文章了解更多详细内容。

410

2026.01.31

高干文在线阅读网站大全
高干文在线阅读网站大全

汇集热门1v1高干文免费阅读资源,涵盖都市言情、京味大院、军旅高干等经典题材,情节紧凑、人物鲜明。阅读专题下面的文章了解更多详细内容。

232

2026.01.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.1万人学习

C# 教程
C# 教程

共94课时 | 8.3万人学习

Java 教程
Java 教程

共578课时 | 55.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号