Java 8 的 java.time
API 彻底革新了日期和时间的处理方式,告别了 SimpleDateFormat
的线程不安全问题和 Calendar
的复杂操作。本文将聚焦 日期操纵、解析与格式化 的核心技巧,并提供可直接复用的代码示例。
Java 8 通过 LocalDate
、LocalTime
、LocalDateTime
等类提供了直观的日期操作方法。
// 创建指定日期
LocalDate date = LocalDate.of(2025, Month.MARCH, 30); // 2025-03-30
LocalTime time = LocalTime.of(14, 30, 45); // 14:30:45
LocalDateTime dateTime = LocalDateTime.of(2025, 3, 30, 14, 30); // 2025-03-30T14:30
// 获取当前日期时间
LocalDateTime now = LocalDateTime.now();
// 增加或减少时间单位
LocalDate tomorrow = LocalDate.now().plusDays(1);
LocalDateTime nextHour = LocalDateTime.now().plusHours(1);
LocalDate lastMonth = LocalDate.now().minusMonths(1);
// 链式操作
LocalDateTime complexAdjust = LocalDateTime.now()
.plusWeeks(2)
.minusDays(3)
.withHour(10); // 设置小时为10点
有的时候,你需要进行一些更加复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象,更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的TemporalAdjuster。你可以通过TemporalAdjuster类的静态工厂方法访问它们,如下所示。
// 调整到某月的第一天
LocalDate firstDayOfMonth = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());
// 调整到下一个周一
LocalDate nextMonday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY));
// 自定义调整(如设置到当月底)
LocalDate lastDayOfMonth = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());
使用 DateTimeFormatter
将字符串转换为日期对象,线程安全且支持严格模式。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsedDate = LocalDateTime.parse("2025-03-30 14:30:00", formatter);
// 解析带时区的字符串
String str = "2025-03-30T14:30:45+08:00";
ZonedDateTime zonedTime = ZonedDateTime.parse(str, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
// 自定义复杂格式
DateTimeFormatter customFormatter = DateTimeFormatter.ofPattern("dd/MMM/yyyy HH:mm", Locale.US);
LocalDateTime date = LocalDateTime.parse("30/Mar/2025 14:30", customFormatter);
// 默认宽松模式:无效日期(如2025-02-30)会自动调整
LocalDate lenientDate = LocalDate.parse("2025-02-30"); // 自动转为2025-03-02
// 启用严格模式
DateTimeFormatter strictFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")
.withResolverStyle(ResolverStyle.STRICT);
LocalDate strictDate = LocalDate.parse("2025-02-28", strictFormatter); // 必须合法
通过 DateTimeFormatter
将日期对象格式化为可读字符串。
LocalDateTime now = LocalDateTime.now();
String formatted1 = now.format(DateTimeFormatter.ISO_DATE_TIME); // "2025-03-30T14:30:45"
String formatted2 = now.format(DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm")); // "2025年03月30日 14:30"
// 使用内置格式(如 ISO 标准)
String isoDate = LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE); // "2025-03-30"
String isoTime = LocalTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME); // "14:30:45.123"
// 根据Locale自动适配格式
DateTimeFormatter germanFormatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withLocale(Locale.GERMAN);
String germanDate = LocalDateTime.now().format(germanFormatter); // "30. März 2025 um 14:30:45"
通过 ZonedDateTime
和 ZoneId
管理跨时区时间。
// 上海时间 → 纽约时间
ZonedDateTime shanghaiTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(ZoneId.of("America/New_York"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z");
String formatted = newYorkTime.format(formatter); // "2025-03-30 02:30:45 -0400"
LocalDate start = LocalDate.of(2025, 3, 1);
LocalDate end = LocalDate.of(2025, 3, 30);
long daysBetween = ChronoUnit.DAYS.between(start, end); // 29
LocalDate date = LocalDate.now();
boolean isWeekend = date.getDayOfWeek() == DayOfWeek.SATURDAY
|| date.getDayOfWeek() == DayOfWeek.SUNDAY;
// 自定义季度逻辑
int quarter = (date.getMonthValue() - 1) / 3 + 1; // 返回1-4
Java 8 的日期 API 提供了:
plusDays()
、withMonth()
等方法。DateTimeFormatter
线程安全且支持严格校验。ZonedDateTime
轻松处理全球化时间。最佳实践:
✅ 优先使用 java.time
而非 Date
/Calendar
✅ 复杂日期逻辑用 TemporalAdjusters
简化
✅ 涉及时区时始终明确指定 ZoneId