《Java 100 天进阶之路》第29篇:Java Date 类详解

第29篇:Java Date 类详解


📌 系列导航《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第28篇:Java反射机制原理详解 |
➡️ 下一篇:第30篇:Date类、Calendar类、date转calendar


一、核心知识点

  • java.util.Date 的基本使用(Java 1.0 起)
  • Date 的问题:年份从1900开始、月份从0开始、可变、线程不安全
  • SimpleDateFormat 格式化与解析(线程不安全)
  • 推荐使用 java.time 包(Java 8+):LocalDateLocalDateTimeZonedDateTimeDateTimeFormatter

二、通俗讲解(1分钟开心学)

1. Date 类的缺陷

java.util.Date 是 Java 早期设计的日期类,存在很多不合理之处:

  • 年份从1900开始,new Date(2024 - 1900, 4, 6) 表示2024年5月6日(月从0开始)。
  • 月份从0开始,11月是10?不,11是12?非常容易混乱。
  • 大部分方法已废弃(如 getYear()setMonth())。
  • Date 是可变的,线程不安全。
  • 时区处理混乱。

2. SimpleDateFormat 的线程不安全问题

SimpleDateFormat 用于格式化 Date 或解析字符串。它的内部有一个 Calendar 引用,多线程共享时,一个线程修改 Calendar 会影响其他线程,导致解析错误或异常。

3. Java 8 的 java.time 包

Java 8 引入了全新的日期时间 API,位于 java.time 包下:

  • LocalDate:只含日期(年月日)
  • LocalTime:只含时间(时分秒纳秒)
  • LocalDateTime:含日期和时间
  • ZonedDateTime:带时区的日期时间
  • DateTimeFormatter:线程安全的格式化器

这些类都是不可变的,线程安全,API 设计清晰。

生活类比
Date 就像一把老式门锁,能用但别扭。LocalDate 是现代智能锁,直观、安全、好用。

三、实操代码案例 + 场景说明

场景:解析用户输入的生日字符串,计算年龄。

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Date;

public class DateDemo {
    public static void main(String[] args) throws Exception {
        // ========== 旧API(不推荐)==========
        // 1. Date 的陷阱
        Date date = new Date(2024 - 1900, 4, 6); // 2024年5月6日
        System.out.println(date);
        
        // 2. SimpleDateFormat 线程不安全演示(单线程没问题,多线程要小心)
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String dateStr = "2024-05-06";
        Date parsed = sdf.parse(dateStr);
        System.out.println(sdf.format(parsed));
        
        // ========== 新API(推荐)==========
        // 3. LocalDate 基本使用
        LocalDate today = LocalDate.now();
        LocalDate birthday = LocalDate.of(2000, 5, 1); // 年,月,日 直观
        System.out.println("今年生日是:" + birthday);
        
        // 4. 日期计算(年龄)
        int age = Period.between(birthday, today).getYears();
        System.out.println("年龄:" + age);
        
        // 5. 格式化(线程安全)
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        String formatted = today.format(formatter);
        System.out.println("格式化日期:" + formatted);
        
        // 6. 字符串解析
        LocalDate parsedDate = LocalDate.parse("2025-12-31"); // ISO格式默认支持
        LocalDate customParsed = LocalDate.parse("2025/12/31", DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        System.out.println(customParsed);
    }
}

四、避坑要点

错误/误区后果正确做法
使用 Date 的废弃构造方法代码不清晰,容易错使用 java.timeCalendar
多个线程共享一个 SimpleDateFormat解析错误、异常每次新建,或用 ThreadLocal 包装
忘记处理时区时区转换错误使用 ZonedDateTime 或明确时区
LocalDateDate 混用时转换错误类型不匹配使用 Date.from(instant)date.toInstant()

五、面试高频考点

Q1:为什么 SimpleDateFormat 是线程不安全的?

内部维护了一个 Calendar 对象,多线程同时调用 formatparse 时会互相干扰,导致状态错乱。

Q2:Java 8 推荐使用哪些日期时间类?

LocalDateLocalDateTimeZonedDateTimeDateTimeFormatter,它们不可变、线程安全、API 清晰。

Q3:如何将 java.util.Date 转换为 LocalDateTime

Date date = new Date();
LocalDateTime ldt = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();

六、练习题

  1. 代码改错:指出以下代码的问题并修正。
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    Date d1 = sdf.parse("2024-01-01");
    Date d2 = sdf.parse("2024-01-02");
    
  2. 编程:计算从出生日期到今天的天数(使用 java.time)。
  3. 简答LocalDateDate 的主要区别?

📊 你的学习进度

  • 当前:第29篇 / 共44篇 · 第四阶段:注解、反射、代理、日期(第26~31篇)
  • ✅ 已完成:第1~28篇
  • 📖 正在学:第29篇
  • ⏳ 待学习:第30~44篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!


下一篇文章预告

《Date类、Calendar类、date转calendar》

内容简介:Calendar的功能(add/roll区别)、Date与Calendar互转、为什么Calendar也被废弃。

💡 学完这篇,你将掌握旧版日期处理的全貌,并理解为什么必须迁移到java.time。

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值