Java 8 日期时间 API 全面指南:使用技巧与场景实践

关注我的公众号:【编程朝花夕拾】,可获取首发内容。

01 引言

日期类在日常开发中很常见,我们习惯了使用各种DateUtils工具包,直接处理java.util.Date类,包括计算、格式化、解析等操作。但是,在使用中存在线程安全等问题。

Java 8 引入的 java.time 包彻底解决了旧版 java.util.DateCalendar 的设计缺陷,提供了线程安全**、**直观易用且功能全面的日期时间处理方案。

习惯了以前的工具类,反而觉得Java 8中的日期类用起来不怎么顺手,本文将深入解析核心类、使用技巧及实际场景应用。

02 核心类解析

类名 描述 示例
LocalDate 仅含日期(年-月-日) 生日、会议日期
LocalTime 仅含时间(时:分:秒.纳秒) 打卡时间、营业时间
LocalDateTime 日期+时间(无时区) 本地事件记录
ZonedDateTime 带时区的完整日期时间 跨时区会议、航班时刻
Instant 时间戳(Unix 时间,精确到纳秒) 日志记录、性能计时
Period 日期区间(年/月/日) 计算年龄、项目周期
Duration 时间间隔(秒/纳秒) 程序执行时间、倒计时
DateTimeFormatter 日期格式化/解析 日期字符串转换

03 关键使用技巧

因为都是关于日期的类,所以他们之间都用几乎相同的API,我们以LocalDateTime为代表介绍其中的用法。

3.1 日期的创建和获取

java 复制代码
@Test
void test01() {
    // 获取当前日期
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now); 
    //2025-07-17T18:19:45.927848800

    // 自定义日期
    LocalDateTime localDateTime = LocalDateTime.of(2025, 7, 17, 12, 30, 20);
    System.out.println(localDateTime);
    // 2025-07-17T12:30:20

    // 通过秒和偏移量获取日期:偏移8小时
    LocalDateTime localDateTime1 = LocalDateTime.ofEpochSecond(System.currentTimeMillis()/1000, 8888, ZoneOffset.ofHours(8));
    System.out.println(localDateTime1);
    // 2025-07-17T18:19:45.000008888

    // 通过秒和偏移量获取日期:使用当前时区时间
    LocalDateTime localDateTime2 = LocalDateTime.ofEpochSecond(System.currentTimeMillis()/1000, 8888, ZoneOffset.from(ZonedDateTime.now()));
    System.out.println(localDateTime2);
    // 2025-07-17T18:19:45.000008888
}

需要说明的是LocalDateTime.ofEpochSecond()方法,通过当前的秒数+纳秒数+时区的偏移/时区时间来构建LocalDateTime对象。

通过LocalDateTime可以获取日期的年、月、日、时、分、秒、纳秒等参数。如图:

3.2 日期的运算和调整

java 复制代码
@Test
void test02() {
    // 获取当前日期
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now);
    // 2025-07-17T18:19:45.927848800
    
    // 时间计算:- 时间段
    LocalDateTime minus = now.minus(Duration.ofDays(1));
    System.out.println(minus);
    // 2025-07-16T18:19:45.927848800

    // 时间计算:+ 时间段
    LocalDateTime plus = now.plusDays(1);
    System.out.println(plus);
    // 2025-07-18T18:19:45.927848800
    
    // 获取本月第一天
    LocalDateTime with = now.with(TemporalAdjusters.firstDayOfMonth()).withHour(0).withMinute(0).withSecond(0).withNano(0);
    // LocalDateTime with = LocalDateTime.of(now.with(TemporalAdjusters.firstDayOfMonth()).toLocalDate(), LocalTime.MIN);
    System.out.println(with);
    // 2025-07-01T00:00

    // 获取本月最后一天
    LocalDateTime with2 = now.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59).withNano(999999999);
    // LocalDateTime with2 = LocalDateTime.of(now.with(TemporalAdjusters.firstDayOfMonth()).toLocalDate(), LocalTime.MAX);
    System.out.println(with2);
    // 2025-07-31T23:59:59.999999999
  
}

日期的调整需要用到调整器TemporalAdjusters

3.3 日期的比较

日期的比较和之前的差别不大

java 复制代码
@Test
void test03() {
    System.out.println(now.compareTo(now.plusSeconds(2)));
    // -1
    System.out.println(now.isEqual(now));
    // true
    System.out.println(now.isAfter(now.plusSeconds(2)));
    // false
    System.out.println(now.isBefore(now.plusSeconds(2)));
    // true
}

3.4 时区的处理

java 复制代码
@Test
void test04() {
    // 时区转化
    ZonedDateTime now = ZonedDateTime.now();
    System.out.println(now);
    // 2025-07-17T18:40:30.202283400+08:00[Asia/Shanghai]

    ZonedDateTime zonedDateTime = now.withZoneSameInstant(ZoneId.of("America/New_York"));
    System.out.println(zonedDateTime);
    // 2025-07-17T06:40:30.202283400-04:00[America/New_York]
}

3.5 时间间隔计算

java 复制代码
@Test
void test05() {
    // 不会向上取整
    long between = ChronoUnit.HOURS.between(LocalDateTime.now(), LocalDateTime.now().plusMinutes(40));
    System.out.println(between);
    // 0

    Period between1 = Period.between(LocalDate.now(), LocalDate.now().plusDays(2));
    System.out.println(between1.getDays());
    // 2
    System.out.println(between1.getYears());
    // 0

    long minutes = Duration.ofSeconds(59).toMinutes();
    System.out.println(minutes);
    // 0
}

这里需要注意的是,时间间隔的计算不会向上取整

3.6 高精度时间

java.time.Instant该采用的时间格式是yyyy-MM-ddTHH:mm:ss.SSSSSSSZ,比LocalDateTime多了一个后缀Z,表示该时间采用 ‌协调世界时(UTC)

java 复制代码
@Test
void test06() {
    Instant now = Instant.now();
    System.out.println(now);
    // 2025-07-17T10:47:08.873287Z

    // 转毫秒
    long epochMilli = now.toEpochMilli();
    System.out.println(epochMilli);
    // 1752749228873

    // 转秒
    System.out.println(now.getEpochSecond());
    // 1752749228
}

为什么这类要单独说呢,因为该类将是java.util.Datejava.time.LocalDateTime的桥梁。

3.7 日期之间的转化

java 复制代码
@Test
void test07() {
    // 转化
    Instant instant = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant();
    System.out.println(instant);
    // 2025-07-17T10:49:36.742740400Z

    LocalDate localDate = LocalDate.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(localDate);
    // 2025-07-17

    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    System.out.println(localDateTime);
    // 2025-07-17T18:49:36.742740400

    Date from = Date.from(instant);
    System.out.println(from);
    // Thu Jul 17 18:49:36 CST 2025

    Instant instant2 = from.toInstant();
    System.out.println(instant2);
    // 2025-07-17T10:49:36.742Z
}

3.8 日期格式化和解析

java 复制代码
@Test
void test06() {
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    LocalDateTime now = LocalDateTime.now();
    System.out.println(now.format(dateTimeFormatter));
    // 2025-07-17

    TemporalAccessor parse = dateTimeFormatter.parse("2025-02-04");
    System.out.println(LocalDate.from(parse));
    // 2025-02-04

    LocalDate parse1 = LocalDate.parse("2025-02-04", dateTimeFormatter);
    System.out.println(parse1);
    // 2025-02-04
}

04 小结

Java 8 日期时间 API 的核心优势:

  • 线程安全:所有类均为不可变对象
  • 链式调用 :流畅的 API 设计(如 plusDays().withHour()
  • 明确语义LocalDateZonedDateTime 等命名清晰
  • 强大工具 :内置 TemporalAdjustersChronoUnit

关键建议

  • 生产环境统一使用 java.time.format.DateTimeFormatter 替代 SimpleDateFormat
  • 复杂日期逻辑优先使用 TemporalAdjusters 而非手动计算
  • 分布式系统强制采用 UTC 时间存储(Instant

通过合理运用这些工具,可显著提升日期时间处理的准确性可维护性 ,彻底告别 Calendar.set(Calendar.MONTH, -1) 式的"魔法数字"陷阱!

相关推荐
陈随易9 分钟前
改变世界的编程语言MoonBit:项目文件详解
前端·后端·程序员
AI绘画哇哒哒10 分钟前
【值得收藏】手把手教你用PyTorch构建Transformer英汉翻译系统,从训练到推理
人工智能·pytorch·ai·语言模型·程序员·大模型·transformer
lssjzmn12 分钟前
会话管理巅峰对决:Spring Web中Cookie-Session、JWT、Spring Session + Redis深度秘籍
java·spring·架构
用户61204149221313 分钟前
C语言做的城市天气数据管理与统计
c语言·后端·敏捷开发
ursazoo17 分钟前
记一次线上API调用失败的排查过程:从405到时间同步
后端
聪明墨菲特17 分钟前
HttpClient工具类优化实践:提升性能与可维护性
后端·设计模式
Java中文社群19 分钟前
面试官:如何提升项目并发性能?
java·后端·面试
繁花与尘埃19 分钟前
Java流程控制04——if选择结构(本文为个人学习笔记,内容整理自哔哩哔哩UP主【遇见狂神说】的公开课程。 > 所有知识点归属原作者,仅作非商业用途分享)
java·笔记·学习
Seven9721 分钟前
hive 中 group by 和 distinct 孰优孰劣?
java
heyCHEEMS29 分钟前
路径总和 Ⅱ Java
java·开发语言·深度优先