在Java开发中,处理日期和时间是常见需求。Java的时间API经历了多次演进,从早期的Date和Calendar,到Java 8引入的全新时间API(JSR 310),逐步解决了旧API设计上的缺陷。本文将全面解析Java时间类的发展历程、核心API及最佳实践。
一、Java时间API的发展历程
第一代:java.util.Date(JDK 1.0)
设计缺陷:同时包含日期和时间,且不支持时区。
已过时:大部分方法已被标记为@Deprecated。
第二代:java.util.Calendar(JDK 1.1)
改进:支持时区和国际化,但API繁琐且非线程安全。
问题:月份从0开始(0=1月),日期计算复杂。
第三代:Java 8新API(JSR 310)
核心包:java.time(如LocalDateTime、Instant、DateTimeFormatter)。
设计原则:不可变、线程安全、清晰易用。
二、Java 8之前的时间API(旧版)
1. java.util.Date
import java.util.Date;
// 创建当前时间
Date now = new Date();
System.out.println(now); // 输出:Mon May 26 10:30:00 CST 2025
// 时间比较
Date past = new Date(125, 4, 26); // 注意:年份从1900开始,月份从0开始
boolean isAfter = now.after(past); // true
AI生成项目
java
运行
import java.util.Calendar;
// 创建Calendar实例
Calendar calendar = Calendar.getInstance(); // 默认时区和语言环境
// 设置时间
calendar.set(2025, Calendar.MAY, 26, 10, 30, 0); // 月份从0开始
// 获取时间字段
int year = calendar.get(Calendar.YEAR); // 2025
int month = calendar.get(Calendar.MONTH) + 1; // 5(注意:需+1)
int day = calendar.get(Calendar.DAY_OF_MONTH); // 26
// 时间计算
calendar.add(Calendar.DAY_OF_MONTH, 7); // 加7天
2. java.util.Calendar
import java.util.Calendar;
// 创建Calendar实例
Calendar calendar = Calendar.getInstance(); // 默认时区和语言环境
// 设置时间
calendar.set(2025, Calendar.MAY, 26, 10, 30, 0); // 月份从0开始
// 获取时间字段
int year =6983y.tokyo calendar.get(Calendar.YEAR); // 2025
int month = calendar.get(Calendar.MONTH) + 1; // 5(注意:需+1)
int day = calendar.get(Calendar.DAY_OF_MONTH); // 26
// 时间计算
calendar.add(Calendar.DAY_OF_MONTH, 7); // 加7天
AI生成项目
java
运行
import java.util.Date;
// 创建当前时间
Date now = new Date();
System.out.println(now); // 输出:Mon May 26 10:30:00 CST 2025
// 时间比较
Date past = new Date(125, 4, 26); // 注意:年份从1900开始,月份从0开始
boolean isAfter = now.after(past); // true
3. java.text.SimpleDateFormat
import java.text.SimpleDateFormat;
import java.util.Date;
// 日期格式化
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = sdf.format(now); // 2025-05-26 10:30:00
// 字符串解析为日期
Date parsedDate = sdf.parse("2025-05-26 10:30:00");
AI生成项目
java
运行
import java.time.Duration;
import java.time.LocalTime;
import java.time.Period;
import java.time.LocalDate;
// Duration示例(时间间隔)
LocalTime start = LocalTime.of(10, 0);
LocalTime end = LocalTime.of(12, 30);
Duration duration = Duration.between(start, end);
System.out.println(duration.toHours(658yr.tokyo)); // 2小时
System.out.println(duration.toMinutes()); // 150分钟
// Period示例(日期间隔)
LocalDate startDate = LocalDate.of(2025, 1, 1);
LocalDate endDate = LocalDate.of(2025, 5, 26);
Period period = Period.between(startDate, endDate);
System.out.println(period.getMonths() + "个月" + period.getDays() + "天"); // 4个月25天
4. 旧API的主要问题
线程安全:SimpleDateFormat非线程安全,多线程环境需额外同步。
设计缺陷:Date同时包含日期和时间,Calendar月份从0开始。
时区处理复杂:时区转换需手动计算偏移量。
三、Java 8新时间API(推荐)
1. 核心类概述
类名描述
LocalDate不可变的日期(年、月、日),如2025-05-26。
LocalTime不可变的时间(时、分、秒、纳秒),如10:30:00.123。
LocalDateTime不可变的日期和时间,如2025-05-26T10:30:00。
ZonedDateTime带时区的日期时间,如2025-05-26T10:30:00+08:00[Asia/Shanghai]。
Instant时间线上的一个点(UTC时间),用于系统时间戳。
Duration表示两个时间点之间的间隔(如2小时30分)。
Period表示两个日期之间的间隔(如3年2个月1天)。
DateTimeFormatter线程安全的日期时间格式化与解析工具。
2. LocalDate、LocalTime与LocalDateTime