2.Java中关于日期时间API的使用整合 - java.time包

日期时间API的使用整合 - java.time包

二、java.time包

(一)java.time.Instant

Instant 是 Java 8 中引入的 java.time 包的一部分,旨在表示时间线上的一个瞬间。它类似于之前的 java.util.Date,但提供了更多的功能和更好的设计。Instant 类不包含时区信息,表示的是UTC(协调世界时)时间。

1. 创建 Instant 对象

获取当前时间的 Instant

可以使用静态方法 Instant.now() 来获取当前时间的 Instant 对象:

import java.time.Instant;

Instant now = Instant.now();
System.out.println("当前时间的 Instant: " + now);
从时间戳创建 Instant

可以通过从1970年1月1日00:00:00 UTC以来的秒数或毫秒数来创建 Instant 对象:

// 从秒数创建 Instant
Instant fromEpochSecond = Instant.ofEpochSecond(1633039200L);
System.out.println("从秒数创建的 Instant: " + fromEpochSecond);

// 从毫秒数创建 Instant
Instant fromEpochMilli = Instant.ofEpochMilli(1633039200000L);
System.out.println("从毫秒数创建的 Instant: " + fromEpochMilli);

2. 操作 Instant 对象

加减时间

可以使用 plusminus 方法来进行时间的加减操作:

// 当前时间的 Instant
Instant now = Instant.now();

// 加1小时
Instant oneHourLater = now.plusSeconds(3600);
System.out.println("加1小时后的 Instant: " + oneHourLater);

// 减30分钟
Instant thirtyMinutesBefore = now.minusSeconds(1800);
System.out.println("减30分钟前的 Instant: " + thirtyMinutesBefore);
计算两个 Instant 之间的时间差

可以使用 Duration 类来计算两个 Instant 之间的时间差:

import java.time.Duration;
import java.time.Instant;

Instant start = Instant.now();

// 模拟一些处理时间
Thread.sleep(2000);

Instant end = Instant.now();
Duration duration = Duration.between(start, end);
System.out.println("处理时间: " + duration.toMillis() + " 毫秒");

3. 转换 Instant 和其他日期时间类型

转换为 LocalDateTime

可以将 Instant 转换为 LocalDateTime,需要通过指定一个 ZoneId(时区)来进行转换:

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;

Instant instant = Instant.now();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println("转换为 LocalDateTime: " + localDateTime);
转换为 ZonedDateTime

可以将 Instant 转换为 ZonedDateTime,需要通过指定一个 ZoneId(时区)来进行转换:

import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.ZoneId;

Instant instant = Instant.now();
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
System.out.println("转换为 ZonedDateTime: " + zonedDateTime);
转换为 Date

虽然现代API大多数时候不需要转换到旧的 Date 类,但必要时仍可以进行转换:

import java.time.Instant;
import java.util.Date;

Instant instant = Instant.now();
Date date = Date.from(instant);
System.out.println("转换为 Date: " + date);
Date 转换为 Instant

同样地,也可以从 Date 转换为 Instant

import java.time.Instant;
import java.util.Date;

Date date = new Date();
Instant instant = date.toInstant();
System.out.println("从 Date 转换为 Instant: " + instant);

4. 格式化和解析 Instant

Instant 不能直接使用 DateTimeFormatter 进行格式化和解析,因为它是基于UTC的时间戳。可以将 Instant 转换为 ZonedDateTimeOffsetDateTime 来进行格式化和解析:

格式化
import java.time.Instant;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

Instant instant = Instant.now();
ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

String formatted = formatter.format(zonedDateTime);
System.out.println("格式化 Instant: " + formatted);
解析
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.ZoneId;
import java.time.ZonedDateTime;

String dateTimeStr = "2021-10-01 12:00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr, formatter);
ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
Instant instant = zonedDateTime.toInstant();
System.out.println("解析字符串到 Instant: " + instant);

5. Instant的比较

可以使用 Instant 类的 isBeforeisAfterequals 方法进行比较:

Instant instant1 = Instant.now();
Instant instant2 = instant1.plusSeconds(10);

boolean isBefore = instant1.isBefore(instant2);  // true
boolean isAfter = instant1.isAfter(instant2);    // false
boolean isEqual = instant1.equals(instant2);     // false

System.out.println("instant1 是否在 instant2 之前: " + isBefore);
System.out.println("instant1 是否在 instant2 之后: " + isAfter);
System.out.println("instant1 是否与 instant2 相等: " + isEqual);

小结

Instant 类是处理时间戳的强大工具,在处理跨时区、需要高精度时间戳和时间间隔计算时非常有用。由于 Instant 是不可变且线程安全的,因此在并发环境下使用非常安全。通过结合 DurationZonedDateTimeDateTimeFormatter 等工具,可以充分发挥 Instant 的功能。

(二)java.time.Duration

Duration 类是 Java 8 中引入的 java.time 包的一部分,主要用于表示两个时间点之间的时间间隔。Duration 对象可以精确到纳秒,并且主要用于以秒和纳秒为单位的时间计算。相比之下,Period 类则用于以年、月、日为单位的日期计算。

1. 创建 Duration 对象

使用工厂方法

可以通过静态工厂方法来创建 Duration 对象:

import java.time.Duration;

// 创建一个表示 5 秒的 Duration
Duration durationSeconds = Duration.ofSeconds(5);
System.out.println("Duration of 5 seconds: " + durationSeconds);

// 创建一个表示 3 分钟的 Duration
Duration durationMinutes = Duration.ofMinutes(3);
System.out.println("Duration of 3 minutes: " + durationMinutes);

// 创建一个表示 2 小时的 Duration
Duration durationHours = Duration.ofHours(2);
System.out.println("Duration of 2 hours: " + durationHours);

// 创建一个表示 1000 毫秒(1 秒)的 Duration
Duration durationMillis = Duration.ofMillis(1000);
System.out.println("Duration of 1000 milliseconds: " + durationMillis);
使用 between 方法

可以通过两个时间点之间的差值来创建 Duration 对象:

import java.time.Duration;
import java.time.Instant;

Instant start = Instant.now();

// 模拟一些处理时间
Thread.sleep(2000);

Instant end = Instant.now();
Duration duration = Duration.between(start, end);
System.out.println("Duration between start and end: " + duration);

2. 操作 Duration 对象

加和减

可以使用 plusminus 方法来对 Duration 进行加减操作:

import java.time.Duration;

// 创建一个初始的 Duration
Duration initialDuration = Duration.ofMinutes(10);

// 增加 5 分钟
Duration extendedDuration = initialDuration.plusMinutes(5);
System.out.println("Duration after adding 5 minutes: " + extendedDuration);

// 减少 3 分钟
Duration reducedDuration = initialDuration.minusMinutes(3);
System.out.println("Duration after subtracting 3 minutes: " + reducedDuration);
转换为其他单位

可以将 Duration 转换为特定单位的时间值,例如天、小时、分钟、秒和毫秒:

import java.time.Duration;

Duration duration = Duration.ofHours(1);

// 转换为分钟
long minutes = duration.toMinutes();
System.out.println("Duration in minutes: " + minutes);

// 转换为秒
long seconds = duration.getSeconds();
System.out.println("Duration in seconds: " + seconds);

// 转换为毫秒
long millis = duration.toMillis();
System.out.println("Duration in milliseconds: " + millis);

// 转换为纳秒
long nanos = duration.toNanos();
System.out.println("Duration in nanoseconds: " + nanos);

3. 检查和比较 Duration

检查零和负数

可以使用 isZeroisNegative 方法来检查 Duration 是否为零或负数:

import java.time.Duration;

Duration zeroDuration = Duration.ofSeconds(0);
Duration positiveDuration = Duration.ofSeconds(5);
Duration negativeDuration = Duration.ofSeconds(-5);

System.out.println("Is zero duration zero? " + zeroDuration.isZero());
System.out.println("Is positive duration negative? " + positiveDuration.isNegative());
System.out.println("Is negative duration negative? " + negativeDuration.isNegative());
比较 Duration

可以使用 compareTo 方法比较两个 Duration 对象:

import java.time.Duration;

Duration duration1 = Duration.ofMinutes(5);
Duration duration2 = Duration.ofMinutes(10);

int comparisonResult = duration1.compareTo(duration2);
if (comparisonResult > 0) {
    System.out.println("duration1 is longer than duration2");
} else if (comparisonResult < 0) {
    System.out.println("duration1 is shorter than duration2");
} else {
    System.out.println("duration1 is equal to duration2");
}

4. 格式化和解析 Duration

转换为字符串

可以通过 toString 方法将 Duration 对象转换为字符串表示:

import java.time.Duration;

Duration duration = Duration.ofHours(1).plusMinutes(30).plusSeconds(20);
String durationStr = duration.toString();
System.out.println("String representation of Duration: " + durationStr);

Duration 的字符串表示格式为 PTnHnMnS,其中 P 表示时期(Period),T 表示时间,nH 表示小时,nM 表示分钟,nS 表示秒。

从字符串解析

可以使用 Duration.parse 方法从字符串解析 Duration 对象:

import java.time.Duration;

String durationStr = "PT1H30M20S";
Duration parsedDuration = Duration.parse(durationStr);
System.out.println("Parsed Duration: " + parsedDuration);

5. 与其他时间类的结合使用

使用 Instant

可以结合 Instant 使用 Duration 来进行时间计算:

import java.time.Instant;
import java.time.Duration;

Instant now = Instant.now();
Duration duration = Duration.ofHours(2);

// 加 2 小时
Instant later = now.plus(duration);
System.out.println("2 hours later: " + later);

// 减 2 小时
Instant earlier = now.minus(duration);
System.out.println("2 hours earlier: " + earlier);
使用 LocalTime

可以结合 LocalTime 使用 Duration 来进行时间计算:

import java.time.LocalTime;
import java.time.Duration;

LocalTime time = LocalTime.now();
Duration duration = Duration.ofMinutes(30);

// 加 30 分钟
LocalTime later = time.plus(duration);
System.out.println("30 minutes later: " + later);

// 减 30 分钟
LocalTime earlier = time.minus(duration);
System.out.println("30 minutes earlier: " + earlier);

小结

Duration 类在处理时间间隔时非常实用,特别是在需要高精度时间计算的场景。它提供了丰富的操作方法,可以方便地进行加减时间、转换单位、比较时间间隔等操作。Duration 结合 Instant 和其他日期时间类使用,可以实现更复杂的时间计算和操作。

(三)java.time.Period

Period 类是 Java 8 引入的 java.time 包中的一部分,主要用于表示以年、月、日为单位的时间量。与 Duration 类(主要用于以秒和纳秒为单位的时间量)不同,Period 类更适合处理日期之间的差异,例如计算两个日期之间的年、月、日差值。
以下是关于 Period 类的详细讲解和使用示例。

1. 创建 Period 对象

使用工厂方法

可以通过静态工厂方法来创建 Period 对象:

import java.time.Period;

// 创建一个表示 1 年 2 个月 3 天的 Period
Period period = Period.of(1, 2, 3);
System.out.println("Period: " + period);

// 创建一个表示 5 天的 Period
Period daysPeriod = Period.ofDays(5);
System.out.println("Period of 5 days: " + daysPeriod);

// 创建一个表示 2 个月的 Period
Period monthsPeriod = Period.ofMonths(2);
System.out.println("Period of 2 months: " + monthsPeriod);

// 创建一个表示 1 年的 Period
Period yearsPeriod = Period.ofYears(1);
System.out.println("Period of 1 year: " + yearsPeriod);
使用 between 方法

可以通过两个日期之间的差值来创建 Period 对象:

import java.time.LocalDate;
import java.time.Period;

LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2024, 3, 15);

Period period = Period.between(startDate, endDate);
System.out.println("Period between start and end date: " + period);

2. 操作 Period 对象

加和减

可以使用 plusminus 方法来对 Period 进行加减操作:

import java.time.Period;

Period initialPeriod = Period.of(1, 2, 3);

// 增加 1 年 1 个月 1 天
Period extendedPeriod = initialPeriod.plus(Period.of(1, 1, 1));
System.out.println("Extended Period: " + extendedPeriod);

// 减少 1 年 1 个月 1 天
Period reducedPeriod = initialPeriod.minus(Period.of(1, 1, 1));
System.out.println("Reduced Period: " + reducedPeriod);
转换为其他单位

可以将 Period 转换为特定单位的时间值,例如天、月、年:

import java.time.Period;

Period period = Period.of(1, 2, 3);

// 获取总月数
int totalMonths = period.toTotalMonths();
System.out.println("Total months: " + totalMonths);

3. 检查和修改 Period

检查零和负数

可以使用 isZeroisNegative 方法来检查 Period 是否为零或负数:

import java.time.Period;

Period zeroPeriod = Period.of(0, 0, 0);
Period positivePeriod = Period.of(1, 2, 3);
Period negativePeriod = Period.of(-1, -2, -3);

System.out.println("Is zero period zero? " + zeroPeriod.isZero());
System.out.println("Is positive period negative? " + positivePeriod.isNegative());
System.out.println("Is negative period negative? " + negativePeriod.isNegative());
设置天数,月份,年份

可以使用 withDayswithMonthswithYears方法来设置天数,月份,年份:

import java.time.Period;

Period period5 = Period.of(2029, 3, 8);
System.out.println("Period with 12 Days: "+period5.withDays(12));
System.out.println("Period with 3 Months: "+period5.withMonths(3));
System.out.println("Period with 1 Years: "+period5.withYears(1));

4. 格式化和解析 Period

转换为字符串

可以通过 toString 方法将 Period 对象转换为字符串表示:

import java.time.Period;

Period period = Period.of(1, 2, 3);
String periodStr = period.toString();
System.out.println("String representation of Period: " + periodStr);

Period 的字符串表示格式为 PnYnMnD,其中 P 表示时期,nY 表示年,nM 表示月,nD 表示日。

从字符串解析

可以使用 Period.parse 方法从字符串解析 Period 对象:

import java.time.Period;

String periodStr = "P1Y2M3D";
Period parsedPeriod = Period.parse(periodStr);
System.out.println("Parsed Period: " + parsedPeriod);

5. 与其他时间类的结合使用

使用 LocalDate

可以结合 LocalDate 使用 Period 来进行日期计算:

import java.time.LocalDate;
import java.time.Period;

LocalDate startDate = LocalDate.of(2023, 1, 1);
Period period = Period.of(1, 2, 3);

// 加 1 年 2 个月 3 天
LocalDate endDate = startDate.plus(period);
System.out.println("End date after adding period: " + endDate);

// 减 1 年 2 个月 3 天
LocalDate earlierDate = startDate.minus(period);
System.out.println("Earlier date after subtracting period: " + earlierDate);

小结

Period 类在处理日期之间的差异时非常实用,特别是在需要以年、月、日为单位的时间计算场景。它提供了丰富的操作方法,可以方便地进行加减时间、转换单位、比较时间间隔等操作。Period 结合 LocalDate 和其他日期时间类使用,可以实现更复杂的时间计算和操作。

(四)java.time.LocalTime

LocalTime 类是 Java 8 引入的 java.time 包的一部分,用于表示没有日期部分的时间,例如一天中的小时、分钟、秒和纳秒。LocalTime 类是不可变且线程安全的。
以下是关于 LocalTime 类的详细讲解和使用示例。

1. 创建 LocalTime 对象

使用工厂方法

LocalTime 提供了多个静态工厂方法来创建时间对象:

import java.time.LocalTime;

// 当前时间
LocalTime currentTime = LocalTime.now();
System.out.println("Current time: " + currentTime);

// 指定时间(小时和分钟)
LocalTime specificTime1 = LocalTime.of(14, 30);
System.out.println("Specific time (HH:MM): " + specificTime1);

// 指定时间(小时、分钟和秒)
LocalTime specificTime2 = LocalTime.of(14, 30, 45);
System.out.println("Specific time (HH:MM:SS): " + specificTime2);

// 指定时间(小时、分钟、秒和纳秒)
LocalTime specificTime3 = LocalTime.of(14, 30, 45, 123456789);
System.out.println("Specific time (HH:MM:SS.NNNNNNNNN): " + specificTime3);

2. 获取时间的各个部分

可以通过 LocalTime 类的方法获取时间的各个部分:

import java.time.LocalTime;

LocalTime time = LocalTime.of(14, 30, 45, 123456789);

int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();
int nano = time.getNano();

System.out.println("Hour: " + hour);      // 14
System.out.println("Minute: " + minute);  // 30
System.out.println("Second: " + second);  // 45
System.out.println("Nano: " + nano);      // 123456789

3. 修改 LocalTime 对象

LocalTime 提供了多种修改时间的方法,这些方法会返回一个新的 LocalTime 实例,因为 LocalTime 是不可变的。

加和减时间
import java.time.LocalTime;

LocalTime time = LocalTime.of(14, 30, 45);

// 加时间
LocalTime timePlusHours = time.plusHours(2);
LocalTime timePlusMinutes = time.plusMinutes(15);
LocalTime timePlusSeconds = time.plusSeconds(30);
LocalTime timePlusNanos = time.plusNanos(1000000);

System.out.println("Time plus 2 hours: " + timePlusHours);
System.out.println("Time plus 15 minutes: " + timePlusMinutes);
System.out.println("Time plus 30 seconds: " + timePlusSeconds);
System.out.println("Time plus 1 millisecond: " + timePlusNanos);

// 减时间
LocalTime timeMinusHours = time.minusHours(2);
LocalTime timeMinusMinutes = time.minusMinutes(15);
LocalTime timeMinusSeconds = time.minusSeconds(30);
LocalTime timeMinusNanos = time.minusNanos(1000000);

System.out.println("Time minus 2 hours: " + timeMinusHours);
System.out.println("Time minus 15 minutes: " + timeMinusMinutes);
System.out.println("Time minus 30 seconds: " + timeMinusSeconds);
System.out.println("Time minus 1 millisecond: " + timeMinusNanos);
设置时间
import java.time.LocalTime;

LocalTime time = LocalTime.of(14, 30, 45);

// 设置时间
LocalTime newTime1 = time.withHour(10);
LocalTime newTime2 = time.withMinute(20);
LocalTime newTime3 = time.withSecond(50);
LocalTime newTime4 = time.withNano(123456789);

System.out.println("Time with hour set to 10: " + newTime1);
System.out.println("Time with minute set to 20: " + newTime2);
System.out.println("Time with second set to 50: " + newTime3);
System.out.println("Time with nano set to 123456789: " + newTime4);

4. 比较 LocalTime 对象

LocalTime 提供了多种比较方法:

import java.time.LocalTime;

LocalTime time1 = LocalTime.of(14, 30, 45);
LocalTime time2 = LocalTime.of(16, 45, 30);

// 比较时间
boolean isBefore = time1.isBefore(time2); // true
boolean isAfter = time1.isAfter(time2);   // false

System.out.println("time1 is before time2: " + isBefore);
System.out.println("time1 is after time2: " + isAfter);

// 使用 compareTo 方法
int comparisonResult = time1.compareTo(time2);
if (comparisonResult < 0) {
    System.out.println("time1 is before time2");
} else if (comparisonResult > 0) {
    System.out.println("time1 is after time2");
} else {
    System.out.println("time1 is equal to time2");
}

5. 格式化和解析 LocalTime

转换为字符串

LocalTime 支持使用 DateTimeFormatter 格式化为字符串:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

LocalTime time = LocalTime.of(14, 30, 45);

// 使用默认格式
String defaultFormatted = time.toString();
System.out.println("Default formatted time: " + defaultFormatted);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
String customFormatted = time.format(formatter);
System.out.println("Custom formatted time: " + customFormatted);
从字符串解析

可以使用 DateTimeFormatter 从字符串解析 LocalTime 对象:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

String timeStr = "14:30:45";

// 使用默认格式
LocalTime parsedTime1 = LocalTime.parse(timeStr);
System.out.println("Parsed time (default): " + parsedTime1);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss");
LocalTime parsedTime2 = LocalTime.parse(timeStr, formatter);
System.out.println("Parsed time (custom): " + parsedTime2);

6. 其他实用方法

Duration 的结合使用

LocalTime 可以与 Duration 类结合使用进行时间计算:

import java.time.Duration;
import java.time.LocalTime;

LocalTime time = LocalTime.of(14, 30, 45);
Duration duration = Duration.ofHours(2);

// 加一个时间段
LocalTime newTime = time.plus(duration);
System.out.println("Time after adding duration: " + newTime);

// 减一个时间段
newTime = time.minus(duration);
System.out.println("Time after subtracting duration: " + newTime);
与当前时间的比较

可以使用 ChronoUnit 枚举计算两个时间之间的差异:

import java.time.LocalTime;
import java.time.temporal.ChronoUnit;

LocalTime time1 = LocalTime.of(14, 30, 45);
LocalTime time2 = LocalTime.of(16, 45, 30);

long hoursBetween = ChronoUnit.HOURS.between(time1, time2);
long minutesBetween = ChronoUnit.MINUTES.between(time1, time2);
long secondsBetween = ChronoUnit.SECONDS.between(time1, time2);

System.out.println("Hours between: " + hoursBetween);
System.out.println("Minutes between: " + minutesBetween);
System.out.println("Seconds between: " + secondsBetween);

总结

LocalTime 类在处理纯时间(没有日期部分)时非常高效且方便。它提供了丰富的操作和比较时间的方法,能够与其他 Java 时间类(如 DurationPeriod)结合使用。通过掌握 LocalTime 的各种方法和操作,能够更好地处理时间相关的任务。

(五)java.time.LocalDate

LocalDate 是 Java 8 中 java.time 包的一部分,用于表示日期而无时间部分。它是不可变且线程安全的。LocalDate 类提供了多种方法来创建、操作和比较日期。以下是对 LocalDate 类的详细讲解和使用示例。

1. 创建 LocalDate 对象

使用工厂方法

可以使用静态工厂方法创建 LocalDate 对象:

import java.time.LocalDate;

// 当前日期
LocalDate currentDate = LocalDate.now();
System.out.println("Current date: " + currentDate);

// 指定日期
LocalDate specificDate = LocalDate.of(2023, 10, 5);
System.out.println("Specific date: " + specificDate);

// 解析日期字符串
LocalDate parsedDate = LocalDate.parse("2023-10-05");
System.out.println("Parsed date: " + parsedDate);

2. 获取日期的各个部分

可以通过 LocalDate 的方法获取日期的各个部分:

import java.time.LocalDate;

LocalDate date = LocalDate.of(2023, 10, 5);

int year = date.getYear();
int month = date.getMonthValue();
int day = date.getDayOfMonth();
int dayOfYear = date.getDayOfYear();
String dayOfWeek = date.getDayOfWeek().name();

System.out.println("Year: " + year);
System.out.println("Month: " + month);
System.out.println("Day: " + day);
System.out.println("Day of year: " + dayOfYear);
System.out.println("Day of week: " + dayOfWeek);

3. 修改 LocalDate 对象

LocalDate 提供了多种方法来修改日期,这些方法会返回一个新的 LocalDate 对象,因为 LocalDate 是不可变的。

加和减日期
import java.time.LocalDate;

LocalDate date = LocalDate.of(2023, 10, 5);

// 加日期
LocalDate datePlusDays = date.plusDays(10);
LocalDate datePlusWeeks = date.plusWeeks(2);
LocalDate datePlusMonths = date.plusMonths(1);
LocalDate datePlusYears = date.plusYears(1);

System.out.println("Date plus 10 days: " + datePlusDays);
System.out.println("Date plus 2 weeks: " + datePlusWeeks);
System.out.println("Date plus 1 month: " + datePlusMonths);
System.out.println("Date plus 1 year: " + datePlusYears);

// 减日期
LocalDate dateMinusDays = date.minusDays(10);
LocalDate dateMinusWeeks = date.minusWeeks(2);
LocalDate dateMinusMonths = date.minusMonths(1);
LocalDate dateMinusYears = date.minusYears(1);

System.out.println("Date minus 10 days: " + dateMinusDays);
System.out.println("Date minus 2 weeks: " + dateMinusWeeks);
System.out.println("Date minus 1 month: " + dateMinusMonths);
System.out.println("Date minus 1 year: " + dateMinusYears);
设置日期
import java.time.LocalDate;

LocalDate date = LocalDate.of(2023, 10, 5);

// 设置日期
LocalDate newDateWithYear = date.withYear(2022);
LocalDate newDateWithMonth = date.withMonth(8);
LocalDate newDateWithDay = date.withDayOfMonth(15);

System.out.println("Date with year set to 2022: " + newDateWithYear);
System.out.println("Date with month set to August: " + newDateWithMonth);
System.out.println("Date with day set to 15: " + newDateWithDay);

4. 比较 LocalDate 对象

LocalDate 提供了多种比较方法:

import java.time.LocalDate;

LocalDate date1 = LocalDate.of(2023, 10, 5);
LocalDate date2 = LocalDate.of(2024, 10, 5);

// 比较日期
boolean isBefore = date1.isBefore(date2); // true
boolean isAfter = date1.isAfter(date2);   // false
boolean isEqual = date1.isEqual(date2);   // false

System.out.println("date1 is before date2: " + isBefore);
System.out.println("date1 is after date2: " + isAfter);
System.out.println("date1 is equal to date2: " + isEqual);

// 使用 compareTo 方法
int comparisonResult = date1.compareTo(date2);
if (comparisonResult < 0) {
    System.out.println("date1 is before date2");
} else if (comparisonResult > 0) {
    System.out.println("date1 is after date2");
} else {
    System.out.println("date1 is equal to date2");
}

5. 格式化和解析 LocalDate

转换为字符串

LocalDate 支持使用 DateTimeFormatter 来格式化为字符串:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

LocalDate date = LocalDate.of(2023, 10, 5);

// 使用默认格式
String formattedDate = date.toString();
System.out.println("Default formatted date: " + formattedDate);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
String customFormattedDate = date.format(formatter);
System.out.println("Custom formatted date: " + customFormattedDate);
从字符串解析

可以使用 DateTimeFormatter 从字符串解析 LocalDate 对象:

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

String dateStr = "05/10/2023";

// 使用默认格式
LocalDate parsedDate1 = LocalDate.parse("2023-10-05");
System.out.println("Parsed date (default): " + parsedDate1);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate parsedDate2 = LocalDate.parse(dateStr, formatter);
System.out.println("Parsed date (custom): " + parsedDate2);

6. 其他实用方法

检查闰年

可以使用 isLeapYear 方法来检查某一年是否是闰年:

import java.time.LocalDate;

LocalDate date = LocalDate.of(2023, 10, 5);

boolean isLeapYear = date.isLeapYear();
System.out.println("Is 2023 a leap year? " + isLeapYear);
获取一个月中的天数

可以使用 lengthOfMonthlengthOfYear 方法获取月份和年份的天数:

import java.time.LocalDate;

LocalDate date = LocalDate.of(2023, 10, 5);

int daysInMonth = date.lengthOfMonth();
int daysInYear = date.lengthOfYear();

System.out.println("Days in October 2023: " + daysInMonth);
System.out.println("Days in year 2023: " + daysInYear);
获取特定日期

可以使用 with 方法来获取特定日期:

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

LocalDate date = LocalDate.of(2023, 10, 5);

// 获取该月的第一天
LocalDate firstDayOfMonth = date.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("First day of month: " + firstDayOfMonth);

// 获取该月的最后一天
LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Last day of month: " + lastDayOfMonth);

// 获取下一个星期一
LocalDate nextMonday = date.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("Next Monday: " + nextMonday);

7. 使用 Period

使用 Period 计算日期之间的差异

Period 类可以用来计算两个日期之间的差异:

import java.time.LocalDate;
import java.time.Period;

LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2024, 1, 1);

Period period = Period.between(startDate, endDate);
System.out.println("Period between start and end date: " + period);
System.out.println("Years: " + period.getYears());
System.out.println("Months: " + period.getMonths());
System.out.println("Days: " + period.getDays());

8. 与其他时间类的结合使用

LocalDate 可以与 LocalTimeLocalDateTime 结合使用以处理日期和时间:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

LocalDate date = LocalDate.of(2023, 10, 5);
LocalTime time = LocalTime.of(14, 30, 45);

// 创建 LocalDateTime 对象
LocalDateTime dateTime = LocalDateTime.of(date, time);
System.out.println("LocalDateTime: " + dateTime);

// 从 LocalDateTime 获取 LocalDate 和 LocalTime
LocalDate extractedDate = dateTime.toLocalDate();
LocalTime extractedTime = dateTime.toLocalTime();
System.out.println("Extracted LocalDate: " + extractedDate);
System.out.println("Extracted LocalTime: " + extractedTime);

小结

LocalDate 类在处理日期(不包含时间)时非常高效和方便。它提供了丰富的方法来创建、操作和比较日期,能够与其他 Java 时间类(如 Period)结合使用。通过掌握 LocalDate 的各种方法和操作,可以更好地处理日期相关的任务。

(六)java.time.LocalDateTime

LocalDateTime 是 Java 8 中 java.time 包的一部分,它结合了 LocalDateLocalTime,用于表示日期和时间(但没有时区信息)。LocalDateTime 类是不可变且线程安全的。以下是对 LocalDateTime 类的详细讲解和使用示例。

1. 创建 LocalDateTime 对象

使用工厂方法

可以使用静态工厂方法来创建 LocalDateTime 对象:

import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;

// 当前日期和时间
LocalDateTime currentDateTime = LocalDateTime.now();
System.out.println("Current date and time: " + currentDateTime);

// 指定日期和时间
LocalDateTime specificDateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);
System.out.println("Specific date and time: " + specificDateTime);

// 使用 LocalDate 和 LocalTime 创建
LocalDate date = LocalDate.of(2023, 10, 5);
LocalTime time = LocalTime.of(14, 30, 45);
LocalDateTime dateTimeFromComponents = LocalDateTime.of(date, time);
System.out.println("DateTime from LocalDate and LocalTime: " + dateTimeFromComponents);

// 解析日期和时间字符串
LocalDateTime parsedDateTime = LocalDateTime.parse("2023-10-05T14:30:45");
System.out.println("Parsed date and time: " + parsedDateTime);

2. 获取日期和时间的各个部分

可以通过 LocalDateTime 的方法获取日期和时间的各个部分:

import java.time.LocalDateTime;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);

int year = dateTime.getYear();
int month = dateTime.getMonthValue();
int day = dateTime.getDayOfMonth();
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
int nano = dateTime.getNano();
String dayOfWeek = dateTime.getDayOfWeek().name();

System.out.println("Year: " + year);
System.out.println("Month: " + month);
System.out.println("Day: " + day);
System.out.println("Hour: " + hour);
System.out.println("Minute: " + minute);
System.out.println("Second: " + second);
System.out.println("Nano: " + nano);
System.out.println("Day of week: " + dayOfWeek);

3. 修改 LocalDateTime 对象

LocalDateTime 提供了多种方法来修改日期和时间,这些方法会返回一个新的 LocalDateTime 对象,因为 LocalDateTime 是不可变的。

加和减日期和时间
import java.time.LocalDateTime;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);

// 加日期和时间
LocalDateTime dateTimePlusDays = dateTime.plusDays(10);
LocalDateTime dateTimePlusWeeks = dateTime.plusWeeks(2);
LocalDateTime dateTimePlusMonths = dateTime.plusMonths(1);
LocalDateTime dateTimePlusYears = dateTime.plusYears(1);
LocalDateTime dateTimePlusHours = dateTime.plusHours(2);
LocalDateTime dateTimePlusMinutes = dateTime.plusMinutes(15);
LocalDateTime dateTimePlusSeconds = dateTime.plusSeconds(30);
LocalDateTime dateTimePlusNanos = dateTime.plusNanos(1000000);

System.out.println("DateTime plus 10 days: " + dateTimePlusDays);
System.out.println("DateTime plus 2 weeks: " + dateTimePlusWeeks);
System.out.println("DateTime plus 1 month: " + dateTimePlusMonths);
System.out.println("DateTime plus 1 year: " + dateTimePlusYears);
System.out.println("DateTime plus 2 hours: " + dateTimePlusHours);
System.out.println("DateTime plus 15 minutes: " + dateTimePlusMinutes);
System.out.println("DateTime plus 30 seconds: " + dateTimePlusSeconds);
System.out.println("DateTime plus 1 millisecond: " + dateTimePlusNanos);

// 减日期和时间
LocalDateTime dateTimeMinusDays = dateTime.minusDays(10);
LocalDateTime dateTimeMinusWeeks = dateTime.minusWeeks(2);
LocalDateTime dateTimeMinusMonths = dateTime.minusMonths(1);
LocalDateTime dateTimeMinusYears = dateTime.minusYears(1);
LocalDateTime dateTimeMinusHours = dateTime.minusHours(2);
LocalDateTime dateTimeMinusMinutes = dateTime.minusMinutes(15);
LocalDateTime dateTimeMinusSeconds = dateTime.minusSeconds(30);
LocalDateTime dateTimeMinusNanos = dateTime.minusNanos(1000000);

System.out.println("DateTime minus 10 days: " + dateTimeMinusDays);
System.out.println("DateTime minus 2 weeks: " + dateTimeMinusWeeks);
System.out.println("DateTime minus 1 month: " + dateTimeMinusMonths);
System.out.println("DateTime minus 1 year: " + dateTimeMinusYears);
System.out.println("DateTime minus 2 hours: " + dateTimeMinusHours);
System.out.println("DateTime minus 15 minutes: " + dateTimeMinusMinutes);
System.out.println("DateTime minus 30 seconds: " + dateTimeMinusSeconds);
System.out.println("DateTime minus 1 millisecond: " + dateTimeMinusNanos);
设置日期和时间
import java.time.LocalDateTime;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);

// 设置日期和时间
LocalDateTime newDateTimeWithYear = dateTime.withYear(2022);
LocalDateTime newDateTimeWithMonth = dateTime.withMonth(8);
LocalDateTime newDateTimeWithDay = dateTime.withDayOfMonth(15);
LocalDateTime newDateTimeWithHour = dateTime.withHour(10);
LocalDateTime newDateTimeWithMinute = dateTime.withMinute(20);
LocalDateTime newDateTimeWithSecond = dateTime.withSecond(50);
LocalDateTime newDateTimeWithNano = dateTime.withNano(123456789);

System.out.println("DateTime with year set to 2022: " + newDateTimeWithYear);
System.out.println("DateTime with month set to August: " + newDateTimeWithMonth);
System.out.println("DateTime with day set to 15: " + newDateTimeWithDay);
System.out.println("DateTime with hour set to 10: " + newDateTimeWithHour);
System.out.println("DateTime with minute set to 20: " + newDateTimeWithMinute);
System.out.println("DateTime with second set to 50: " + newDateTimeWithSecond);
System.out.println("DateTime with nano set to 123456789: " + newDateTimeWithNano);

4. 比较 LocalDateTime 对象

LocalDateTime 提供了多种比较方法:

import java.time.LocalDateTime;

LocalDateTime dateTime1 = LocalDateTime.of(2023, 10, 5, 14, 30, 45);
LocalDateTime dateTime2 = LocalDateTime.of(2024, 10, 5, 14, 30, 45);

// 比较日期和时间
boolean isBefore = dateTime1.isBefore(dateTime2); // true
boolean isAfter = dateTime1.isAfter(dateTime2);   // false
boolean isEqual = dateTime1.isEqual(dateTime2);   // false

System.out.println("dateTime1 is before dateTime2: " + isBefore);
System.out.println("dateTime1 is after dateTime2: " + isAfter);
System.out.println("dateTime1 is equal to dateTime2: " + isEqual);

// 使用 compareTo 方法
int comparisonResult = dateTime1.compareTo(dateTime2);
if (comparisonResult < 0) {
    System.out.println("dateTime1 is before dateTime2");
} else if (comparisonResult > 0) {
    System.out.println("dateTime1 is after dateTime2");
} else {
    System.out.println("dateTime1 is equal to dateTime2");
}

5. 格式化和解析 LocalDateTime

转换为字符串

LocalDateTime 支持使用 DateTimeFormatter 来格式化为字符串:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);

// 使用默认格式
String formattedDateTime = dateTime.toString();
System.out.println("Default formatted date and time: " + formattedDateTime);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String customFormattedDateTime = dateTime.format(formatter);
System.out.println("Custom formatted date and time: " + customFormattedDateTime);
从字符串解析

可以使用 DateTimeFormatter 从字符串解析 LocalDateTime 对象:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

String dateTimeStr = "2023-10-05 14:30:45";

// 使用默认格式
LocalDateTime parsedDateTime1 = LocalDateTime.parse("2023-10-05T14:30:45");
System.out.println("Parsed date and time (default): " + parsedDateTime1);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsedDateTime2 = LocalDateTime.parse(dateTimeStr, formatter);
System.out.println("Parsed date and time (custom): " + parsedDateTime2);

6. 其他实用方法

获取 LocalDateLocalTime

可以从 LocalDateTime 对象中提取 LocalDateLocalTime 对象:

import java.time.LocalDateTime;
import java.time.LocalDate;
import java.time.LocalTime;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);

// 获取 LocalDate 和 LocalTime
LocalDate date = dateTime.toLocalDate();
LocalTime time = dateTime.toLocalTime();

System.out.println("Date: " + date);
System.out.println("Time: " + time);
获取特定日期和时间

可以使用 with 方法来获取特定日期和时间:

import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;
import java.time.DayOfWeek;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);

// 获取该月的第一天
LocalDateTime firstDayOfMonth = dateTime.with(TemporalAdjusters.firstDayOfMonth());
System.out.println("First day of month: " + firstDayOfMonth);

// 获取该月的最后一天
LocalDateTime lastDayOfMonth = dateTime.with(TemporalAdjusters.lastDayOfMonth());
System.out.println("Last day of month: " + lastDayOfMonth);

// 获取下一个星期一
LocalDateTime nextMonday = dateTime.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
System.out.println("Next Monday: " + nextMonday);

7. 使用 PeriodDuration

使用 Period 计算日期之间的差异

Period 类可以用来计算两个日期之间的差异:

import java.time.LocalDate;
import java.time.Period;

LocalDate startDate = LocalDate.of(2023, 1, 1);
LocalDate endDate = LocalDate.of(2024, 1, 1);

Period period = Period.between(startDate, endDate);
System.out.println("Years: " + period.getYears());
System.out.println("Months: " + period.getMonths());
System.out.println("Days: " + period.getDays());
使用 Duration 计算时间之间的差异

Duration 类可以用来计算两个时间点之间的差异,并用于时间计算:

import java.time.Duration;
import java.time.LocalDateTime;

LocalDateTime startDateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);
LocalDateTime endDateTime = LocalDateTime.of(2023, 10, 5, 16, 30, 45);

Duration duration = Duration.between(startDateTime, endDateTime);
System.out.println("Hours: " + duration.toHours());
System.out.println("Minutes: " + duration.toMinutes());
System.out.println("Seconds: " + duration.getSeconds());

8. 与时区结合使用

LocalDateTime 不包含时区信息,但可以与 ZonedDateTime 结合使用来处理时区:

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;

LocalDateTime dateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);
ZoneId zoneId = ZoneId.of("America/New_York");

// 转换为 ZonedDateTime
ZonedDateTime zonedDateTime = dateTime.atZone(zoneId);
System.out.println("ZonedDateTime: " + zonedDateTime);

// 从 ZonedDateTime 获取 LocalDateTime
LocalDateTime localDateTimeFromZoned = zonedDateTime.toLocalDateTime();
System.out.println("LocalDateTime from ZonedDateTime: " + localDateTimeFromZoned);

小结

LocalDateTime 类在处理包含日期和时间(没有时区信息)的场景时非常方便。它提供了丰富的方法来创建、操作和比较日期和时间,能够与其他 Java 时间类(如 PeriodDurationZonedDateTime)结合使用。通过掌握 LocalDateTime 的各种方法和操作,可以更好地处理各种复杂的日期和时间相关的任务。

(七)java.time.ZonedDateTime

ZonedDateTime 是 Java 8 中 java.time 包的一部分,它结合了 LocalDate, LocalTimeZoneId,用于表示带有时区的日期和时间。ZonedDateTime 是不可变且线程安全的。以下是对 ZonedDateTime 类的详细讲解和使用示例。

1. 创建 ZonedDateTime 对象

使用工厂方法

可以使用静态工厂方法创建 ZonedDateTime 对象:

import java.time.ZonedDateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;

// 当前日期和时间,使用默认时区
ZonedDateTime currentDateTime = ZonedDateTime.now();
System.out.println("Current date and time: " + currentDateTime);

// 当前日期和时间,使用指定时区
ZonedDateTime currentDateTimeInZone = ZonedDateTime.now(ZoneId.of("America/New_York"));
System.out.println("Current date and time in New York: " + currentDateTimeInZone);

// 指定日期和时间,使用指定时区
LocalDateTime localDateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);
ZonedDateTime specificDateTime = ZonedDateTime.of(localDateTime, ZoneId.of("Asia/Tokyo"));
System.out.println("Specific date and time in Tokyo: " + specificDateTime);

// 解析日期和时间字符串
ZonedDateTime parsedDateTime = ZonedDateTime.parse("2023-10-05T14:30:45+09:00[Asia/Tokyo]");
System.out.println("Parsed date and time: " + parsedDateTime);

2. 获取日期、时间和时区的各个部分

可以通过 ZonedDateTime 的方法获取日期、时间和时区的各个部分:

import java.time.ZonedDateTime;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

int year = dateTime.getYear();
int month = dateTime.getMonthValue();
int day = dateTime.getDayOfMonth();
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
int nano = dateTime.getNano();
String dayOfWeek = dateTime.getDayOfWeek().name();
ZoneId zone = dateTime.getZone();

System.out.println("Year: " + year);
System.out.println("Month: " + month);
System.out.println("Day: " + day);
System.out.println("Hour: " + hour);
System.out.println("Minute: " + minute);
System.out.println("Second: " + second);
System.out.println("Nano: " + nano);
System.out.println("Day of week: " + dayOfWeek);
System.out.println("Zone: " + zone);

3. 修改 ZonedDateTime 对象

ZonedDateTime 提供了多种方法来修改日期、时间和时区,这些方法会返回一个新的 ZonedDateTime 对象,因为 ZonedDateTime 是不可变的。

加和减日期和时间
import java.time.ZonedDateTime;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 加日期和时间
ZonedDateTime dateTimePlusDays = dateTime.plusDays(10);
ZonedDateTime dateTimePlusWeeks = dateTime.plusWeeks(2);
ZonedDateTime dateTimePlusMonths = dateTime.plusMonths(1);
ZonedDateTime dateTimePlusYears = dateTime.plusYears(1);
ZonedDateTime dateTimePlusHours = dateTime.plusHours(2);
ZonedDateTime dateTimePlusMinutes = dateTime.plusMinutes(15);
ZonedDateTime dateTimePlusSeconds = dateTime.plusSeconds(30);
ZonedDateTime dateTimePlusNanos = dateTime.plusNanos(1000000);

System.out.println("DateTime plus 10 days: " + dateTimePlusDays);
System.out.println("DateTime plus 2 weeks: " + dateTimePlusWeeks);
System.out.println("DateTime plus 1 month: " + dateTimePlusMonths);
System.out.println("DateTime plus 1 year: " + dateTimePlusYears);
System.out.println("DateTime plus 2 hours: " + dateTimePlusHours);
System.out.println("DateTime plus 15 minutes: " + dateTimePlusMinutes);
System.out.println("DateTime plus 30 seconds: " + dateTimePlusSeconds);
System.out.println("DateTime plus 1 millisecond: " + dateTimePlusNanos);

// 减日期和时间
ZonedDateTime dateTimeMinusDays = dateTime.minusDays(10);
ZonedDateTime dateTimeMinusWeeks = dateTime.minusWeeks(2);
ZonedDateTime dateTimeMinusMonths = dateTime.minusMonths(1);
ZonedDateTime dateTimeMinusYears = dateTime.minusYears(1);
ZonedDateTime dateTimeMinusHours = dateTime.minusHours(2);
ZonedDateTime dateTimeMinusMinutes = dateTime.minusMinutes(15);
ZonedDateTime dateTimeMinusSeconds = dateTime.minusSeconds(30);
ZonedDateTime dateTimeMinusNanos = dateTime.minusNanos(1000000);

System.out.println("DateTime minus 10 days: " + dateTimeMinusDays);
System.out.println("DateTime minus 2 weeks: " + dateTimeMinusWeeks);
System.out.println("DateTime minus 1 month: " + dateTimeMinusMonths);
System.out.println("DateTime minus 1 year: " + dateTimeMinusYears);
System.out.println("DateTime minus 2 hours: " + dateTimeMinusHours);
System.out.println("DateTime minus 15 minutes: " + dateTimeMinusMinutes);
System.out.println("DateTime minus 30 seconds: " + dateTimeMinusSeconds);
System.out.println("DateTime minus 1 millisecond: " + dateTimeMinusNanos);
设置日期、时间和时区
import java.time.ZonedDateTime;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 设置日期和时间
ZonedDateTime newDateTimeWithYear = dateTime.withYear(2022);
ZonedDateTime newDateTimeWithMonth = dateTime.withMonth(8);
ZonedDateTime newDateTimeWithDay = dateTime.withDayOfMonth(15);
ZonedDateTime newDateTimeWithHour = dateTime.withHour(10);
ZonedDateTime newDateTimeWithMinute = dateTime.withMinute(20);
ZonedDateTime newDateTimeWithSecond = dateTime.withSecond(50);
ZonedDateTime newDateTimeWithNano = dateTime.withNano(123456789);

System.out.println("DateTime with year set to 2022: " + newDateTimeWithYear);
System.out.println("DateTime with month set to August: " + newDateTimeWithMonth);
System.out.println("DateTime with day set to 15: " + newDateTimeWithDay);
System.out.println("DateTime with hour set to 10: " + newDateTimeWithHour);
System.out.println("DateTime with minute set to 20: " + newDateTimeWithMinute);
System.out.println("DateTime with second set to 50: " + newDateTimeWithSecond);
System.out.println("DateTime with nano set to 123456789: " + newDateTimeWithNano);

// 设置时区
ZonedDateTime dateTimeInNewZone = dateTime.withZoneSameInstant(ZoneId.of("Europe/London"));
System.out.println("DateTime in new zone (London): " + dateTimeInNewZone);

4. 比较 ZonedDateTime 对象

ZonedDateTime 提供了多种比较方法:

import java.time.ZonedDateTime;

ZonedDateTime dateTime1 = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));
ZonedDateTime dateTime2 = ZonedDateTime.of(2024, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 比较日期和时间
boolean isBefore = dateTime1.isBefore(dateTime2); // true
boolean isAfter = dateTime1.isAfter(dateTime2);   // false
boolean isEqual = dateTime1.isEqual(dateTime2);   // false

System.out.println("dateTime1 is before dateTime2: " + isBefore);
System.out.println("dateTime1 is after dateTime2: " + isAfter);
System.out.println("dateTime1 is equal to dateTime2: " + isEqual);

// 使用 compareTo 方法
int comparisonResult = dateTime1.compareTo(dateTime2);
if (comparisonResult < 0) {
    System.out.println("dateTime1 is before dateTime2");
} else if (comparisonResult > 0) {
    System.out.println("dateTime1 is after dateTime2");
} else {
    System.out.println("dateTime1 is equal to dateTime2");
}

5. 格式化和解析 ZonedDateTime

转换为字符串

ZonedDateTime 支持使用 DateTimeFormatter 来格式化为字符串:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 使用默认格式
String formattedDateTime = dateTime.toString();
System.out.println("Default formatted date and time: " + formattedDateTime);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z z");
String customFormattedDateTime = dateTime.format(formatter);
System.out.println("Custom formatted date and time: " + customFormattedDateTime);
从字符串解析

可以使用 DateTimeFormatter 从字符串解析 ZonedDateTime 对象:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

String dateTimeStr = "2023-10-05 14:30:45 +0900 JST";

// 使用默认格式
ZonedDateTime parsedDateTime1 = ZonedDateTime.parse("2023-10-05T14:30:45+09:00[Asia/Tokyo]");
System.out.println("Parsed date and time (default): " + parsedDateTime1);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z z");
ZonedDateTime parsedDateTime2 = ZonedDateTime.parse(dateTimeStr, formatter);
System.out.println("Parsed date and time (custom): " + parsedDateTime2);

6. 其他实用方法

Instant 结合使用

可以将 ZonedDateTime 转换为 Instant,并相互转换:

import java.time.ZonedDateTime;
import java.time.Instant;
import java.time.ZoneId;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 转换为 Instant
Instant instant = dateTime.toInstant();
System.out.println("Instant: " + instant);

// 从 Instant 转换回 ZonedDateTime
ZonedDateTime dateTimeFromInstant = instant.atZone(ZoneId.of("Asia/Tokyo"));
System.out.println("ZonedDateTime from Instant: " + dateTimeFromInstant);
获取 LocalDateTime

可以从 ZonedDateTime 提取 LocalDateTime 对象:

import java.time.ZonedDateTime;
import java.time.LocalDateTime;
import java.time.ZoneId;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 获取 LocalDateTime
LocalDateTime localDateTime = dateTime.toLocalDateTime();
System.out.println("LocalDateTime: " + localDateTime);
转换为其他时区

可以将 ZonedDateTime 转换为其他时区:

import java.time.ZonedDateTime;
import java.time.ZoneId;

ZonedDateTime dateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

// 转换为其他时区
ZonedDateTime dateTimeInNewZone = dateTime.withZoneSameInstant(ZoneId.of("Europe/London"));
System.out.println("DateTime in new zone (London): " + dateTimeInNewZone);

7. 使用 PeriodDuration

使用 Period 计算日期之间的差异

Period 类可以用来计算两个日期之间的差异:

import java.time.Period;
import java.time.ZonedDateTime;
import java.time.ZoneId;

ZonedDateTime startDateTime = ZonedDateTime.of(2023, 1, 1, 0, 0, 0, 0, ZoneId.of("Asia/Tokyo"));
ZonedDateTime endDateTime = ZonedDateTime.of(2024, 1, 1, 0, 0, 0, 0, ZoneId.of("Asia/Tokyo"));

Period period = Period.between(startDateTime.toLocalDate(), endDateTime.toLocalDate());
System.out.println("Years: " + period.getYears());
System.out.println("Months: " + period.getMonths());
System.out.println("Days: " + period.getDays());
使用 Duration 计算时间之间的差异

Duration 类可以用于计算两个时间点之间的差异,并用于时间计算:

import java.time.Duration;
import java.time.ZonedDateTime;
import java.time.ZoneId;

ZonedDateTime startDateTime = ZonedDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneId.of("Asia/Tokyo"));
ZonedDateTime endDateTime = ZonedDateTime.of(2023, 10, 5, 16, 30, 45, 0, ZoneId.of("Asia/Tokyo"));

Duration duration = Duration.between(startDateTime, endDateTime);
System.out.println("Hours: " + duration.toHours());
System.out.println("Minutes: " + duration.toMinutes());
System.out.println("Seconds: " + duration.getSeconds());

小结

ZonedDateTime 类在处理带有时区的日期和时间时非常有用。它提供了丰富的方法来创建、操作和比较带有时区的日期和时间,并能与其他 Java 时间类(如 InstantPeriodDuration)结合使用。通过掌握 ZonedDateTime 的各种方法和操作,可以更好地处理各类复杂的日期和时间相关任务。

(八)java.time.OffsetDateTime

OffsetDateTime 是 Java 8 中 java.time 包的一部分,用于表示带有偏移量的日期和时间。它结合了 LocalDateTimeZoneOffset,表示特定时区的时间,但不包括时区规则。OffsetDateTime 是不可变且线程安全的。以下是对 OffsetDateTime 类的详细讲解和使用示例。

1. 创建 OffsetDateTime 对象

使用工厂方法

可以使用静态工厂方法创建 OffsetDateTime 对象:

import java.time.OffsetDateTime;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

// 当前日期和时间,使用系统默认的偏移量
OffsetDateTime currentDateTime = OffsetDateTime.now();
System.out.println("Current date and time: " + currentDateTime);

// 当前日期和时间,使用指定的偏移量
OffsetDateTime currentDateTimeWithOffset = OffsetDateTime.now(ZoneOffset.ofHours(-5));
System.out.println("Current date and time with offset: " + currentDateTimeWithOffset);

// 指定日期和时间,使用指定的偏移量
LocalDateTime localDateTime = LocalDateTime.of(2023, 10, 5, 14, 30, 45);
ZoneOffset offset = ZoneOffset.ofHours(9);
OffsetDateTime specificDateTime = OffsetDateTime.of(localDateTime, offset);
System.out.println("Specific date and time with offset: " + specificDateTime);

// 解析日期和时间字符串
OffsetDateTime parsedDateTime = OffsetDateTime.parse("2023-10-05T14:30:45+09:00");
System.out.println("Parsed date and time: " + parsedDateTime);

2. 获取日期、时间和偏移量的各个部分

可以通过 OffsetDateTime 的方法获取日期、时间和偏移量的各个部分:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

int year = dateTime.getYear();
int month = dateTime.getMonthValue();
int day = dateTime.getDayOfMonth();
int hour = dateTime.getHour();
int minute = dateTime.getMinute();
int second = dateTime.getSecond();
int nano = dateTime.getNano();
String dayOfWeek = dateTime.getDayOfWeek().name();
ZoneOffset zoneOffset = dateTime.getOffset();

System.out.println("Year: " + year);
System.out.println("Month: " + month);
System.out.println("Day: " + day);
System.out.println("Hour: " + hour);
System.out.println("Minute: " + minute);
System.out.println("Second: " + second);
System.out.println("Nano: " + nano);
System.out.println("Day of week: " + dayOfWeek);
System.out.println("Zone offset: " + zoneOffset);

3. 修改 OffsetDateTime 对象

OffsetDateTime 提供了多种方法来修改日期、时间和偏移量,这些方法会返回一个新的 OffsetDateTime 对象,因为 OffsetDateTime 是不可变的。

加和减日期和时间
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 加日期和时间
OffsetDateTime dateTimePlusDays = dateTime.plusDays(10);
OffsetDateTime dateTimePlusWeeks = dateTime.plusWeeks(2);
OffsetDateTime dateTimePlusMonths = dateTime.plusMonths(1);
OffsetDateTime dateTimePlusYears = dateTime.plusYears(1);
OffsetDateTime dateTimePlusHours = dateTime.plusHours(2);
OffsetDateTime dateTimePlusMinutes = dateTime.plusMinutes(15);
OffsetDateTime dateTimePlusSeconds = dateTime.plusSeconds(30);
OffsetDateTime dateTimePlusNanos = dateTime.plusNanos(1000000);

System.out.println("DateTime plus 10 days: " + dateTimePlusDays);
System.out.println("DateTime plus 2 weeks: " + dateTimePlusWeeks);
System.out.println("DateTime plus 1 month: " + dateTimePlusMonths);
System.out.println("DateTime plus 1 year: " + dateTimePlusYears);
System.out.println("DateTime plus 2 hours: " + dateTimePlusHours);
System.out.println("DateTime plus 15 minutes: " + dateTimePlusMinutes);
System.out.println("DateTime plus 30 seconds: " + dateTimePlusSeconds);
System.out.println("DateTime plus 1 millisecond: " + dateTimePlusNanos);

// 减日期和时间
OffsetDateTime dateTimeMinusDays = dateTime.minusDays(10);
OffsetDateTime dateTimeMinusWeeks = dateTime.minusWeeks(2);
OffsetDateTime dateTimeMinusMonths = dateTime.minusMonths(1);
OffsetDateTime dateTimeMinusYears = dateTime.minusYears(1);
OffsetDateTime dateTimeMinusHours = dateTime.minusHours(2);
OffsetDateTime dateTimeMinusMinutes = dateTime.minusMinutes(15);
OffsetDateTime dateTimeMinusSeconds = dateTime.minusSeconds(30);
OffsetDateTime dateTimeMinusNanos = dateTime.minusNanos(1000000);

System.out.println("DateTime minus 10 days: " + dateTimeMinusDays);
System.out.println("DateTime minus 2 weeks: " + dateTimeMinusWeeks);
System.out.println("DateTime minus 1 month: " + dateTimeMinusMonths);
System.out.println("DateTime minus 1 year: " + dateTimeMinusYears);
System.out.println("DateTime minus 2 hours: " + dateTimeMinusHours);
System.out.println("DateTime minus 15 minutes: " + dateTimeMinusMinutes);
System.out.println("DateTime minus 30 seconds: " + dateTimeMinusSeconds);
System.out.println("DateTime minus 1 millisecond: " + dateTimeMinusNanos);
设置日期、时间和偏移量
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 设置日期和时间
OffsetDateTime newDateTimeWithYear = dateTime.withYear(2022);
OffsetDateTime newDateTimeWithMonth = dateTime.withMonth(8);
OffsetDateTime newDateTimeWithDay = dateTime.withDayOfMonth(15);
OffsetDateTime newDateTimeWithHour = dateTime.withHour(10);
OffsetDateTime newDateTimeWithMinute = dateTime.withMinute(20);
OffsetDateTime newDateTimeWithSecond = dateTime.withSecond(50);
OffsetDateTime newDateTimeWithNano = dateTime.withNano(123456789);

System.out.println("DateTime with year set to 2022: " + newDateTimeWithYear);
System.out.println("DateTime with month set to August: " + newDateTimeWithMonth);
System.out.println("DateTime with day set to 15: " + newDateTimeWithDay);
System.out.println("DateTime with hour set to 10: " + newDateTimeWithHour);
System.out.println("DateTime with minute set to 20: " + newDateTimeWithMinute);
System.out.println("DateTime with second set to 50: " + newDateTimeWithSecond);
System.out.println("DateTime with nano set to 123456789: " + newDateTimeWithNano);

// 设置偏移量
OffsetDateTime newDateTimeWithOffset = dateTime.withOffsetSameInstant(ZoneOffset.ofHours(-5));
System.out.println("DateTime with new offset: " + newDateTimeWithOffset);

4. 比较 OffsetDateTime 对象

OffsetDateTime 提供了多种比较方法:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

OffsetDateTime dateTime1 = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));
OffsetDateTime dateTime2 = OffsetDateTime.of(2024, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 比较日期和时间
boolean isBefore = dateTime1.isBefore(dateTime2); // true
boolean isAfter = dateTime1.isAfter(dateTime2);   // false
boolean isEqual = dateTime1.isEqual(dateTime2);   // false

System.out.println("dateTime1 is before dateTime2: " + isBefore);
System.out.println("dateTime1 is after dateTime2: " + isAfter);
System.out.println("dateTime1 is equal to dateTime2: " + isEqual);

// 使用 compareTo 方法
int comparisonResult = dateTime1.compareTo(dateTime2);
if (comparisonResult < 0) {
    System.out.println("dateTime1 is before dateTime2");
} else if (comparisonResult > 0) {
    System.out.println("dateTime1 is after dateTime2");
} else {
    System.out.println("dateTime1 is equal to dateTime2");
}

5. 格式化和解析 OffsetDateTime

转换为字符串

OffsetDateTime 支持使用 DateTimeFormatter 来格式化为字符串:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 使用默认格式
String formattedDateTime = dateTime.toString();
System.out.println("Default formatted date and time: " + formattedDateTime);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
String customFormattedDateTime = dateTime.format(formatter);
System.out.println("Custom formatted date and time: " + customFormattedDateTime);
从字符串解析

可以使用 DateTimeFormatter 从字符串解析 OffsetDateTime 对象:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

String dateTimeStr = "2023-10-05 14:30:45 +09:00";

// 使用默认格式
OffsetDateTime parsedDateTime1 = OffsetDateTime.parse("2023-10-05T14:30:45+09:00");
System.out.println("Parsed date and time (default): " + parsedDateTime1);

// 使用自定义格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
OffsetDateTime parsedDateTime2 = OffsetDateTime.parse(dateTimeStr, formatter);
System.out.println("Parsed date and time (custom): " + parsedDateTime2);

6. 其他实用方法

Instant 结合使用

可以将 OffsetDateTime 转换为 Instant,并相互转换:

import java.time.OffsetDateTime;
import java.time.Instant;
import java.time.ZoneOffset;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 转换为 Instant
Instant instant = dateTime.toInstant();
System.out.println("Instant: " + instant);

// 从 Instant 转换回 OffsetDateTime
OffsetDateTime dateTimeFromInstant = instant.atOffset(ZoneOffset.ofHours(9));
System.out.println("OffsetDateTime from Instant: " + dateTimeFromInstant);
获取 LocalDateTime

可以从 OffsetDateTime 提取 LocalDateTime 对象:

import java.time.OffsetDateTime;
import java.time.LocalDateTime;
import java.time.ZoneOffset;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 获取 LocalDateTime
LocalDateTime localDateTime = dateTime.toLocalDateTime();
System.out.println("LocalDateTime: " + localDateTime);
转换为 ZonedDateTime

可以将 OffsetDateTime 转换为 ZonedDateTime

import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.time.ZoneOffset;
import java.time.ZoneId;

OffsetDateTime dateTime = OffsetDateTime.of(2023, 10, 5, 14, 30, 45, 0, ZoneOffset.ofHours(9));

// 转换为 ZonedDateTime
ZonedDateTime zonedDateTime = dateTime.toZonedDateTime();
System.out.println("ZonedDateTime: " + zonedDateTime);

// 从 ZonedDateTime 转换回 OffsetDateTime
OffsetDateTime dateTimeFromZoned = zonedDateTime.oOffsetDateTime();
System.out.println("OffsetDateTime from ZonedDateTime: " + dateTimeFromZoned);

7. 实际应用场景

记录事件时间

在日志记录或事件记录中,可以使用 OffsetDateTime 记录发生的精确时间,包括时区信息,便于全球协作和时间同步:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class EventLogger {
    public static void logEvent(String event) {
        OffsetDateTime currentTime = OffsetDateTime.now(ZoneOffset.UTC);
        System.out.println("Event: " + event + " at " + currentTime);
    }

    public static void main(String[] args) {
        logEvent("Application started");
    }
}
API 传输

在 RESTful API 的开发中,通过 JSON 格式传输时间数据时,可以使用 OffsetDateTime 来确保传输的时间包含时区信息,避免跨时区的时间误差:

import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TimeApiExample {
    public static void main(String[] args) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        OffsetDateTime dateTime = OffsetDateTime.now(ZoneOffset.UTC);

        // 序列化为 JSON
        String json = objectMapper.writeValueAsString(dateTime);
        System.out.println("Serialized JSON: " + json);

        // 反序列化为 OffsetDateTime
        OffsetDateTime deserializedDateTime = objectMapper.readValue(json, OffsetDateTime.class);
        System.out.println("Deserialized OffsetDateTime: " + deserializedDateTime);
    }
}

小结

OffsetDateTime 类在处理带有偏移量(时区)的日期和时间时非常有用。它提供了丰富的方法来创建、操作和比较带有时区的日期和时间,并能与其他 Java 时间类(如 InstantLocalDateTimeZonedDateTime)结合使用。通过掌握 OffsetDateTime 的各种方法和操作,可以更好地处理各类复杂的日期和时间相关任务。

(九)java.time.temporal.ChronoUnit

ChronoUnit 是 Java 8 中 java.time.temporal 包的一部分,用于度量时间单位的标准集。它在处理日期和时间的计算时非常有用。ChronoUnit 提供了一组常用的时间单位,例如天(DAYS)、小时(HOURS)、分钟(MINUTES)等。以下是对 ChronoUnit 类的详细讲解和使用示例。

1. ChronoUnit 常用方法

常用时间单位

ChronoUnit 提供了多种时间单位,包括但不限于:

  • NANOS
  • MICROS
  • MILLIS
  • SECONDS
  • MINUTES
  • HOURS
  • HALF_DAYS
  • DAYS
  • WEEKS
  • MONTHS
  • YEARS
  • DECADES
  • CENTURIES
  • MILLENNIA
  • ERAS
  • FOREVER

每个时间单位都实现了 TemporalUnit 接口,因此可以在任何支持 TemporalUnit 的方法中使用。

2. 计算两个日期或时间之间的差异

可以使用 ChronoUnit 计算两个日期或时间之间的差异:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

LocalDate date1 = LocalDate.of(2023, 1, 1);
LocalDate date2 = LocalDate.of(2024, 1, 1);

// 计算两个日期之间的天数差异
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println("Days between: " + daysBetween);

LocalDateTime dateTime1 = LocalDateTime.of(2023, 1, 1, 0, 0);
LocalDateTime dateTime2 = LocalDateTime.of(2023, 1, 2, 12, 0);

// 计算两个日期时间之间的小时差异
long hoursBetween = ChronoUnit.HOURS.between(dateTime1, dateTime2);
System.out.println("Hours between: " + hoursBetween);

ChronoUnit.between 方法接受两个 Temporal 对象,并返回它们之间以指定单位度量的差异。

3. 加减时间

可以使用 ChronoUnit 在日期或时间上增加或减少时间:

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

LocalDate date = LocalDate.of(2023, 1, 1);

// 增加时间
LocalDate newDatePlus = date.plus(1, ChronoUnit.MONTHS);
System.out.println("Date plus 1 month: " + newDatePlus);

// 减少时间
LocalDate newDateMinus = date.minus(10, ChronoUnit.DAYS);
System.out.println("Date minus 10 days: " + newDateMinus);

Temporal 接口(例如 LocalDateLocalDateTime)的 plusminus 方法都可以接受 TemporalUnit 作为参数。

4. 更多示例

计算年龄

可以使用 ChronoUnit 计算特定日期到现在的差异,例如计算年龄:

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

LocalDate birthDate = LocalDate.of(1990, 1, 1);
LocalDate currentDate = LocalDate.now();

// 计算年龄
long age = ChronoUnit.YEARS.between(birthDate, currentDate);
System.out.println("Age: " + age);
倒计时

可以使用 ChronoUnit 提供倒计时功能:

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;

LocalDate eventDate = LocalDate.of(2024, 12, 31);
LocalDate currentDate = LocalDate.now();

// 计算天数倒计时
long daysUntilEvent = ChronoUnit.DAYS.between(currentDate, eventDate);
System.out.println("Days until event: " + daysUntilEvent);

5. 与其他时间类结合使用

ChronoUnit 可以与其他 Temporal 类结合使用,如:

  • ZonedDateTime
  • OffsetDateTime
  • Instant
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;

ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime zonedDateTime2 = zonedDateTime1.plusHours(5);

// 计算两个 ZonedDateTime 之间的小时差异
long hoursBetween = ChronoUnit.HOURS.between(zonedDateTime1, zonedDateTime2);
System.out.println("Hours between: " + hoursBetween);

6. ChronoUnit 常见操作总结

  • 计算两个日期或时间之间的差异:使用 ChronoUnit.between 方法。
  • 加减日期或时间:使用 Temporal 类的 plusminus 方法,结合 ChronoUnit
  • 与其他时间类结合:如 ZonedDateTimeOffsetDateTimeInstant

通过掌握 ChronoUnit 的各种操作,可以在处理日期和时间计算时更加灵活和高效。

(十)java.time.format.DateTimeFormatter

DateTimeFormatter 是 Java 8 引入的 java.time.format 包中的一个类,用于格式化和解析日期和时间。它是 java.time 包的一部分,提供了线程安全、功能强大且易于使用的日期和时间格式化工具。

1. 创建 DateTimeFormatter 对象

DateTimeFormatter 可以通过多种方式创建,包括使用预定义的格式化器、模式字符串和自定义解析样式。

使用预定义的格式化器

Java 提供了一些预定义的 DateTimeFormatter 实例,可以直接使用:

import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;

DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = now.format(formatter);
System.out.println("Formatted date and time: " + formattedDateTime);
使用模式字符串

可以使用模式字符串创建 DateTimeFormatter 对象:

import java.time.format.DateTimeFormatter;
import java.time.LocalDateTime;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = now.format(formatter);
System.out.println("Formatted date and time: " + formattedDateTime);
使用自定义解析样式

可以结合模式字符串和解析样式创建 DateTimeFormatter 对象:

import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.LocalDateTime;
import java.util.Locale;

DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.US);
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = now.format(formatter);
System.out.println("Formatted date and time: " + formattedDateTime);

2. 格式化日期和时间

使用 DateTimeFormatter 对象的 format 方法可以将 LocalDateTimeZonedDateTime 等日期时间对象格式化为字符串:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

LocalDateTime now = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = now.format(formatter);
System.out.println("Formatted date and time: " + formattedDateTime);

3. 解析日期和时间字符串

使用 DateTimeFormatter 对象的 parse 方法可以将字符串解析为日期时间对象:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

String dateTimeString = "2023-10-05 14:30:45";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString, formatter);
System.out.println("Parsed date and time: " + parsedDateTime);

4. 模式字符串详解

DateTimeFormatter 的模式字符串使用特定的字母表示日期和时间的各个部分:

  • y:年
  • M:月
  • d:天
  • H:小时(24小时制)
  • h:小时(12小时制)
  • m:分钟
  • s:秒
  • S:毫秒
  • E:星期几
  • D:一年中的天数
  • F:一个月中的星期几
  • w:一年中的周数
  • W:一个月中的周数
  • a:AM/PM 标记
  • k:小时(1-24)
  • K:小时(0-11)
  • z:时区名称
  • Z:时区偏移量
  • X:时区偏移量(ISO 8601 格式)

示例:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, MMMM dd, yyyy 'at' hh:mm:ss a z");
LocalDateTime now = LocalDateTime.now();
String formattedDateTime = now.format(formatter);
System.out.println("Custom formatted date and time: " + formattedDateTime);

5. 处理时区和区域设置

DateTimeFormatter 可以与 ZoneIdLocale 结合使用,以处理不同的时区和区域设置:

import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

ZoneId zoneId = ZoneId.of("America/New_York");
ZonedDateTime zonedDateTime = ZonedDateTime.now(zoneId);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z").withLocale(Locale.US);
String formattedDateTime = zonedDateTime.format(formatter);
System.out.println("Formatted date and time with timezone: " + formattedDateTime);

6. 综合实例

以下是一个综合实例,展示如何在实际应用中使用 DateTimeFormatter 类:

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.util.Locale;

public class DateTimeFormatterExample {
    public static void main(String[] args) {
        // 获取当前日期和时间
        LocalDateTime now = LocalDateTime.now();
        System.out.println("Current date and time: " + now);

        // 使用预定义的格式化器
        DateTimeFormatter isoFormatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
        String isoFormattedDateTime = now.format(isoFormatter);
        System.out.println("ISO formatted date and time: " + isoFormattedDateTime);

        // 使用模式字符串
        DateTimeFormatter patternFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String patternFormattedDateTime = now.format(patternFormatter);
        System.out.println("Pattern formatted date and time: " + patternFormattedDateTime);

        // 使用自定义解析样式
        DateTimeFormatter localizedFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM).withLocale(Locale.US);
        String localizedFormattedDateTime = now.format(localizedFormatter);
        System.out.println("Localized formatted date and time: " + localizedFormattedDateTime);

        // 解析日期和时间字符串
        String dateTimeString = "2023-10-05 14:30:45";
        LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeString, patternFormatter);
        System.out.println("Parsed date and time: " + parsedDateTime);

        // 处理时区和区域设置
        ZoneId zoneId = ZoneId.of("America/New_York");
        ZonedDateTime zonedDateTime = ZonedDateTime.now(zoneId);
        DateTimeFormatter zoneFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z").withLocale(Locale.US);
        String zoneFormattedDateTime = zonedDateTime.format(zoneFormatter);
        System.out.println("Formatted date and time with timezone: " + zoneFormattedDateTime);
    }
}

小结

DateTimeFormatter 是 Java 8 引入的用于格式化和解析日期和时间的高级工具。它提供了线程安全、功能丰富且易于使用的 API,适用于现代 Java 应用中的日期和时间处理。掌握 DateTimeFormatter 的创建、格式化和解析方法,以及如何处理时区和区域设置,可以帮助开发者更高效地处理日期和时间相关任务。

(十一)java.time.temporal.TemporalAdjusters

TemporalAdjustersjava.time.temporal 包中的一个类,提供了一系列静态方法,用于创建 TemporalAdjuster 实例来调整日期和时间对象。它们可以用于各种常见的日期操作,例如调整到下一个或上一个特定的日期(如下一个周一、上一个月的最后一天)。

1. TemporalAdjuster 接口概述

TemporalAdjuster 是一个函数式接口,定义了一个调整日期或时间的方法:

import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public interface TemporalAdjuster {
    Temporal adjustInto(Temporal temporal);
}

它被设计为用于调整 Temporal 对象的操作工具,而 TemporalAdjusters 类提供了一些常见的实现。

2. 创建 TemporalAdjuster 实例

可以使用 TemporalAdjusters 中的静态方法来创建常见的 TemporalAdjuster 实例。

调整到下一个或上一个特定的日期
  • next(DayOfWeek dayOfWeek):调整到下一个指定的星期几。
  • previous(DayOfWeek dayOfWeek):调整到上一个指定的星期几。
  • nextOrSame(DayOfWeek dayOfWeek):调整到下一个或同一天的指定星期几。
  • previousOrSame(DayOfWeek dayOfWeek):调整到上一个或同一天的指定星期几。

示例:

import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

LocalDate today = LocalDate.now();
LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
LocalDate previousFriday = today.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));

System.out.println("Today: " + today);
System.out.println("Next Monday: " + nextMonday);
System.out.println("Previous Friday: " + previousFriday);
调整到月的开始和结束
  • firstDayOfMonth():调整到当前月的第一天。
  • lastDayOfMonth():调整到当前月的最后一天。
  • firstDayOfNextMonth():调整到下一个月的第一天。
  • firstDayOfYear():调整到当前年的第一天。
  • lastDayOfYear():调整到当前年的最后一天。
  • firstDayOfNextYear():调整到下一年的第一天。

示例:

import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;

LocalDate today = LocalDate.now();
LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
LocalDate lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());

System.out.println("Today: " + today);
System.out.println("First day of this month: " + firstDayOfMonth);
System.out.println("Last day of this month: " + lastDayOfMonth);
调整到特定日期
  • dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek):调整到当前月的第几个指定星期几(例如,第一个周三)。

示例:

import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;

LocalDate today = LocalDate.now();
LocalDate thirdWednesday = today.with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.WEDNESDAY));

System.out.println("Today: " + today);
System.out.println("Third Wednesday of this month: " + thirdWednesday);

3. 自定义 TemporalAdjuster

除了使用 TemporalAdjusters 提供的静态方法外,还可以创建自定义的 TemporalAdjuster

使用 TemporalAdjuster 接口
import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class NextPaydayAdjuster implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        LocalDate date = LocalDate.from(temporal);
        LocalDate nextPayday = date.withDayOfMonth(15);
        if (date.getDayOfMonth() > 15) {
            nextPayday = date.withDayOfMonth(1).plusMonths(1);
            nextPayday = nextPayday.withDayOfMonth(15);
        }
        return temporal.with(nextPayday);
    }
}

// 使用自定义的 TemporalAdjuster
LocalDate today = LocalDate.now();
LocalDate nextPayday = today.with(new NextPaydayAdjuster());

System.out.println("Today: " + today);
System.out.println("Next payday: " + nextPayday);
使用 Lambda 表达式

由于 TemporalAdjuster 是一个函数式接口,可以使用 Lambda 表达式创建:

import java.time.LocalDate;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

TemporalAdjuster nextPaydayAdjuster = (Temporal temporal) -> {
    LocalDate date = LocalDate.from(temporal);
    LocalDate nextPayday = date.withDayOfMonth(15);
    if (date.getDayOfMonth() > 15) {
        nextPayday = date.withDayOfMonth(1).plusMonths(1);
        nextPayday = nextPayday.withDayOfMonth(15);
    }
    return temporal.with(nextPayday);
};

// 使用 Lambda 表达式创建的 TemporalAdjuster
LocalDate today = LocalDate.now();
LocalDate nextPayday = today.with(nextPaydayAdjuster);

System.out.println("Today: " + today);
System.out.println("Next payday: " + nextPayday);

4. 综合实例

以下是一个综合实例,展示如何在实际应用中使用 TemporalAdjusters 类和自定义 TemporalAdjuster

import java.time.LocalDate;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class TemporalAdjustersExample {
    public static void main(String[] args) {
        // 今日日期
        LocalDate today = LocalDate.now();
        System.out.println("Today: " + today);

        // 使用 TemporalAdjusters 进行日期调整
        LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
        LocalDate previousFriday = today.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
        LocalDate firstDayOfMonth = today.with(TemporalAdjusters.firstDayOfMonth());
        LocalDate lastDayOfMonth = today.with(TemporalAdjusters.lastDayOfMonth());
        LocalDate thirdWednesday = today.with(TemporalAdjusters.dayOfWeekInMonth(3, DayOfWeek.WEDNESDAY));

        System.out.println("Next Monday: " + nextMonday);
        System.out.println("Previous Friday: " + previousFriday);
        System.out.println("First day of this month: " + firstDayOfMonth);
        System.out.println("Last day of this month: " + lastDayOfMonth);
        System.out.println("Third Wednesday of this month: " + thirdWednesday);

        // 使用自定义的 TemporalAdjuster
        TemporalAdjuster nextPaydayAdjuster = new NextPaydayAdjuster();
        LocalDate nextPayday = today.with(nextPaydayAdjuster);
        System.out.println("Next payday: " + nextPayday);

        // 使用 Lambda 表达式创建的 TemporalAdjuster
        TemporalAdjuster nextEndOfQuarterAdjuster = (Temporal temporal) -> {
            LocalDate date = LocalDate.from(temporal);
            LocalDate endOfQuarter;
            int month = date.getMonthValue();
            if (month <= 3) {
                endOfQuarter = LocalDate.of(date.getYear(), 3, 31);
            } else if (month <= 6) {
                endOfQuarter = LocalDate.of(date.getYear(), 6, 30);
            } else if (month <= 9) {
                endOfQuarter = LocalDate.of(date.getYear(), 9, 30);
            } else {
                endOfQuarter = LocalDate.of(date.getYear(), 12, 31);
            }
            return temporal.with(endOfQuarter);
        };

        LocalDate nextEndOfQuarter = today.with(nextEndOfQuarterAdjuster);
        System.out.println("Next end of quarter: " + nextEndOfQuarter);
    }

    // 自定义 TemporalAdjuster 实现
    static class NextPaydayAdjuster implements TemporalAdjuster {
        @Override
        public Temporal adjustInto(Temporal temporal) {
            LocalDate date = LocalDate.from(temporal);
            LocalDate nextPayday = date.withDayOfMonth(15);
            if (date.getDayOfMonth() > 15) {
                nextPayday = date.withDayOfMonth(1).plusMonths(1);
                nextPayday = nextPayday.withDayOfMonth(15);
            }
            return temporal.with(nextPayday);
        }
    }
}

小结

TemporalAdjusters 类提供了一系列用于调整日期和时间的静态方法,使得日期操作变得非常直观便捷。掌握这些方法以及如何创建自定义的 TemporalAdjuster,可以让开发者高效地处理各种日期调整需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值