日期时间API的使用整合 - java.time包
- 二、java.time包
- (一)java.time.Instant
- (二)java.time.Duration
- (三)java.time.Period
- (四)java.time.LocalTime
- (五)java.time.LocalDate
- (六)java.time.LocalDateTime
- (七)java.time.ZonedDateTime
- (八)java.time.OffsetDateTime
- (九)java.time.temporal.ChronoUnit
- (十)java.time.format.DateTimeFormatter
- (十一)java.time.temporal.TemporalAdjusters
二、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
对象
加减时间
可以使用 plus
和 minus
方法来进行时间的加减操作:
// 当前时间的 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
转换为 ZonedDateTime
或 OffsetDateTime
来进行格式化和解析:
格式化
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
类的 isBefore
、isAfter
和 equals
方法进行比较:
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
是不可变且线程安全的,因此在并发环境下使用非常安全。通过结合 Duration
、ZonedDateTime
和 DateTimeFormatter
等工具,可以充分发挥 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
对象
加和减
可以使用 plus
和 minus
方法来对 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
检查零和负数
可以使用 isZero
和 isNegative
方法来检查 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
对象
加和减
可以使用 plus
和 minus
方法来对 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
检查零和负数
可以使用 isZero
和 isNegative
方法来检查 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());
设置天数,月份,年份
可以使用 withDays
、withMonths
、withYears
方法来设置天数,月份,年份:
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 时间类(如 Duration
和 Period
)结合使用。通过掌握 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);
获取一个月中的天数
可以使用 lengthOfMonth
和 lengthOfYear
方法获取月份和年份的天数:
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
可以与 LocalTime
和 LocalDateTime
结合使用以处理日期和时间:
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
包的一部分,它结合了 LocalDate
和 LocalTime
,用于表示日期和时间(但没有时区信息)。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. 其他实用方法
获取 LocalDate
和 LocalTime
可以从 LocalDateTime
对象中提取 LocalDate
和 LocalTime
对象:
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. 使用 Period
和 Duration
使用 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 时间类(如 Period
、Duration
和 ZonedDateTime
)结合使用。通过掌握 LocalDateTime
的各种方法和操作,可以更好地处理各种复杂的日期和时间相关的任务。
(七)java.time.ZonedDateTime
ZonedDateTime
是 Java 8 中 java.time
包的一部分,它结合了 LocalDate
, LocalTime
和 ZoneId
,用于表示带有时区的日期和时间。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. 使用 Period
和 Duration
使用 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 时间类(如 Instant
、Period
和 Duration
)结合使用。通过掌握 ZonedDateTime
的各种方法和操作,可以更好地处理各类复杂的日期和时间相关任务。
(八)java.time.OffsetDateTime
OffsetDateTime
是 Java 8 中 java.time
包的一部分,用于表示带有偏移量的日期和时间。它结合了 LocalDateTime
和 ZoneOffset
,表示特定时区的时间,但不包括时区规则。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.t·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 时间类(如 Instant
、LocalDateTime
和 ZonedDateTime
)结合使用。通过掌握 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
接口(例如 LocalDate
、LocalDateTime
)的 plus
和 minus
方法都可以接受 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
类的plus
和minus
方法,结合ChronoUnit
。 - 与其他时间类结合:如
ZonedDateTime
、OffsetDateTime
和Instant
。
通过掌握 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
方法可以将 LocalDateTime
、ZonedDateTime
等日期时间对象格式化为字符串:
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
可以与 ZoneId
和 Locale
结合使用,以处理不同的时区和区域设置:
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
TemporalAdjusters
是 java.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
,可以让开发者高效地处理各种日期调整需求。