Java 的java.time
包详解
引言
在Java 8之前,处理日期和时间一直是开发者的一大痛点。Java 8引入了新的日期和时间API,即java.time
包,极大地简化了日期和时间的处理。本文将详细介绍java.time
包的各个组成部分及其使用方法。
1. java.time
包概述
java.time
包提供了一组全新的类,用于处理日期、时间、时区和时间间隔。与旧的java.util.Date
和java.util.Calendar
类相比,java.time
包中的类是不可变且线程安全的,基于ISO-8601日历系统。
1.1 核心类
LocalDate
: 表示没有时区的日期,例如2007-12-03
。LocalTime
: 表示没有时区的时间,例如10:15:30
。LocalDateTime
: 表示没有时区的日期和时间,例如2007-12-03T10:15:30
。ZonedDateTime
: 表示带时区的日期和时间,例如2007-12-03T10:15:30+01:00[Europe/Paris]
。OffsetDateTime
: 表示带偏移量的日期和时间,例如2007-12-03T10:15:30+01:00
。OffsetTime
: 表示带偏移量的时间,例如10:15:30+01:00
。Instant
: 表示时间线上的一个瞬时点,例如2007-12-03T10:15:30Z
。Duration
: 表示时间的持续时间,例如PT20.345S
。Period
: 表示日期的时间段,例如P1Y2M3D
。
2. LocalDate
类
LocalDate
类表示没有时区的日期,通常用于表示生日、假期等。
2.1 创建LocalDate
实例
LocalDate today = LocalDate.now();
LocalDate specificDate = LocalDate.of(2024, Month.JANUARY, 1);
LocalDate parsedDate = LocalDate.parse("2024-01-01");
2.2 LocalDate
的常用方法
- 获取日期信息:
int year = today.getYear(); Month month = today.getMonth(); int dayOfMonth = today.getDayOfMonth(); DayOfWeek dayOfWeek = today.getDayOfWeek();
- 日期运算:
LocalDate tomorrow = today.plusDays(1); LocalDate previousMonthSameDay = today.minus(1, ChronoUnit.MONTHS);
3. LocalTime
类
LocalTime
类表示没有时区的时间,通常用于表示一天中的某个时间点。
3.1 创建LocalTime
实例
LocalTime now = LocalTime.now();
LocalTime specificTime = LocalTime.of(10, 15, 30);
LocalTime parsedTime = LocalTime.parse("10:15:30");
3.2 LocalTime
的常用方法
- 获取时间信息:
int hour = now.getHour(); int minute = now.getMinute(); int second = now.getSecond();
- 时间运算:
LocalTime oneHourLater = now.plusHours(1); LocalTime tenMinutesEarlier = now.minusMinutes(10);
4. LocalDateTime
类
LocalDateTime
类表示没有时区的日期和时间,通常用于表示具体的时间点。
4.1 创建LocalDateTime
实例
LocalDateTime now = LocalDateTime.now();
LocalDateTime specificDateTime = LocalDateTime.of(2024, Month.JANUARY, 1, 10, 15, 30);
LocalDateTime parsedDateTime = LocalDateTime.parse("2024-01-01T10:15:30");
4.2 LocalDateTime
的常用方法
- 获取日期和时间信息:
LocalDate date = now.toLocalDate(); LocalTime time = now.toLocalTime();
- 日期和时间运算:
LocalDateTime nextWeek = now.plusWeeks(1); LocalDateTime previousYear = now.minusYears(1);
5. ZonedDateTime
类
ZonedDateTime
类表示带时区的日期和时间,通常用于跨时区的时间处理。
5.1 创建ZonedDateTime
实例
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime specificZonedDateTime = ZonedDateTime.of(2024, 1, 1, 10, 15, 30, 0, ZoneId.of("Europe/Paris"));
ZonedDateTime parsedZonedDateTime = ZonedDateTime.parse("2024-01-01T10:15:30+01:00[Europe/Paris]");
5.2 ZonedDateTime
的常用方法
- 获取时区信息:
ZoneId zone = now.getZone(); ZonedOffset offset = now.getOffset();
- 时区转换:
ZonedDateTime utcDateTime = now.withZoneSameInstant(ZoneOffset.UTC); ZonedDateTime newYorkDateTime = now.withZoneSameInstant(ZoneId.of("America/New_York"));
6. OffsetDateTime
类
OffsetDateTime
类表示带偏移量的日期和时间,通常用于表示与UTC时间的偏移。
6.1 创建OffsetDateTime
实例
OffsetDateTime now = OffsetDateTime.now();
OffsetDateTime specificOffsetDateTime = OffsetDateTime.of(2024, 1, 1, 10, 15, 30, 0, ZoneOffset.of("+01:00"));
OffsetDateTime parsedOffsetDateTime = OffsetDateTime.parse("2024-01-01T10:15:30+01:00");
6.2 OffsetDateTime
的常用方法
- 获取偏移量信息:
ZoneOffset offset = now.getOffset();
- 偏移量转换:
OffsetDateTime utcOffsetDateTime = now.withOffsetSameInstant(ZoneOffset.UTC);
7. Instant
类
Instant
类表示时间线上的一个瞬时点,通常用于时间戳。
7.1 创建Instant
实例
Instant now = Instant.now();
Instant specificInstant = Instant.ofEpochMilli(1609459200000L);
Instant parsedInstant = Instant.parse("2024-09-01T00:00:00Z");
7.2 Instant
的常用方法
- 获取时间戳信息:
long epochMilli = now.toEpochMilli();
- 时间戳运算:
Instant oneHourLater = now.plus(1, ChronoUnit.HOURS); Instant tenMinutesEarlier = now.minus(10, ChronoUnit.MINUTES);
8. Duration
类
Duration
类表示时间的持续时间,通常用于计算两个时间点之间的差异。
8.1 创建Duration
实例
Duration duration = Duration.ofHours(1);
Duration parsedDuration = Duration.parse("PT1H");
8.2 Duration
的常用方法
- 获取持续时间信息:
long seconds = duration.getSeconds(); long nanos = duration.getNano();
- 持续时间运算:
Duration twoHoursLater = duration.plusHours(1); Duration tenMinutesEarlier = duration.minusMinutes(10);
8.3 Duration
的其他方法
-
计算两个时间点之间的持续时间:
Instant start = Instant.parse("2024-01-01T10:15:30.00Z"); Instant end = Instant.parse("2024-01-01T12:15:30.00Z"); Duration duration = Duration.between(start, end); long hours = duration.toHours(); // 2 hours
-
将
Duration
转换为其他单位:long minutes = duration.toMinutes(); // 120 minutes long millis = duration.toMillis(); // 7200000 milliseconds
-
比较两个
Duration
对象:Duration duration1 = Duration.ofHours(1); Duration duration2 = Duration.ofMinutes(60); boolean isEqual = duration1.equals(duration2); // true
-
获取绝对值:
Duration negativeDuration = Duration.ofHours(-2); Duration positiveDuration = negativeDuration.abs(); // PT2H
-
除法和乘法运算:
Duration dividedDuration = duration.dividedBy(2); // PT1H Duration multipliedDuration = duration.multipliedBy(2); // PT4H
-
添加和减去
Duration
:Duration addedDuration = duration.plus(Duration.ofMinutes(30)); // PT2H30M Duration subtractedDuration = duration.minus(Duration.ofMinutes(30)); // PT1H30M
9. Period
类
Period
类表示日期的时间段,通常用于计算两个日期之间的差异。
9.1 创建Period
实例
Period period = Period.ofYears(1);
Period parsedPeriod = Period.parse("P1Y");
9.2 Period
的常用方法
-
获取时间段信息:
int years = period.getYears(); int months = period.getMonths(); int days = period.getDays();
-
时间段运算:
Period twoYearsLater = period.plusYears(1); Period tenMonthsEarlier = period.minusMonths(10);
-
计算两个日期之间的时间段:
LocalDate startDate = LocalDate.of(2023, 1, 1); LocalDate endDate = LocalDate.of(2024, 1, 1); Period periodBetween = Period.between(startDate, endDate);
-
将
Period
转换为总天数:long totalDays = periodBetween.toTotalMonths() * 30 + periodBetween.getDays();
-
解析和格式化
Period
:Period parsedPeriod = Period.parse("P1Y2M3D"); String formattedPeriod = parsedPeriod.toString(); // P1Y2M3D
10. ZoneId
和ZoneOffset
类
ZoneId
类表示时区ID,例如Europe/Paris
,ZoneOffset
类表示与UTC的时区偏移,例如+02:00
。
10.1 创建ZoneId
和ZoneOffset
实例
ZoneId zoneId = ZoneId.of("Europe/Paris");
ZoneOffset zoneOffset = ZoneOffset.of("+02:00");
10.2 ZoneId
和ZoneOffset
的常用方法
- 获取系统默认时区:
ZoneId systemDefault = ZoneId.systemDefault();
- 时区转换:
ZonedDateTime zonedDateTime = ZonedDateTime.now(zoneId); OffsetDateTime offsetDateTime = OffsetDateTime.now(zoneOffset);
11. Clock
类
Clock
类提供了对当前时间和日期的访问,使用指定的时区。
11.1 创建Clock
实例
Clock clock = Clock.systemDefaultZone();
Clock utcClock = Clock.systemUTC();
Clock fixedClock = Clock.fixed(Instant.now(), ZoneId.of("Europe/Paris"));
11.2 Clock
的常用方法
- 获取当前时间:
Instant instant = clock.instant(); ZonedDateTime zonedDateTime = ZonedDateTime.now(clock);
12. TemporalAdjuster
接口
TemporalAdjuster
接口用于执行复杂的日期操作,例如调整到下一个工作日。
12.1 使用TemporalAdjuster
LocalDate nextSunday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
LocalDate firstDayOfMonth = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
13. DateTimeFormatter
类
DateTimeFormatter
类用于格式化和解析日期时间对象。
13.1 创建DateTimeFormatter
实例
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
13.2 DateTimeFormatter
的常用方法
- 格式化日期时间:
String formattedDateTime = LocalDateTime.now().format(formatter);
- 解析日期时间:
LocalDateTime dateTime = LocalDateTime.parse("2024-01-01 10:15:30", formatter);
14. java.time.temporal
包
java.time.temporal
包提供了更底层的日期时间操作接口和类,例如Temporal
、TemporalAmount
、TemporalUnit
等。
14.1 Temporal
接口
Temporal
接口定义了日期时间对象的基本操作,例如加减时间单位。
14.2 TemporalAmount
接口
TemporalAmount
接口表示时间量,例如Duration
和Period
。
14.3 TemporalUnit
接口
TemporalUnit
接口表示时间单位,例如天、小时、分钟等。
15. java.time.chrono
包
java.time.chrono
包提供了对非ISO-8601日历系统的支持,例如日本历、泰国历等。
15.1 ChronoLocalDate
接口
ChronoLocalDate
接口表示日历系统中的日期。
15.2 ChronoLocalDateTime
接口
ChronoLocalDateTime
接口表示日历系统中的日期和时间。
15.3 ChronoZonedDateTime
接口
ChronoZonedDateTime
接口表示带时区的日期和时间。
16. java.time.format
包
java.time.format
包提供了格式化和解析日期时间的类和接口。
16.1 DateTimeFormatter
类
DateTimeFormatter
类用于格式化和解析日期时间对象。
16.2 DateTimeFormatterBuilder
类
DateTimeFormatterBuilder
类用于构建复杂的日期时间格式化器。
16.3 ResolverStyle
枚举
ResolverStyle
枚举定义了解析日期时间字符串时的策略,例如严格模式、宽松模式等。
17. java.time.zone
包
java.time.zone
包提供了对时区规则的支持。
17.1 ZoneRules
类
ZoneRules
类表示时区的规则,例如夏令时的开始和结束时间。
17.2 ZoneRulesProvider
类
ZoneRulesProvider
类提供了获取时区规则的方法。
结论
Java 8引入的java.time
包极大地简化了日期和时间的处理。通过使用不可变和线程安全的类可以更轻松地进行日期和时间的操作。