Java 8 日期操作、解析与格式化

Java 8 日期操作、解析与格式化:实战指南

Java 8 的 java.time API 彻底革新了日期和时间的处理方式,告别了 SimpleDateFormat 的线程不安全问题和 Calendar 的复杂操作。本文将聚焦 日期操纵、解析与格式化 的核心技巧,并提供可直接复用的代码示例。


一、日期的基础操作

Java 8 通过 LocalDateLocalTimeLocalDateTime 等类提供了直观的日期操作方法。

1. 创建日期对象

// 创建指定日期
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(); 

2. 日期增减操作

// 增加或减少时间单位
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点

3. 调整日期到特定值

有的时候,你需要进行一些更加复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。这时,你可以使用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象,更加灵活地处理日期。对于最常见的用例,日期和时间API已经提供了大量预定义的TemporalAdjuster。你可以通过TemporalAdjuster类的静态工厂方法访问它们,如下所示。
Java 8 日期操作、解析与格式化_第1张图片

// 调整到某月的第一天
LocalDate firstDayOfMonth = LocalDate.now().with(TemporalAdjusters.firstDayOfMonth());

// 调整到下一个周一
LocalDate nextMonday = LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.MONDAY));

// 自定义调整(如设置到当月底)
LocalDate lastDayOfMonth = LocalDate.now().with(TemporalAdjusters.lastDayOfMonth());

二、日期解析(String → Date)

使用 DateTimeFormatter 将字符串转换为日期对象,线程安全且支持严格模式

1. 基础解析

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsedDate = LocalDateTime.parse("2025-03-30 14:30:00", formatter);

2. 处理不同格式

// 解析带时区的字符串
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);

3. 严格模式避免错误

// 默认宽松模式:无效日期(如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); // 必须合法

三、日期格式化(Date → String)

通过 DateTimeFormatter 将日期对象格式化为可读字符串。

1. 基础格式化

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"

2. 预定义格式化器

// 使用内置格式(如 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"

3. 本地化格式化

// 根据Locale自动适配格式
DateTimeFormatter germanFormatter = DateTimeFormatter
    .ofLocalizedDateTime(FormatStyle.LONG)
    .withLocale(Locale.GERMAN);
String germanDate = LocalDateTime.now().format(germanFormatter); // "30. März 2025 um 14:30:45"

四、时区处理

通过 ZonedDateTimeZoneId 管理跨时区时间。

1. 转换时区

// 上海时间 → 纽约时间
ZonedDateTime shanghaiTime = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYorkTime = shanghaiTime.withZoneSameInstant(ZoneId.of("America/New_York"));

2. 格式化带时区的日期

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss Z");
String formatted = newYorkTime.format(formatter); // "2025-03-30 02:30:45 -0400"

五、常见问题解决

1. 计算两个日期之间的天数

LocalDate start = LocalDate.of(2025, 3, 1);
LocalDate end = LocalDate.of(2025, 3, 30);
long daysBetween = ChronoUnit.DAYS.between(start, end); // 29

2. 判断是否是周末

LocalDate date = LocalDate.now();
boolean isWeekend = date.getDayOfWeek() == DayOfWeek.SATURDAY 
    || date.getDayOfWeek() == DayOfWeek.SUNDAY;

3. 处理季度

// 自定义季度逻辑
int quarter = (date.getMonthValue() - 1) / 3 + 1; // 返回1-4

六、总结

Java 8 的日期 API 提供了:

  • 直观的操作:如 plusDays()withMonth() 等方法。
  • 安全的解析与格式化DateTimeFormatter 线程安全且支持严格校验。
  • 强大的时区管理:通过 ZonedDateTime 轻松处理全球化时间。

最佳实践
✅ 优先使用 java.time 而非 Date/Calendar
✅ 复杂日期逻辑用 TemporalAdjusters 简化
✅ 涉及时区时始终明确指定 ZoneId

你可能感兴趣的:(java,日期操纵,解析,格式化,日期)