🚀 Java 巩固进阶 · 第 29 天
主题:JDK8 时间 API 进阶 ------ 时区与时间戳实战
📅 进度概览 :继接口默认方法之后,今天深入 JDK8 时间 API 的高级特性 。虽然第 22 天我们掌握了基础用法,但全球化和数据库交互需要更深入的 时区(Zone) 和 时间戳(Instant) 知识。
💡 核心价值:
- 全球化支持 :掌握
ZoneId和ZonedDateTime,轻松处理跨国业务时间。- 数据库交互 :理解
Instant与时间戳的转换,完美对接数据库timestamp字段。- 新旧兼容 :学会
Date与LocalDateTime互转,兼容遗留系统。- 面试高频:时区处理、时间戳精度、新旧 API 转换是高级开发必问。
一、核心类详解:Instant 与 Zone 🌍
1. Instant:时间戳的化身
java
// ✅ 获取当前时间戳(秒 + 纳秒)
Instant now = Instant.now();
long epochSecond = now.getEpochSecond(); // 秒级时间戳
long nano = now.getNano(); // 纳秒部分
// ✅ 时间戳 → Instant
Instant instant = Instant.ofEpochSecond(1712034600L);
// 💡 场景:数据库存储、分布式 ID 生成、日志记录
// 优势:统一标准(UTC),无时区歧义
2. ZoneId 与 ZonedDateTime:带时区的时间
java
// ✅ 获取所有可用时区 ID
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
// ✅ 创建特定时区
ZoneId shanghai = ZoneId.of("Asia/Shanghai");
ZoneId newYork = ZoneId.of("America/New_York");
// ✅ 带时区的时间
ZonedDateTime zdt = ZonedDateTime.now(shanghai);
System.out.println("北京:" + zdt);
ZonedDateTime nyTime = zdt.withZoneSameInstant(newYork);
System.out.println("纽约:" + nyTime); // 自动换算时差
⚠️ 关键区别:
LocalDateTime:本地日期时间,无时区信息(适合业务展示)ZonedDateTime:带时区的日期时间,包含时区偏移(适合跨国交互)Instant:时间戳,UTC 标准(适合存储、传输)
二、高级格式化与解析 🔤
1. 本地化格式
java
// ✅ 使用预定义的本地化格式
DateTimeFormatter chineseFormatter =
DateTimeFormatter.ofPattern("yyyy 年 MM 月 dd 日 HH 时 mm 分", Locale.CHINA);
String str = LocalDateTime.now().format(chineseFormatter);
// 输出:2024 年 04 月 02 日 15 时 30 分
2. 复杂解析
java
// ✅ 解析带时区的字符串
String isoStr = "2024-04-02T15:30:00+08:00[Asia/Shanghai]";
ZonedDateTime zdt = ZonedDateTime.parse(isoStr);
// ✅ 解析时间戳
Instant instant = Instant.parse("2024-04-02T07:30:00Z"); // Z 表示 UTC
三、新旧 API 互转:兼容遗留代码 🔄
1. Date ↔ LocalDateTime
java
// ✅ Date → LocalDateTime
Date oldDate = new Date();
LocalDateTime ldt = oldDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
// ✅ LocalDateTime → Date
LocalDateTime now = LocalDateTime.now();
Date newDate = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
2. Date ↔ Instant
java
// ✅ Date → Instant
Instant instant = oldDate.toInstant();
// ✅ Instant → Date
Date date = Date.from(instant);
💡 最佳实践:
- 新代码一律用
java.time包- 仅在数据库驱动或老旧库交互时转换
Date- 数据库字段建议用
timestamp↔Instant或LocalDateTime
四、🎯 今日实战任务:全球时间转换器
任务 1:多时区时间对比
java
/**
* 要求:
* 1. 获取当前北京时间、纽约时间、伦敦时间
* 2. 计算它们之间的时差(小时)
* 3. 格式化为 "yyyy-MM-dd HH:mm:ss z"(z 显示时区缩写)
*
* 💡 提示:
* ZoneId.of("Asia/Shanghai")
* Duration.between(zdt1, zdt2).toHours()
*/
任务 2:时间戳与日期互转
java
/**
* 业务场景:前端传时间戳,后端存日期
*
* 要求:
* 1. 接收 long 类型时间戳(毫秒)
* 2. 转换为 LocalDateTime 存入数据库(模拟)
* 3. 从数据库取出 LocalDateTime,转回时间戳返回前端
*
* 💡 关键 API:
* Instant.ofEpochMilli(timestamp)
* ldt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
*/
任务 3:旧系统兼容工具类
java
/**
* 要求:
* 1. 创建 DateUtils 工具类
* 2. 实现 convertToDate(LocalDateTime) 和 convertToLocalDateTime(Date)
* 3. 处理时区问题(统一用系统默认时区)
* 4. 编写单元测试验证转换前后时间一致
*
* 💡 挑战:
* - 考虑夏令时影响(ZonedDateTime 会自动处理)
*/
任务 4:计算跨时区会议时间
java
/**
* 业务场景:安排北京与纽约的会议
*
* 要求:
* 1. 输入:北京时间 2024-04-02 20:00
* 2. 输出:对应的纽约时间是几点?是否在当地工作时间(9:00-18:00)?
* 3. 如果不在工作时间,提示建议时间
*
* 💡 提示:
* 用 withZoneSameInstant 转换时区
* 用 getHour() 判断小时数
*/
📝 第 29 天 · 核心总结(极简背诵版)
-
核心类选型:
java存储/传输 → Instant (时间戳) 业务展示 → LocalDateTime (无时区) 跨国交互 → ZonedDateTime (带时区) -
时区操作:
javaZoneId.of("Asia/Shanghai") zdt.withZoneSameInstant(newZone) // 转换时区 -
新旧转换:
javaDate ↔ Instant: date.toInstant() / Date.from(instant) Instant ↔ LocalDateTime: atZone() / toInstant() -
格式化:
javaDateTimeFormatter.ofPattern("...", Locale.CHINA)
明天预告 :🆕 JDK9-11 常用新特性 ------ 语法糖与工具升级!
- JDK9:集合工厂方法(List.of, Map.of)
- JDK10:var 局部变量类型推断
- JDK11:String 新方法(isBlank, strip, repeat)
- 实战:用新特性重构旧代码
准备好了吗?明天我们体验 Java 的"现代语法"! ✨🔧