Calendar 类本身并不直接存储“毫秒”作为一个独立的字段,但它有一个核心概念叫做 “时间”,这个时间在 Java 中通常以 从 1970 年 1 月 1 日 00:00:00 UTC(纪元)开始的毫秒数 来表示。

理解这一点是关键。
核心方法:getTimeInMillis() 和 setTimeInMillis()
这是 Calendar 类中与毫秒数交互最主要、最直接的两个方法。
getTimeInMillis()
这个方法返回 Calendar 对象所表示的时间点,对应的毫秒数(long 类型)。
示例代码:

import java.util.Calendar;
public class CalendarMillisecondExample {
public static void main(String[] args) {
// 1. 创建一个 Calendar 实例,默认设置为当前时间
Calendar calendar = Calendar.getInstance();
// 2. 获取当前时间对应的毫秒数
long currentTimeInMillis = calendar.getTimeInMillis();
System.out.println("当前时间的毫秒数: " + currentTimeInMillis);
// 3. 设置一个特定的日期和时间,2000-01-01 00:00:00
Calendar specificDate = Calendar.getInstance();
specificDate.set(2000, Calendar.JANUARY, 1, 0, 0, 0);
// 注意:月份是从0开始的,Calendar.JANUARY 是 0
long specificTimeInMillis = specificDate.getTimeInMillis();
System.out.println("2000-01-01 的毫秒数: " + specificTimeInMillis);
}
}
输出结果会类似这样(因为“当前时间”是动态的):
当前时间的毫秒数: 1678886400000 // 这是一个示例值,每次运行都会不同
2000-01-01 的毫秒数: 946684800000
setTimeInMillis(long millis)
这个方法使用一个给定的毫秒数来设置 Calendar 对象的日期和时间。
示例代码:
import java.util.Calendar;
public class SetTimeInMillisExample {
public static void main(String[] args) {
// 创建一个 Calendar 实例
Calendar calendar = Calendar.getInstance();
// 定义一个毫秒数,代表某个时间点
long someTimeInMillis = 946684800000L; // 2000-01-01 00:00:00 UTC
// 使用这个毫秒数来设置 Calendar
calendar.setTimeInMillis(someTimeInMillis);
// calendar 对象就代表了 2000-01-01 这个时间点
// 我们可以从中提取年、月、日等信息
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1; // +1 因为月份从0开始
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("毫秒数 " + someTimeInMillis + " 对应的日期是:");
System.out.println("年份: " + year);
System.out.println("月份: " + month);
System.out.println("日期: " + day);
}
}
输出:
毫秒数 946684800000 对应的日期是:
年份: 2000
月份: 1
日期: 1
Calendar 与 Date 类的关系
Calendar 和 Date 是 Java 早期处理日期和时间的重要类,它们之间通过毫秒数紧密相连。
Date对象本质上就是一个封装了 long 类型毫秒数 的容器。Calendar的getTime()方法可以将其内部的时间(毫秒数)转换为一个Date对象。Calendar的setTime(Date date)方法可以将一个Date对象代表的毫秒数设置到Calendar实例中。
示例代码:
import java.util.Calendar;
import java.util.Date;
public class CalendarAndDateExample {
public static void main(String[] args) {
// 1. 从 Calendar 获取 Date
Calendar calendar = Calendar.getInstance();
Date dateFromCalendar = calendar.getTime(); // 内部调用 getTimeInMillis() 转换
System.out.println("Calendar 转换后的 Date 对象: " + dateFromCalendar);
System.out.println("Date 对象内部存储的毫秒数: " + dateFromCalendar.getTime());
System.out.println("--------------------");
// 2. 从 Date 设置 Calendar
Date someDate = new Date(); // 当前时间的 Date 对象
System.out.println("原始 Date 对象: " + someDate);
Calendar calendarFromDate = Calendar.getInstance();
calendarFromDate.setTime(someDate); // 将 Date 的毫秒数设置给 Calendar
System.out.println("用 Date 设置后的 Calendar 年份: " + calendarFromDate.get(Calendar.YEAR));
}
}
输出:
Calendar 转换后的 Date 对象: Sat Mar 18 10:30:00 CST 2025
Date 对象内部存储的毫秒数: 1679106600000 // 示例值
--------------------
原始 Date 对象: Sat Mar 18 10:30:00 CST 2025
用 Date 设置后的 Calendar 年份: 2025
获取和设置毫秒级的精度(MILLISECOND 字段)
Calendar 确实有一个字段叫做 Calendar.MILLISECOND,但它通常不被推荐使用,原因如下:
- 默认行为:当你通过
Calendar.getInstance()创建一个实例时,MILLISECOND字段的值通常是 0。 - 作用范围:
MILLISECOND字段只影响 一秒内的毫秒部分,它的取值范围是 0 到 999。 - 主要用途:当你需要对一个已经存在的
Calendar对象进行微调,增加或减少几毫秒时,可以使用它。
示例代码:
import java.util.Calendar;
public class CalendarMillisecondFieldExample {
public static void main(String[] args) {
Calendar calendar = Calendar.getInstance();
System.out.println("初始毫秒字段: " + calendar.get(Calendar.MILLISECOND)); // 很可能是 0
// 设置毫秒为 500
calendar.set(Calendar.MILLISECOND, 500);
System.out.println("设置后的毫秒字段: " + calendar.get(Calendar.MILLISECOND));
// 验证 getTimeInMillis() 的变化
long time1 = calendar.getTimeInMillis();
System.out.println("设置 500ms 后的总毫秒数: " + time1);
// 再增加 100 毫秒
calendar.add(Calendar.MILLISECOND, 100);
long time2 = calendar.getTimeInMillis();
System.out.println("再增加 100ms 后的总毫秒数: " + time2);
System.out.println("毫秒差值: " + (time2 - time1)); // 应该输出 100
}
}
输出:
初始毫秒字段: 0
设置后的毫秒字段: 500
设置 500ms 后的总毫秒数: 1678886400500 // 示例值
再增加 100ms 后的总毫秒数: 1678886400600 // 示例值
毫秒差值: 100
重要提醒:Calendar 已被废弃
自 Java 8 以来,java.util.Calendar 和 java.util.Date 类都已被标记为 @Deprecated (已废弃),官方文档强烈建议使用新的 java.time 包来处理日期和时间。
java.time 包中的类(如 Instant, LocalDateTime, ZonedDateTime)提供了更强大、更直观、更不容易出错的 API。
java.time 中的毫秒处理:
Instant: 代表时间线上的一个精确点,其内部就是存储了从纪元开始的纳秒数,可以轻松获取毫秒。LocalDateTime: 代表一个不带时区的日期和时间,可以处理纳秒精度。
示例(对比 Calendar 和 java.time):
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Calendar;
public class ModernJavaTimeExample {
public static void main(String[] args) {
// --- 旧方式 (Calendar) ---
Calendar calendar = Calendar.getInstance();
long calendarMillis = calendar.getTimeInMillis();
System.out.println("[Calendar] 当前时间的毫秒数: " + calendarMillis);
// --- 新方式 (java.time) ---
// 1. 获取当前时间的毫秒数 (推荐)
Instant instant = Instant.now();
long instantMillis = instant.toEpochMilli(); // 直接获取毫秒
System.out.println("[Instant] 当前时间的毫秒数: " + instantMillis);
// 2. 使用毫秒数创建一个时间点
long someMillis = 946684800000L;
Instant instantFromMillis = Instant.ofEpochMilli(someMillis);
System.out.println("[Instant] 从毫秒创建的时间点: " + instantFromMillis);
// 3. 转换为本地日期时间
LocalDateTime localDateTime = LocalDateTime.ofInstant(instantFromMillis, ZoneId.systemDefault());
System.out.println("[LocalDateTime] 对应的本地日期时间: " + localDateTime);
}
}
输出:
[Calendar] 当前时间的毫秒数: 1678886400000 // 示例值
[Instant] 当前时间的毫秒数: 1678886400000 // 示例值
[Instant] 从毫秒创建的时间点: 2000-01-01T00:00:00Z
[LocalDateTime] 对应的本地日期时间: 2000-01-01T08:00:00 // 假设系统时区是 CST (UTC+8)
| 特性 | java.util.Calendar |
java.time.Instant / LocalDateTime |
|---|---|---|
| 核心概念 | 内部存储一个从纪元开始的 毫秒数 | Instant 直接存储从纪元开始的 纳秒数 |
| 获取毫秒数 | getTimeInMillis() |
toEpochMilli() |
| 设置毫秒数 | setTimeInMillis(long) |
ofEpochMilli(long) |
| 精度 | 毫秒 | 纳秒(更高精度) |
| 状态 | 已废弃 (@Deprecated) | 推荐使用 |
| 线程安全 | 非线程安全 | 大部分核心类是不可变的,因此是线程安全的 |
- 如果你正在维护旧的 Java 代码(Java 8 之前),你需要使用
Calendar,记住它与毫秒数交互的核心是getTimeInMillis()和setTimeInMillis()。 - 对于所有新的项目,请务必使用
java.time包,它更现代、更安全、更易用,是处理日期和时间的标准方式。
