Java 8 的 LocalDate 和 LocalTime 是线程安全、不可变的纯日期/纯时间类,分别处理年月日和时分秒,不含时区与时刻概念,适用于生日、营业时间等场景。

Java 8 引入了全新的日期时间 API(java.time 包),彻底替代了老旧、线程不安全的 Date 和 SimpleDateFormat。其中 LocalDate 和 LocalTime 是最常用的基础类,分别专注处理“纯日期”(年-月-日)和“纯时间”(时:分:秒.纳秒),不含时区、不含时刻(instant)概念,语义清晰、不可变、线程安全。
LocalDate:只管年月日,不关心几点几分
LocalDate 表示一个不带时间、不带时区的日期,比如“2025年4月5日”。它适合处理生日、合同生效日、节假日等仅需日期的场景。
- 获取当前日期:
LocalDate.now()(默认使用系统时区的本地日期) - 构造指定日期:
LocalDate.of(2025, 4, 5)或LocalDate.parse("2025-04-05")(字符串格式必须是 ISO 格式 yyyy-MM-dd) - 计算日期差:
long days = date1.until(date2, ChronoUnit.DAYS),或用Period.between(date1, date2)得到“2年3个月5天”这样的结构化结果 - 加减日期:
date.plusDays(7)、date.minusMonths(1)—— 返回新对象(原对象不变)
LocalTime:只管时分秒,不关心哪年哪月
LocalTime 表示一天中的时间点,例如“14:30:45.123”,不绑定具体日期,也不含时区信息。适用于排班表、营业时间、定时任务触发时刻等。
- 获取当前时间:
LocalTime.now() - 构造指定时间:
LocalTime.of(14, 30)、LocalTime.of(9, 0, 30, 500_000_000)(时、分、秒、纳秒),或解析:LocalTime.parse("09:15:30") - 比较与计算:
time1.isBefore(time2)、time1.plusMinutes(90);注意不能跨日运算(如 23:00 + 2 小时会得到 01:00,但不会自动进到第二天) - 获取字段值:
time.getHour()、time.getMinute()、time.getSecond()、time.getNano()
LocalDate + LocalTime = LocalDateTime(组合使用很自然)
虽然它们各自独立,但常一起用于构建完整的时间点(仍无时区):LocalDateTime dt = LocalDate.now().atTime(LocalTime.now()),或更直接地:LocalDateTime.now()。也可拆解:localDateTime.toLocalDate()、localDateTime.toLocalTime()。
立即学习“Java免费学习笔记(深入)”;
- 避免混用旧 API:不要把
LocalDate和java.util.Date直接转换,要用atStartOfDay()+atZone(ZoneId.systemDefault()).toInstant()等桥接方法 - 格式化输出:用
DateTimeFormatter,例如LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月dd日")) - 输入校验提醒:
parse()方法遇到非法字符串(如 "2025-02-30")会抛出DateTimeParseException,建议包裹 try-catch
常见误区与提醒
初学者容易混淆 LocalDate/LocalTime 和 Instant/ZonedDateTime。记住:LocalXXX 类不表示真实世界中的某个“时刻”(instant),只是日历/钟表上的局部读数。 它们不能直接用于记录事件发生时间(应选 Instant),也不能用于跨时区计算(应选 ZonedDateTime)。
- LocalDate 不等于 “今天”——它依赖系统默认时区的本地日期,服务器部署在纽约,
now()就是纽约当天,不是北京时间 - LocalTime 没有“上午/下午”概念:
LocalTime.NOON是 12:00,LocalTime.MIDNIGHT是 00:00,但of(12, 0)就是中午,of(0, 0)就是午夜,没有 AM/PM 属性 - 所有操作都返回新实例:
date.plusDays(1)不改变原 date,务必接收返回值


















