1. 概述

Java 8 的发布彻底改变了日期处理的方式。新的 java.time 包下的 Date & Time API 相比老旧的 java.util.DateCalendar,使用起来更加直观、安全且不易出错。本文聚焦于如何创建带有具体值的 LocalDate,这是日常开发中非常常见的需求。

LocalDatejava.time 包中的核心类之一,它是一个✅ 不可变、线程安全的对象,仅用于表示日期(年月日),❌ 不包含时间部分,也不带时区信息。

接下来,我们将系统性地介绍几种创建 LocalDate 实例的方法。

2. 使用 of() 方法创建自定义 LocalDate

这是最直接、最常用的方式。我们可以通过 LocalDate.of() 工厂方法传入年、月、日来创建一个指定日期。

以创建 2020 年 1 月 8 日为例:

LocalDate date = LocalDate.of(2020, 1, 8);

⚠️ 注意:月份参数使用数字时,1 表示一月,12 表示十二月,不是从 0 开始的,这一点和 Calendar 类完全不同,避免了常见的“月份踩坑”。

更推荐的做法是使用 Month 枚举,代码可读性更强,也更安全:

LocalDate date = LocalDate.of(2020, Month.JANUARY, 8);

此外,LocalDate 还提供了基于“纪元日”(Epoch Day)的创建方式。纪元日是从 1970-01-01(UTC)开始计算的天数:

LocalDate date = LocalDate.ofEpochDay(18269); // 对应 2020-01-08

最后,如果知道某年中的第几天,也可以使用 ofYearDay() 方法:

LocalDate date = LocalDate.ofYearDay(2020, 8); // 2020 年的第 8 天,即 1 月 8 日

✅ 小结:of() 是最推荐的创建方式,清晰明了;Month 枚举优于魔法数字;ofEpochDayofYearDay 在特定场景下很有用。

3. 通过解析字符串创建 LocalDate

当日期以字符串形式存在(如从配置文件、网络接口或用户输入中获取)时,我们需要将其解析为 LocalDate

LocalDate.parse() 方法默认支持 ISO-8601 格式的字符串(yyyy-MM-dd):

LocalDate date = LocalDate.parse("2020-01-08");

如果字符串格式不同,比如 "8-Jan-2020",则需要配合 DateTimeFormatter 指定解析模式:

LocalDate date = LocalDate.parse("8-Jan-2020", DateTimeFormatter.ofPattern("d-MMM-yyyy"));

这里 "d-MMM-yyyy" 是自定义的格式模式:

  • d:表示日(1-31)
  • MMM:表示缩写的月份名称(如 Jan, Feb)
  • yyyy:表示四位年份

⚠️ 踩坑提醒:解析时务必确保字符串格式与 DateTimeFormatter 定义的模式完全匹配,否则会抛出 DateTimeParseException。建议在生产环境中对输入做校验。

4. 总结

本文系统梳理了 Java 8 Date & Time API 中创建 LocalDate 的四种主要方式:

  • LocalDate.of(year, month, day):最常用,推荐使用 Month 枚举
  • LocalDate.ofEpochDay(epochDay):基于纪元日创建
  • LocalDate.ofYearDay(year, dayOfYear):基于年内的第几天创建
  • LocalDate.parse(text, formatter):解析字符串,灵活支持各种格式

这些方法简单粗暴且类型安全,彻底告别了 SimpleDateFormat 的线程安全问题和 Calendar 的晦涩 API。

示例代码已托管至 GitHub: https://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-8-datetime-2


原始标题:Creating a LocalDate with Values in Java