沉默是金,总会发光
大家好,我是沉默
如果你是一名 Java 开发者,java.util.Date 这个类你一定见过。
甚至可以说——
你没主动用过,也一定被它“坑”过。
很多新同学都会有个疑问:
明明是 JDK 自带的类,
为什么老项目里一堆Date,
但新项目却几乎看不到它了?
答案很简单一句话:
它太老了,老到不适合现代开发。
今天我们就用最直观的代码 + 最真实的坑,把这个“Java 的老古董”一次性讲清楚。
**-**01-
一个“活化石”级别的类
java.util.Date 诞生于 Java 1.0(1996 年) 。
那一年:
- Java 还没泛型
- 还没注解
- 甚至连集合框架都不完整
你现在看到的 Date,本质是 30 年前的设计产物。
Date date = newDate();
System.out.println(date);
输出:
MonSep2209:50:24CST2025
看起来是不是很“正常”?
坑,正是从这里开始的。
- 02-
Date 的三大“反人类”设计缺陷
1. API 设计:
Date date = newDate();
System.out.println("当前年月日:" + LocalDate.now());
System.out.println(date.getYear());
System.out.println(date.getMonth());
输出:
当前年月日:2025-09-22
125
8
**
**
问题来了:
getYear()返回 125?getMonth()返回 8?
原因是:
- 年份:从 1900 年开始算
- 月份:从 0 开始(0 = 一月)
2. 可变对象:
Date date = newDate(2025 - 1900, 8, 22);
System.out.println("原定日期: " + date);
// 某个地方悄悄改了它
date.setYear(2026 - 1900);
System.out.println("修改后的日期: " + date);
输出:
原定日期: Mon Sep 22 00:00:00 CST 2025
修改后的日期: Tue Sep 22 00:00:00 CST 2026
**
**
在多线程环境下:
- 谁改了?
- 什么时候改的?
- 为什么变了?
debug 到秃头都找不到[哭]
**
**
3. 时区语义混乱
Date now = newDate();
System.out.println(now);
你看到的是:
- 系统默认时区的展示结果
但 Date 本身:
- 只存一个毫秒时间戳
- 根本不关心时区
展示和真实语义是分裂的,非常容易踩坑。
- 03-
一个真实业务场景:算天数差
用 Date 算两个日期差几天,你只能这么干:
Date date1 = newDate(125, 8, 22); // 2025-09-22
Date date2 = newDate(125, 9, 22); // 2025-10-22
long diff = date2.getTime() - date1.getTime();
long days = diff / (1000 * 60 * 60 * 24);
System.out.println("相差天数: " + days);
问题是:
- 可读性差
- 全是魔法数字
- 时区 / 夏令时一变就翻车
**-**04-
最后的最后
替代方案:Java 8 时间 API(java.time)
Java 8 之后,官方已经给出了“正确答案” 。
1. API 清晰到像自然语言
LocalDate date = LocalDate.of(2025, 9, 22);
System.out.println(date);
LocalDateTime now = LocalDateTime.now();
ZonedDateTime shanghai =
ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
2. 不可变对象,天生线程安全
LocalDate appointment = LocalDate.of(2025, 9, 22);
LocalDate newDate = appointment.plusDays(30);
- 原对象不变
- 返回新对象
- 并发场景天然安全
3. 时间计算一行搞定
long days = ChronoUnit.DAYS.between(
LocalDate.of(2025, 9, 22),
LocalDate.of(2025, 10, 22)
);
这才是 “业务代码”该有的样子。
4. 时区是显式的,而不是“猜的”
ZonedDateTime shanghai=
ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
ZonedDateTime newYork=
shanghai.withZoneSameInstant(
ZoneId.of("America/New_York")
);
老项目怎么办?
不用你“一刀切重构”
推荐做法:
- 新代码:一律用
java.time - 旧代码交互:只在边界转换
public static LocalDate toLocalDate(Date date) {
if (date == null) {
return null;
}
return date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDate();
}
publicstatic LocalDateTime toLocalDateTime(Date date) {
if (date == null) {
return null;
}
return date.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
}
(面试直接背)
java.util.Date是历史产物,
可变、反直觉、时区混乱、不适合现代并发系统。Java 8 之后,
java.time才是唯一正确选择。
如果你在项目里还大量看到 Date,
那不是你的错——
但你有责任在新代码里终结它。
**-**05-
粉丝福利
点点关注,送你互联网大厂面试题库,如果你正在找工作,又或者刚准备换工作。可以仔细阅读一下,或许对你有所帮助!