DateTimeFormatter ✨
在使用旧的Date对象时,我们使用SimpleDateFromat进行格式化显示。使用新的LocalDateTime或ZonedDateTime时,我们要进行格式化显示,就要用DateTimeFormatter。
和SimpleDateFormat不同的是,DateTimeFormatter不但是不变对象,它还是线程安全的。SimpleDateFormat不是线程安全的,使用的时候,只能在方法内部创建新的局部变量。而DateTimeFormatter可以只创建一个实例,到处引用。
创建DateTimeFormatter时,通过传入格式化字符串来实现:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");另一种创建方法是,传入格式化字符串时,同时执行Locale:
LocalDateTime date = LocalDateTime.now();
DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("E, yyyy-MMMM-dd HH:mm", Locale.US);
System.out.println(formatter1.format(date)); // Mon, 2025-January-20 14:02
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("E, yyyy-MMMM-dd HH:mm", Locale.CHINESE);
System.out.println(formatter2.format(date)); // 周一, 2025-一月-20 14:02这种方式可以按照Locale默认习惯格式化:
ZonedDateTime zonedDateTime = ZonedDateTime.now();
var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
System.out.println(formatter.format(zonedDateTime)); // 2023-08-26T21:50 GMT+08:00
var zhFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
System.out.println(zhFormatter.format(zonedDateTime)); // 2023 8月 26 周六 21:50
var usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
System.out.println(usFormatter.format(zonedDateTime)); // Sat, August/26/2023 21:50如果要自定义输出的格式,或者要把一个非ISO 8601格式的字符串解析成LocalDateTime,可以使用新的DateTimeFormatter:
LocalDateTime dateTime = LocalDateTime.now();
// 自定义日期时间格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");
System.out.println(dateTime.format(formatter)); // 20/01/2025 14:05:53
// 自定义格式解析
LocalDateTime dateTime2 = LocalDateTime.parse("20/09/2021 10:00:00", formatter);
System.out.println(dateTime2); // 2021-09-20T10:00LocalDateTime提供了对日期和时间进行加减的非常简单的链式调用:
LocalDateTime now = LocalDateTime.of(2020, 12, 31, 10, 10, 10);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
System.out.println(now); // 2020-12-31T10:10:10
// 加一天3小时5分钟
LocalDateTime after = now.plusDays(1).plusHours(3).plusMinutes(5);
System.out.println(after.format(formatter)); // 2021-01-01 13:15:10
// 减一天3小时5分钟
LocalDateTime before = now.minusDays(1).minusHours(3).minusMinutes(5);
System.out.println(before.format(formatter)); // 2020-12-30 07:05:10
// 减去1个月
LocalDateTime beforeMonth = now.minusMonths(1);
System.out.println(beforeMonth.format(formatter)); // 2020-11-30 10:10:10注意到月份加减会自动调整日期,例如从2020-12-31减去1个月得到的结果是2020-11-30,因为11月没有31日。
对日期和时间进行调整则使用withXxx()方法,例如:withHour(15)会把10:11:12变为15:11:12:
调整年:
withYear()调整月:
withMonth()调整日:
withDayOfMonth()调整时:
withHour()调整分:
withMinute()调整秒:
withSecond()
LocalDateTime now = LocalDateTime.of(2020, 12, 31, 10, 10, 10);
System.out.println(now); // 2020-12-31 10:10:10
// 日期变为12
System.out.println(now.withDayOfMonth(12)); // 2020-12-12T10:10:10
// 月份变为9
System.out.println(now.withMonth(9)); // 2020-09-30T10:10:10同样注意到调整月份时,会相应地调整日期,即把2020-12-31的月份调整为9时,日期也自动变为30。
实际上,LocalDateTime还有一个通用的with()方法允许我们做更复杂的运算。例如:
// 本月第一天0:00时刻:
LocalDateTime firstDay = LocalDate.now().withDayOfMonth(1).atStartOfDay();
System.out.println(firstDay); // 2023-08-01T00:00
// 本月最后1天:
LocalDate lastDay = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
System.out.println(lastDay); // 2023-08-31
// 下月第1天:
LocalDate nextMonthFirstDay = LocalDate.now().with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println(nextMonthFirstDay); // 2023-09-01
// 本月第1个周一:
LocalDate firstWeekday = LocalDate.now().with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY));
System.out.println(firstWeekday); // 2023-08-07对于计算某个月第1个周日这样的问题,新的API可以轻松完成。
要判断两个LocalDateTime的先后,可以使用isBefore()、isAfter()方法,对于LocalDate和LocalTime类似:
LocalDateTime now = LocalDateTime.now();
LocalDateTime target = LocalDateTime.of(2019, 11, 19, 8, 15, 0);
System.out.println(now.isBefore(target)); // false
System.out.println(LocalDate.now().isBefore(LocalDate.of(2019, 11, 19))); // true
System.out.println(LocalTime.now().isAfter(LocalTime.parse("08:15:00"))); // true注意到LocalDateTime无法与时间戳进行转换,因为LocalDateTime没有时区,无法确定某一时刻。后面我们要介绍的ZonedDateTime相当于LocalDateTime加时区的组合,它具有时区,可以与long表示的时间戳进行转换。
最后更新于
这有帮助吗?