- 传统方式:使用
java.util.Calendar(为了维护旧代码或理解历史) - 推荐方式:使用
java.time包 (现代、首选)
传统方式:使用 java.util.Calendar
Calendar 是一个抽象类,它提供了一个类方法 getInstance() 来获取一个代表当前时间的 Calendar 对象。

基本步骤
- 获取
Calendar实例:Calendar.getInstance() - 获取时间字段:使用
get(int field)方法,传入Calendar类中定义的常量。 - 格式化输出:通常需要将获取的数字格式化成我们习惯的字符串。
示例代码
import java.util.Calendar;
import java.util.Locale;
public class CalendarExample {
public static void main(String[] args) {
// 1. 获取代表当前时间的 Calendar 实例
Calendar now = Calendar.getInstance();
// 2. 获取各个时间字段
int year = now.get(Calendar.YEAR); // 年
int month = now.get(Calendar.MONTH); // 月 (注意:0代表一月,11代表十二月)
int dayOfMonth = now.get(Calendar.DAY_OF_MONTH); // 月中的第几天
int dayOfWeek = now.get(Calendar.DAY_OF_WEEK); // 星期 (1代表星期日,2代表星期一...7代表星期六)
int hour = now.get(Calendar.HOUR_OF_DAY); // 小时 (24小时制)
int minute = now.get(Calendar.MINUTE); // 分钟
int second = now.get(Calendar.SECOND); // 秒
int millisecond = now.get(Calendar.MILLISECOND); // 毫秒
// 3. 输出结果
System.out.println("使用 java.util.Calendar 获取当前时间:");
System.out.println("年: " + year);
System.out.println("月: " + (month + 1)); // 输出时需要 +1,因为月份从0开始
System.out.println("日: " + dayOfMonth);
System.out.println("星期: " + dayOfWeek); // 1=Sunday, 2=Monday, ..., 7=Saturday
System.out.println("时: " + hour);
System.out.println("分: " + minute);
System.out.println("秒: " + second);
System.out.println("毫秒: " + millisecond);
// --- 常见用法 ---
// 获取特定格式的时间字符串 ( 2025-10-27 15:30:45)
// 使用 String.format 进行格式化
String formattedTime = String.format("%04d-%02d-%02d %02d:%02d:%02d",
year,
month + 1, // 格式化时也需要 +1
dayOfMonth,
hour,
minute,
second);
System.out.println("\n格式化后的时间: " + formattedTime);
// 获取中文星期的名称
String[] weekDays = {"", "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
System.out.println("今天是: " + weekDays[dayOfWeek]);
}
}
Calendar 的主要特点
- 月份从 0 开始:这是最容易出错的地方。
Calendar.JANUARY的值是 0,Calendar.DECEMBER的值是 11,所以在获取月份时,通常需要+1。 - 星期从 1 开始:
Calendar.SUNDAY是 1,Calendar.MONDAY是 2,依此类推,Calendar.SATURDAY是 7。 - 可变性:
Calendar对象是可变的,你可以调用set()方法来修改它的值。 - 线程不安全:
Calendar不是线程安全的,在多线程环境下需要额外同步。
推荐方式:使用 java.time 包 (Java 8+)
自 Java 8 起,Oracle 引入了全新的 java.time API,旨在替代旧的 Date 和 Calendar 类,这个 API 设计得非常优秀,是不可变的、线程安全的,API 设计非常直观。
主要类
LocalDate:表示一个日期(年、月、日),没有时间部分。LocalTime:表示一个时间(时、分、秒、纳秒),没有日期部分。LocalDateTime:表示一个日期和时间的组合。ZonedDateTime:表示一个带有时区信息的日期和时间。DateTimeFormatter:用于日期时间的格式化和解析。
示例代码
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
public class JavaTimeExample {
public static void main(String[] args) {
// --- 获取当前时间 ---
// 1. 获取当前日期 (LocalDate)
LocalDate today = LocalDate.now();
System.out.println("使用 java.time 获取当前日期:");
System.out.println("年: " + today.getYear());
System.out.println("月: " + today.getMonthValue()); // 月份从1开始,非常直观!
System.out.println("日: " + today.getDayOfMonth());
System.out.println("星期: " + today.getDayOfWeek()); // 返回 DayOfWeek 枚举
System.out.println("一年中的第几天: " + today.getDayOfYear());
// 2. 获取当前时间 (LocalTime)
LocalTime now = LocalTime.now();
System.out.println("\n使用 java.time 获取当前时间:");
System.out.println("时: " + now.getHour());
System.out.println("分: " + now.getMinute());
System.out.println("秒: " + now.getSecond());
System.out.println("纳秒: " + now.getNano());
// 3. 获取当前日期和时间 (LocalDateTime)
LocalDateTime nowDateTime = LocalDateTime.now();
System.out.println("\n使用 java.time 获取当前日期和时间:");
System.out.println(nowDateTime);
// --- 格式化时间 ---
// 使用 DateTimeFormatter 进行格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化 LocalDateTime
String formattedDateTime = nowDateTime.format(formatter);
System.out.println("\n格式化后的日期时间: " + formattedDateTime);
// 也可以直接格式化 LocalDate
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 EEEE");
String formattedDate = today.format(dateFormatter);
System.out.println("格式化后的日期 (中文): " + formattedDate); // 2025年10月27日 星期五
// --- 解析字符串为日期时间对象 ---
String dateStr = "2025-12-25";
LocalDate parsedDate = LocalDate.parse(dateStr);
System.out.println("\n解析字符串得到的日期: " + parsedDate);
String dateTimeStr = "2025-10-27 20:30:00";
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeStr, formatter);
System.out.println("解析字符串得到的日期时间: " + parsedDateTime);
}
}
java.time 的主要优点
- 不可变:所有
java.time类都是不可变的,一旦创建,其值就不能改变,这使它们天生就是线程安全的,避免了并发问题。 - API 直观:月份从 1 开始(
1-12),星期是枚举类型(DayOfWeek.MONDAY),代码可读性极高。 - 功能强大:提供了丰富的方法来处理日期时间的计算,如
plusDays(),minusMonths(),withHour()等。 - 清晰的分离:将日期、时间、日期时间、时区等概念清晰地分离开来,职责单一。
- 现代设计:解决了旧 API 的许多设计缺陷。
总结与对比
| 特性 | java.util.Calendar |
java.time (Java 8+) |
|---|---|---|
| 线程安全 | 否 | 是 (因为不可变) |
| 可变性 | 可变 | 不可变 |
| 月份 | 从 0 开始 (0-11) | 从 1 开始 (1-12) |
| 星期 | 数字 (1=周日, 7=周六) | 枚举 (DayOfWeek.MONDAY) |
| API 设计 | 相对繁琐,常量多 | 直观、流畅、方法链式调用 |
| 易用性 | 较差 | 非常优秀 |
| 推荐度 | 仅用于维护旧代码 | 强烈推荐,所有新项目的首选 |
最终建议
- 如果你正在编写新的 Java 8 或更高版本的项目,请毫不犹豫地使用
java.time包,它是未来的方向,能让你写出更健壮、更易读的代码。 - 如果你需要维护一个旧的 Java 项目(版本低于 8),那么你将不得不使用
java.util.Calendar或java.util.Date,在这种情况下,请务必小心月份从0开始这个“陷阱”。 - 如果你的旧项目升级到了 Java 8,但代码中大量使用了
Calendar,可以考虑使用ThreeTen Backport库,它将java.time的 API 向后移植到了 Java 6 和 7,可以平滑地迁移代码。

