Java 日期与时间(java.time)
Java 8 引入了新的日期时间 API(java.time 包),解决了旧 API 的问题,提供了更好的日期时间处理能力。理解新的日期时间 API 是进行时间相关开发的基础。本章将详细介绍 Java 中的日期时间处理。
java.time 包概览(LocalDate、LocalTime、LocalDateTime)
为什么需要新的日期时间 API
旧 API(java.util.Date、Calendar)的问题:
- 线程不安全
- API 设计混乱
- 时区处理复杂
- 可变对象,容易出错
新 API(java.time)的优势:
- 线程安全(不可变对象)
- API 设计清晰
- 时区处理简单
- 不可变对象,更安全
LocalDate
**LocalDate**表示日期(年-月-日),不包含时间。
import java.time.LocalDate;
// 获取当前日期
LocalDate today = LocalDate.now();
System.out.println("今天:" + today); // 2024-01-15
// 创建指定日期
LocalDate date1 = LocalDate.of(2024, 1, 15);
LocalDate date2 = LocalDate.of(2024, Month.JANUARY, 15);
// 从字符串解析
LocalDate date3 = LocalDate.parse("2024-01-15");
// 获取日期组成部分
int year = today.getYear(); // 2024
int month = today.getMonthValue(); // 1
int day = today.getDayOfMonth(); // 15
DayOfWeek dayOfWeek = today.getDayOfWeek(); // MONDAY
LocalTime
**LocalTime**表示时间(时:分:秒),不包含日期。
import java.time.LocalTime;
// 获取当前时间
LocalTime now = LocalTime.now();
System.out.println("现在:" + now); // 14:30:45.123
// 创建指定时间
LocalTime time1 = LocalTime.of(14, 30);
LocalTime time2 = LocalTime.of(14, 30, 45);
LocalTime time3 = LocalTime.of(14, 30, 45, 123456789);
// 从字符串解析
LocalTime time4 = LocalTime.parse("14:30:45");
// 获取时间组成部分
int hour = now.getHour(); // 14
int minute = now.getMinute(); // 30
int second = now.getSecond(); // 45
LocalDateTime
**LocalDateTime**表示日期和时间,不包含时区。
import java.time.LocalDateTime;
// 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
System.out.println("现在:" + now); // 2024-01-15T14:30:45.123
// 创建指定日期时间
LocalDateTime dt1 = LocalDateTime.of(2024, 1, 15, 14, 30);
LocalDateTime dt2 = LocalDateTime.of(2024, Month.JANUARY, 15, 14, 30, 45);
// 从 LocalDate 和 LocalTime 组合
LocalDate date = LocalDate.of(2024, 1, 15);
LocalTime time = LocalTime.of(14, 30);
LocalDateTime dt3 = LocalDateTime.of(date, time);
// 从字符串解析
LocalDateTime dt4 = LocalDateTime.parse("2024-01-15T14:30:45");
日期/时间解析与格式化(DateTimeFormatter)
DateTimeFormatter
**DateTimeFormatter**用于格式化和解析日期时间。
import java.time.format.DateTimeFormatter;
// 格式化
LocalDate date = LocalDate.of(2024, 1, 15);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
String formatted = date.format(formatter); // "2024-01-15"
// 解析
LocalDate parsed = LocalDate.parse("2024-01-15", formatter);
// 预定义格式
DateTimeFormatter isoDate = DateTimeFormatter.ISO_DATE;
String formatted2 = date.format(isoDate); // "2024-01-15"
常用格式模式
LocalDateTime now = LocalDateTime.now();
// 自定义格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formatted1 = now.format(formatter1); // "2024-01-15 14:30:45"
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH时mm分");
String formatted2 = now.format(formatter2); // "2024年01月15日 14时30分"
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String formatted3 = now.format(formatter3); // "15/01/2024"
格式模式符号
| 符号 | 含义 | 示例 |
|---|---|---|
| y | 年 | 2024 |
| M | 月 | 1, 01, Jan, January |
| d | 日 | 1, 01 |
| H | 时(24小时制) | 0-23 |
| h | 时(12小时制) | 1-12 |
| m | 分 | 0-59 |
| s | 秒 | 0-59 |
| a | AM/PM | AM, PM |
时间间隔与计算(Duration、Period)
Duration
**Duration**表示时间间隔(精确到纳秒),用于 LocalTime 和 LocalDateTime。
import java.time.Duration;
LocalTime start = LocalTime.of(10, 0);
LocalTime end = LocalTime.of(14, 30);
// 计算时间间隔
Duration duration = Duration.between(start, end);
System.out.println("间隔:" + duration); // PT4H30M
// 获取间隔组成部分
long hours = duration.toHours(); // 4
long minutes = duration.toMinutes(); // 270
long seconds = duration.getSeconds(); // 16200
// 创建 Duration
Duration duration1 = Duration.ofHours(2);
Duration duration2 = Duration.ofMinutes(30);
Duration duration3 = Duration.ofSeconds(90);
Period
**Period**表示日期间隔(年-月-日),用于 LocalDate。
import java.time.Period;
LocalDate start = LocalDate.of(2024, 1, 1);
LocalDate end = LocalDate.of(2024, 12, 31);
// 计算日期间隔
Period period = Period.between(start, end);
System.out.println("间隔:" + period); // P11M30D
// 获取间隔组成部分
int years = period.getYears(); // 0
int months = period.getMonths(); // 11
int days = period.getDays(); // 30
// 创建 Period
Period period1 = Period.ofYears(1);
Period period2 = Period.ofMonths(6);
Period period3 = Period.ofDays(30);
Period period4 = Period.of(1, 2, 3); // 1年2月3天
日期时间计算
LocalDate date = LocalDate.of(2024, 1, 15);
// 加减日期
LocalDate plusDays = date.plusDays(10); // 加 10 天
LocalDate plusWeeks = date.plusWeeks(2); // 加 2 周
LocalDate plusMonths = date.plusMonths(1); // 加 1 月
LocalDate plusYears = date.plusYears(1); // 加 1 年
LocalDate minusDays = date.minusDays(5); // 减 5 天
// 使用 Period
Period period = Period.of(1, 2, 3);
LocalDate newDate = date.plus(period); // 加 1年2月3天
// 使用 Duration(需要转换为 LocalDateTime)
LocalDateTime dateTime = date.atStartOfDay();
LocalDateTime newDateTime = dateTime.plus(Duration.ofHours(2));
时区处理(ZonedDateTime)
ZonedDateTime
**ZonedDateTime**表示带时区的日期时间。
import java.time.ZonedDateTime;
import java.time.ZoneId;
// 获取当前时区的日期时间
ZonedDateTime now = ZonedDateTime.now();
System.out.println("现在:" + now); // 2024-01-15T14:30:45.123+08:00[Asia/Shanghai]
// 指定时区
ZonedDateTime zoned1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime zoned2 = ZonedDateTime.now(ZoneId.of("America/New_York"));
// 从 LocalDateTime 创建
LocalDateTime localDateTime = LocalDateTime.of(2024, 1, 15, 14, 30);
ZonedDateTime zoned3 = localDateTime.atZone(ZoneId.of("Asia/Shanghai"));
// 时区转换
ZonedDateTime beijing = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYork = beijing.withZoneSameInstant(ZoneId.of("America/New_York"));
ZoneId
**ZoneId**表示时区标识符。
import java.time.ZoneId;
// 系统默认时区
ZoneId systemZone = ZoneId.systemDefault();
// 指定时区
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
ZoneId newYork = ZoneId.of("America/New_York");
ZoneId utc = ZoneId.of("UTC");
// 获取所有可用时区
Set<String> zoneIds = ZoneId.getAvailableZoneIds();