news 2026/3/7 10:23:15

Java 8日期时间API完全指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java 8日期时间API完全指南

一、Java 8 之前的日期时间 API 问题

1.设计缺陷

  • Date 类:既包含日期又包含时间,且时间以毫秒数存储,设计混乱,Date可变,线程不安全

  • Calendar 类:月份从0开始(0=一月),不符合人类直觉,反人类设计

  • SimpleDateFormat 非线程安全:多线程环境下需要额外同步

2.代码示例 - 旧API的坑

  • ❌ 月份从0开始,年份要减1900

  • ❌ Date可变,线程不安全

  • ❌ SimpleDateFormat线程不安全

  • ❌ API设计混乱

  • ❌ 时区处理复杂

// 1. 月份从0开始 Date date = new Date(2025-1900, 0, 1); // 2025年1月1日?实际上是2025年1月1日 // 实际上月份参数0表示一月 // 2. SimpleDateFormat 线程不安全 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 多线程使用会抛出异常 // 3. 日期计算复杂 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DAY_OF_MONTH, 5); // 增加5天 // 代码冗长,可读性差 // 4. 时区处理混乱 Date date = new Date(); // 默认使用系统时区,转换麻烦 Date now = newDate(); now.setTime(0); // 可以随意修改,多线程下危险!

二、Java 8 日期时间 API 核心类

1.主要类层次结构

java.time ├── LocalDate // 日期(年-月-日) ├── LocalTime // 时间(时-分-秒-纳秒) ├── LocalDateTime // 日期+时间 ├── ZonedDateTime // 带时区的日期时间 ├── Instant // 时间戳(Unix时间) ├── Duration // 时间间隔(秒,纳秒) ├── Period // 日期间隔(年,月,日) └── DateTimeFormatter // 格式化器

2.Java 8新API的优势 ✨

// 新API:简洁、清晰、不可变 LocalDate date = LocalDate.of(2025, 1, 15); // 就是2025年1月15日 LocalDate tomorrow = date.plusDays(1); // 返回新对象,原对象不变 // 线程安全的格式化 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); Stringstr = date.format(formatter); // 完全线程安全 // 流畅的API LocalDateTime now = LocalDateTime.now() .plusDays(7) .minusHours(2) .withMinute(30);

三、核心类详解

1.LocalDate - 本地日期

// 创建 LocalDate today = LocalDate.now(); LocalDate specificDate = LocalDate.of(2025, 12, 25); LocalDate parsedDate = LocalDate.parse("2025-12-25"); // 操作 LocalDate tomorrow = today.plusDays(1); LocalDate nextMonth = today.plusMonths(1); LocalDate previousYear = today.minusYears(1); // 获取信息 int year = today.getYear(); Month month = today.getMonth(); // 返回Month枚举 int dayOfMonth = today.getDayOfMonth(); DayOfWeek dayOfWeek = today.getDayOfWeek(); // 判断 boolean isLeapYear = today.isLeapYear(); boolean isBefore = today.isBefore(LocalDate.of(2025, 1, 1));

2.LocalTime - 本地时间

// 创建 LocalTime now = LocalTime.now(); LocalTime specificTime = LocalTime.of(14, 30, 45); // 14:30:45 LocalTime parsedTime = LocalTime.parse("14:30:45"); // 操作 LocalTime plusHours = now.plusHours(2); LocalTime minusMinutes = now.minusMinutes(30); // 获取信息 int hour = now.getHour(); int minute = now.getMinute(); int second = now.getSecond();

3.LocalDateTime - 本地日期时间

// 创建 LocalDateTime now = LocalDateTime.now(); LocalDateTime specificDateTime = LocalDateTime.of(2025, 12, 25, 14, 30); LocalDateTime combined = LocalDateTime.of(today, now); // 转换 LocalDate date = now.toLocalDate(); LocalTime time = now.toLocalTime(); // 操作 LocalDateTime nextWeek = now.plusWeeks(1); LocalDateTime lastHour = now.minusHours(1);

4.Instant - 时间戳

// 创建 Instant now = Instant.now(); Instant specific = Instant.ofEpochSecond(1700000000L); // 转换 Instant fromDate = date.atStartOfDay(ZoneId.systemDefault()).toInstant(); LocalDateTime ldt = LocalDateTime.ofInstant(now, ZoneId.systemDefault()); // 计算 Instant plusSeconds = now.plusSeconds(3600); Duration between = Duration.between(now, plusSeconds);

5.ZonedDateTime - 带时区日期时间

// 创建 ZonedDateTime nowInShanghai = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); ZonedDateTime zoned = ZonedDateTime.of( LocalDateTime.now(), ZoneId.of("America/New_York") ); // 时区转换 ZonedDateTime nowTime= ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); ZonedDateTime newYorkTime = nowTime.withZoneSameInstant( ZoneId.of("America/New_York") ); // 获取所有可用时区 Set<String> allZones = ZoneId.getAvailableZoneIds();

6.Duration 和 Period

// Duration - 时间间隔(精确到纳秒) Duration duration = Duration.between( LocalTime.of(14, 0), LocalTime.of(16, 30) ); long hours = duration.toHours(); // 2 long minutes = duration.toMinutes(); // 150 // Period - 日期间隔(年、月、日) Period period = Period.between( LocalDate.of(2025, 1, 1), LocalDate.of(2025, 12, 31) ); int months = period.getMonths(); // 11 int days = period.getDays(); // 30

四、格式化与解析

1.DateTimeFormatter

// 预定义格式器 LocalDateTime now = LocalDateTime.now(); String isoFormat = now.format(DateTimeFormatter.ISO_DATE_TIME); // 自定义格式 DateTimeFormatter formatter = DateTimeFormatter .ofPattern("yyyy-MM-dd HH:mm:ss") .withLocale(Locale.CHINA); // 格式化 String formatted = now.format(formatter); // 解析 LocalDateTime parsed = LocalDateTime.parse("2025-12-25 14:30:00", formatter); // 本地化格式 DateTimeFormatter germanFormatter = DateTimeFormatter .ofLocalizedDateTime(FormatStyle.MEDIUM) .withLocale(Locale.GERMAN);

五、实用操作示例

1.日期计算

// 计算两个日期之间的天数 long daysBetween = ChronoUnit.DAYS.between( LocalDate.of(2025, 1, 1), LocalDate.of(2025, 12, 31) ); // 获取本月第一天和最后一天 LocalDate firstDay = today.with(TemporalAdjusters.firstDayOfMonth()); LocalDate lastDay = today.with(TemporalAdjusters.lastDayOfMonth()); // 获取下个周一 LocalDate nextMonday = today.with(TemporalAdjusters.next(DayOfWeek.MONDAY));

2.时区处理

// 获取当前所有时区的当前时间 Map<String, LocalDateTime> timesInAllZones = ZoneId.getAvailableZoneIds().stream() .collect(Collectors.toMap( zone -> zone, zone -> LocalDateTime.now(ZoneId.of(zone)) )); // 判断是否夏令时 ZoneId zone = ZoneId.of("Asia/Shanghai"); ZonedDateTime zdt = ZonedDateTime.now(zone); boolean isDST = zdt.getZone().getRules().isDaylightSavings(zdt.toInstant());

3.业务常见场景

// 1. 计算年龄 public int calculateAge(LocalDate birthDate) { return Period.between(birthDate, LocalDate.now()).getYears(); } // 2. 计算工作日(排除周末) public long calculateWorkingDays(LocalDate start, LocalDate end) { return Stream.iterate(start, date -> date.plusDays(1)) .limit(ChronoUnit.DAYS.between(start, end)) .filter(date -> date.getDayOfWeek() != DayOfWeek.SATURDAY && date.getDayOfWeek() != DayOfWeek.SUNDAY) .count(); } // 3. 定时任务执行时间计算 public LocalDateTime nextExecutionTime(LocalDateTime lastExecution, Duration interval) { return lastExecution.plus(interval); }

六、与传统API的互操作

// Date 转 LocalDateTime Date oldDate = new Date(); LocalDateTime newDateTime = oldDate.toInstant() .atZone(ZoneId.systemDefault()) .toLocalDateTime(); // LocalDateTime 转 Date LocalDateTime ldt = LocalDateTime.now(); Date date = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant()); // Calendar 转 LocalDate Calendar calendar = Calendar.getInstance(); LocalDate localDate = LocalDate.of( calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, // 注意月份+1 calendar.get(Calendar.DAY_OF_MONTH) );

七、最佳实践

1.选择正确的类

  • 只关心日期 →LocalDate

  • 只关心时间 →LocalTime

  • 需要日期时间 →LocalDateTime

  • 需要时区 →ZonedDateTime

  • 时间戳存储 →Instant

2.线程安全

// DateTimeFormatter 是线程安全的,可以共享 private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public String formatDateTime(LocalDateTime dateTime) { return dateTime.format(FORMATTER); // 线程安全 }

3.避免空指针

public Optional<LocalDate> parseDate(String dateStr) { try { return Optional.of(LocalDate.parse(dateStr)); } catch (DateTimeParseException e) { return Optional.empty(); } }

八、总结对比

特性旧API (java.util.Date)新API (java.time)
设计清晰度混乱,一锅炖职责单一,清晰
线程安全不安全所有类不可变,线程安全
月份表示0-11(0=一月)1-12(符合直觉)
格式化SimpleDateFormat(非线程安全)DateTimeFormatter(线程安全)
时区处理复杂易错内置支持完善
日期计算繁琐简单直观
可读性优秀

Java 8 日期时间 API 的设计遵循了以下原则:

  1. 不可变性:所有核心类都是不可变的

  2. 清晰性:类名和方法名明确表达意图

  3. 流畅性:方法链式调用,代码流畅

  4. 扩展性:支持自定义的时间调节器

  5. 完整性:覆盖了所有常见的日期时间操作场景

建议所有新项目都使用 Java 8 日期时间 API,对于老项目逐步迁移替换。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/7 5:21:35

RDP Wrapper配置库完全使用指南:解锁Windows远程桌面全部潜能

RDP Wrapper配置库完全使用指南&#xff1a;解锁Windows远程桌面全部潜能 【免费下载链接】rdpwrap.ini RDPWrap.ini for RDP Wrapper Library by StasM 项目地址: https://gitcode.com/GitHub_Trending/rd/rdpwrap.ini RDP Wrapper Library是一个强大的开源工具&#x…

作者头像 李华
网站建设 2026/3/5 13:40:21

官宣!TDengine 授权麦斯时代为钻石分销商,共筑工业数据新生态

当前&#xff0c;工业数字化转型进入深水区&#xff0c;时序数据作为工业设备运维、生产监控、能源管理等场景的核心数据载体&#xff0c;市场需求呈现爆发式增长。涛思数据始终坚持 “技术驱动 生态共建” 的发展战略&#xff0c;通过构建完善的分销商体系&#xff0c;让 TDe…

作者头像 李华
网站建设 2026/3/6 2:29:38

亿欧 2025 AI 软件创新产品 Top10 出炉,时序数据库TDengine 入选

当“AI 驱动增长”成为越来越多企业的共识时&#xff0c;一个新的分水岭正在出现&#xff1a;行业已经从讨论模型能力&#xff0c;转向讨论哪类 AI 软件真正能够在未来产业里稳定运行。尤其在制造、能源、化工等典型工业场景中&#xff0c;AI 要面对的不是实验条件&#xff0c;…

作者头像 李华
网站建设 2026/3/6 2:29:35

百度网盘秒传技术全解析:从零基础到效率达人的终极指南

还在为下载大文件耗费数小时而烦恼吗&#xff1f;百度网盘秒传技术正是为你量身打造的极速传输解决方案&#xff01;通过独特的文件特征值匹配机制&#xff0c;让你在几秒钟内完成原本需要数小时的下载任务&#xff0c;真正实现"秒级"传输体验。 【免费下载链接】bai…

作者头像 李华
网站建设 2026/3/6 2:29:31

OpenAI Whisper Large-V3-Turbo本地部署终极指南:从零搭建到性能调优

OpenAI Whisper Large-V3-Turbo本地部署终极指南&#xff1a;从零搭建到性能调优 【免费下载链接】whisper-large-v3-turbo 项目地址: https://ai.gitcode.com/hf_mirrors/openai/whisper-large-v3-turbo 还在为语音转写模型的高内存占用和复杂部署流程而头疼吗&#x…

作者头像 李华
网站建设 2026/3/4 6:26:29

75、深入探索GDB调试器:命令详解与实用技巧

深入探索GDB调试器:命令详解与实用技巧 1. GDB调试基础:断点与调用 在GDB调试中,断点是控制程序执行流程、定位问题的关键工具。 break 命令提供了多种设置断点的方式: - break :在当前栈帧的下一条指令处设置断点。若不在最内层栈帧,执行返回该帧时控制停止;在最…

作者头像 李华