网站首页 > java教程 正文
Java 里的 java.util.Date 和 java.sql.Date 绝对是那种看起来不起眼但能搞得你 Debug 到半夜的“坑王”。
我们先从表面上看,java.sql.Date 是继承自 java.util.Date 的,按理说是“子承父业”,兼容没问题对吧?但实际上,这俩压根儿不是一个世界的。java.util.Date 是 Java 标准库里提供的“通用型”时间类,而 java.sql.Date 则是 JDBC 里为了数据库操作特化出来的版本,核心区别就在于:一个有时间,一个没时间!
就是这么沙雕的区别,java.sql.Date 把时间部分(小时、分钟、秒)全都砍了个干净,只保留年月日。为什么这么干?因为很多数据库的 DATE 类型本来就只存年月日,比如 MySQL 的 DATE 字段。所以 java.sql.Date 就跟着这个“传统艺能”走了,给你个精确到天的“日子”。
来看段代码你就明白了:
public class DateExample {
public static void main(String[] args) {
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
System.out.println("utilDate: " + utilDate); // 有时间
System.out.println("sqlDate: " + sqlDate); // 只有年月日
}
}
输出可能是这样的:
utilDate: Thu Jun 05 15:30:12 CST 2025
sqlDate: 2025-06-05
你看,时间部分直接没了!这就导致很多时候你把 java.sql.Date 传回前端,前端一看没时间,直接懵了...
我遇到过最离谱的是,有个哥们把 java.sql.Date 强转成 java.util.Date,然后还奇怪为啥结果有问题。讲真,这是个巨坑。虽然它们在继承关系上确实可以强转,但你转完之后,它的“灵魂”还是那个没有时间的 sql.Date
所以你如果真的要拿 java.sql.Date 去做一些带时间的运算,比如和当前时间比较,或者转换成时间戳,那基本就是拿刀割自己手指头。比如这个例子:
java.sql.Date sqlDate = java.sql.Date.valueOf("2025-06-05");
long millis = sqlDate.getTime(); // 你以为这是某个时间点?
Date converted = new Date(millis);
System.out.println(converted); // 时间是 00:00:00 啊兄弟!
你以为你得到了“某一天的某个时刻”,结果其实是“那天的零点”... 这还不如直接用 LocalDate 呢。
对,说到这个就得扯一下 Java 8 的时间新 API——java.time.*。这波更新真的可以说是“Date 的反攻”。像 LocalDate 和 LocalDateTime 就分别对应 java.sql.Date 和 java.util.Date 的干净替代品,前者精确到天,后者精确到秒,而且线程安全,没有时区困扰,API 超清晰,看着就让人舒服。
LocalDate localDate = LocalDate.now();
LocalDateTime localDateTime = LocalDateTime.now();
System.out.println("LocalDate: " + localDate); // 2025-06-05
System.out.println("LocalDateTime: " + localDateTime); // 2025-06-05T15:45:30
最重要的是,java.sql.Date、java.sql.Time 和 java.sql.Timestamp 都有对应的 toLocalDate() 或 toLocalDateTime() 方法,基本可以无痛迁移。
但你要说现实项目里能不能彻底抛弃 java.sql.Date?我只能说:想多了。只要你在用 JDBC,尤其是用 MyBatis 或 Hibernate 这种 ORM 框架,它们底层还是会默认你搞点 java.sql.Date 出来。所以我个人的策略是:入库出库都用 LocalDate / LocalDateTime,中间统一转换。
比如用 MyBatis 的 TypeHandler 机制,写一个 LocalDate 转 java.sql.Date 的 Handler:
@MappedTypes(LocalDate.class)
public class LocalDateTypeHandler extends BaseTypeHandler<LocalDate> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i,
LocalDate parameter, JdbcType jdbcType) throws SQLException {
ps.setDate(i, Date.valueOf(parameter));
}
@Override
public LocalDate getNullableResult(ResultSet rs, String columnName) throws SQLException {
Date date = rs.getDate(columnName);
return date != null ? date.toLocalDate() : null;
}
// 其他两个 get 方法略
}
配上 XML 或注解,就能实现 LocalDate 的透明持久化,再也不用在每个 Entity 里扔一堆类型转换的代码了
另外顺带一提,还有不少人会问:“那 java.sql.Timestamp 是啥角色?”很简单,它就是 java.util.Date + 纳秒精度的变种,主要是数据库里有精确到秒甚至微秒的 TIMESTAMP 字段时用的。但我一般都尽量避免用它,因为那玩意儿坑更多,特别是跨数据库还经常有精度兼容性问题(MySQL 精确到毫秒,Oracle 精确到纳秒,一导出 CSV 就炸了...)
回到最初的问题:到底 java.util.Date 和 java.sql.Date 有啥区别?
如果用一句话总结就是:
java.util.Date 是全能选手,啥时间信息都有; java.sql.Date 是简化版,为了和数据库的 DATE 类型打配合,砍掉了时间部分,只保留“日期”。
但这区别,常常在你不注意的时候就搞事,所以我现在干脆上来就用 LocalDate 和 LocalDateTime,实在不行中间过渡一下,也总比在项目上线前踩坑强
猜你喜欢
- 2025-07-27 千万级数据,如何做性能优化?分库分表、Oracle分区表?
- 2025-07-27 服务器时间不准,相差 8 个小时?教你轻松解决!
- 2025-07-27 时间轮的艺术:原理、使用场景及复杂业务环境下的Java实践
- 2025-07-27 为Java虚拟机分配堆内存大于机器物理内存会怎么样?
- 2025-07-27 Java性能翻倍秘诀!3个被低估的JVM参数(附实测数据)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)