Calendar是Java处理日期时间的抽象基类,需通过getInstance()获取实例,支持时区、字段操作等,但月份从0开始、线程不安全,Java 8后推荐使用java.time包。

Java 的 Calendar 类是用来处理日期和时间的抽象基类,不能直接 new 实例,需通过 Calendar.getInstance() 获取具体子类(如 GregorianCalendar)对象。它比过时的 Date 类更灵活,支持时区、历法、字段操作等,但自 Java 8 起官方推荐使用 java.time 包(如 LocalDateTime、ZonedDateTime),不过很多老项目仍在用 Calendar。
获取和初始化 Calendar 对象
Calendar 是抽象类,必须通过静态工厂方法创建:
- 默认方式:
Calendar cal = Calendar.getInstance();—— 使用系统默认时区和语言环境,返回GregorianCalendar实例 - 指定时区:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8")); - 指定时区 + 语言环境:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("PST"), Locale.US);
设置和读取日期时间字段
Calendar 把日期拆成多个字段(如年、月、日、小时等),用常量表示(Calendar.YEAR、Calendar.MONTH 等),注意月份从 0 开始(0=1月,11=12月),星期几中 Calendar.SUNDAY = 1,Calendar.MONDAY = 2(与日常习惯不同):
- 设置单个字段:
cal.set(Calendar.YEAR, 2025); cal.set(Calendar.MONTH, 0); // 1月 - 一次性设置多个字段:
cal.set(2025, Calendar.JANUARY, 20, 14, 30, 0); // 年、月、日、时、分、秒 - 读取字段值:
int year = cal.get(Calendar.YEAR); int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
日期计算与偏移
用 add() 和 roll() 方法做日期加减,区别在于是否影响更大单位:
立即学习“Java免费学习笔记(深入)”;
-
cal.add(Calendar.DATE, 10):加 10 天,可能进位到下个月或下一年 -
cal.roll(Calendar.DATE, 10):只在当月内滚动,比如 1 月 25 日 +10 天 → 1 月 4 日(不跨月) - 常用偏移:
add(Calendar.MONTH, -1)上个月,add(Calendar.HOUR_OF_DAY, 24)加一天
与 Date 和毫秒值互转
Calendar 与传统 Date 及时间戳(long 毫秒)之间可互相转换:
- Calendar → Date:
Date date = cal.getTime(); - Date → Calendar:
cal.setTime(date); - Calendar → 毫秒:
long millis = cal.getTimeInMillis(); - 毫秒 → Calendar:
cal.setTimeInMillis(millis);
注意:getTime() 返回的是一个 Date 对象,其内部仍是毫秒值,但 Date 的大部分 setter/getter 已过时,应避免直接调用 date.getYear() 等方法。
常见陷阱与替代建议
Calendar 容易出错的地方包括:月份从 0 开始、星期定义不一致、线程不安全(不能共享实例)、API 设计不够直观。实际开发中建议:
- 新项目优先用
java.time:如LocalDateTime.now().plusDays(7)更清晰安全 - 必须用 Calendar 时,封装工具类统一处理字段逻辑(如“获取本月第一天”)
- 多线程环境下每次使用都新建实例,或用
ThreadLocal缓存
不复杂但容易忽略细节,用熟了效率高,但长期看转向 java.time 是更可持续的选择。










