核心概念对比
我们要理解这两者分别是什么。

MySQL 中的日期时间类型
MySQL 主要提供三种与日期时间相关的类型:
| 类型 | 格式 | 范围 | 精度 | 用途 |
|---|---|---|---|---|
DATE |
YYYY-MM-DD |
1000-01-01 到 9999-12-31 |
天 | 仅存储日期,不存储时间,生日、纪念日。 |
DATETIME |
YYYY-MM-DD HH:MM:SS |
1000-01-01 00:00:00 到 9999-12-31 23:59:59 |
秒 | 同时存储日期和时间,与时区无关。 |
TIMESTAMP |
YYYY-MM-DD HH:MM:SS |
1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC |
秒 | 同时存储日期和时间,依赖于时区,通常用于记录记录的创建和更新时间。 |
关键区别:
DATETIMEvsTIMESTAMP:最大的区别是时区处理。DATETIME存储的是你插入时它所代表的“绝对时间值”,不会自动转换时区,而TIMESTAMP在存储时会转换为 UTC 时间,在查询时又会根据当前连接的时区转换回本地时间,这使得TIMESTAMP在不同服务器间同步时非常有用。DATEvsDATETIME:DATE只关心日期,DATETIME关心日期和时间。
Java 中的日期时间 API
Java 的日期时间 API 经历了从旧到新的演变。
旧 API: java.util.Date (不推荐在新的业务逻辑中使用)
- 本质:它是一个“时间戳”的包装类,内部存储的是一个自 1970 年 1 月 1 日 00:00:00 GMT (UTC) 以来的毫秒数。
- 问题:
- 设计混乱:它的名称是
Date,但它同时包含了日期和时间信息,它还包含了很多过时的、与日期格式化无关的方法(如getHours(),getDate()),这些方法已被废弃。 - 线程不安全:
SimpleDateFormat等格式化类是线程不安全的。 - 时区处理困难:对时区的支持非常原始和麻烦。
- 设计混乱:它的名称是
新 API: java.time (Java 8+,推荐使用)
Java 8 引入了全新的 java.time 包,彻底解决了旧 API 的问题,这是现代 Java 开发中处理日期时间的标准。

| 类 | 描述 |
|---|---|
LocalDate |
表示一个日期(年、月、日),不包含时间信息,对应 MySQL 的 DATE。 |
LocalTime |
表示一个时间(时、分、秒、纳秒),不包含日期信息。 |
LocalDateTime |
表示一个日期和时间(年、月、日、时、分、秒、纳秒),不包含时区信息,对应 MySQL 的 DATETIME。 |
ZonedDateTime |
表示一个带时区的日期和时间,对应 MySQL 的 TIMESTAMP(在概念上)。 |
Instant |
表示一个时间轴上的瞬时点,与 java.util.Date 类似,基于 UTC 时间戳。 |
映射关系与转换
我们来看如何将 Java 的类型与 MySQL 的类型进行映射和转换。
| Java 类型 | MySQL 类型 | 说明 |
|---|---|---|
java.time.LocalDate |
DATE |
最直接的映射,两者都只表示日期。 |
java.time.LocalDateTime |
DATETIME |
最直接的映射,两者都表示日期和时间,且都不依赖时区。 |
java.util.Date |
DATETIME |
Date 内部是毫秒时间戳,可以无损地转换为 DATETIME,这是旧 JDBC 驱动默认的行为。 |
java.time.Instant |
TIMESTAMP |
Instant 是 UTC 时间戳,与 TIMESTAMP 的核心行为(存储为 UTC)非常匹配。 |
java.time.ZonedDateTime |
TIMESTAMP |
带时区的日期时间,在存入数据库时,JDBC 驱动会将其转换为 UTC 的 TIMESTAMP。 |
代码实践 (JDBC 操作)
下面我们通过代码示例来看具体的转换过程。
场景1:使用旧 API (java.util.Date)
假设我们有一个 User 表:
CREATE TABLE `user_old` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `name` VARCHAR(50), `create_time` DATETIME -- 使用 DATETIME );
Java 代码 (JDBC):

import java.sql.*;
import java.util.Date;
public class JdbcDateExampleOld {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC";
String user = "your_username";
String password = "your_password";
// 1. Java 对象 -> MySQL DATETIME (插入)
Date javaDate = new Date(); // 获取当前时间
String insertSql = "INSERT INTO user_old (name, create_time) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(insertSql)) {
pstmt.setString(1, "Alice");
// setObject 会自动将 java.util.Date 转换为 SQL 的 Timestamp 类型
pstmt.setObject(2, javaDate);
pstmt.executeUpdate();
System.out.println("插入成功,Java Date: " + javaDate);
} catch (SQLException e) {
e.printStackTrace();
}
// 2. MySQL DATETIME -> Java Date (查询)
String selectSql = "SELECT id, name, create_time FROM user_old WHERE name = ?";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(selectSql)) {
pstmt.setString(1, "Alice");
ResultSet rs = pstmt.executeQuery();
if (rs.next()) {
// 从 ResultSet 中获取时,getTimestamp 返回的是 java.sql.Timestamp
// 它是 java.util.Date 的子类,可以直接赋值
Timestamp timestamp = rs.getTimestamp("create_time");
Date retrievedDate = timestamp;
System.out.println("查询成功,从 MySQL 读取的 Date: " + retrievedDate);
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
关键点:
- 在 JDBC 中,处理日期时间推荐使用
java.sql.Date,java.sql.Time,java.sql.Timestamp,它们是java.util.Date的子类,专门用于与数据库交互。 PreparedStatement.setObject()和ResultSet.getTimestamp()是进行转换的关键方法。
场景2:使用新 API (java.time)
这是现代 Java 开发推荐的方式,确保你的 JDBC 驱动版本较新(如 mysql-connector-j 8.0+),它原生支持 java.time。
假设我们有一个 order 表:
CREATE TABLE `order_new` ( `id` INT PRIMARY KEY AUTO_INCREMENT, `order_date` DATE, -- 对应 LocalDate `created_at` DATETIME, -- 对应 LocalDateTime `last_updated` TIMESTAMP -- 对应 ZonedDateTime 或 Instant );
Java 代码 (JDBC):
import java.sql.*;
import java.time.*;
public class JdbcDateExampleNew {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC";
String user = "your_username";
String password = "your_password";
// 1. Java 对象 -> MySQL 类型 (插入)
LocalDate orderDate = LocalDate.now();
LocalDateTime createdAt = LocalDateTime.now();
ZonedDateTime updatedAt = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); // 假设服务器在中国
String insertSql = "INSERT INTO order_new (order_date, created_at, last_updated) VALUES (?, ?, ?)";
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement pstmt = conn.prepareStatement(insertSql)) { 