时间戳 vs. 格式化
-
时间戳:通常指一个特定的、精确到毫秒甚至纳秒的瞬间,在 Java 中,它本质上是一个长整型数字,表示自 1970 年 1 月 1 日 00:00:00 UTC(称为“纪元”或 Epoch)以来经过的毫秒数。
(图片来源网络,侵删)java.util.Date和java.sql.Timestamp都代表了这样一个瞬间。System.currentTimeMillis()返回的就是这个长整型数字。
-
格式化:指将一个时间戳(瞬间)转换成人类可读的字符串(如 "2025-10-27 10:30:00"),或者将一个符合某种格式的字符串解析回一个时间戳对象的过程。
旧版 API (不推荐,但需了解)
在 Java 8 之前,主要使用 java.util.Date 和 java.text.SimpleDateFormat。
a. java.util.Date
Date 对象本身不包含格式信息,它只是一个时间点,要格式化它,必须借助 SimpleDateFormat。
示例:格式化 Date

import java.util.Date;
import java.text.SimpleDateFormat;
public class LegacyDateFormat {
public static void main(String[] args) {
// 1. 获取当前时间的 Date 对象
Date now = new Date();
// 2. 创建 SimpleDateFormat 对象,并指定格式模式
// yyyy: 年, MM: 月, dd: 日, HH: 24小时制, mm: 分, ss: 秒
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 3. 格式化 Date 对象为字符串
String formattedDate = formatter.format(now);
System.out.println("原始 Date 对象: " + now);
System.out.println("格式化后的字符串: " + formattedDate);
// 4. 解析字符串为 Date 对象
try {
String dateStr = "2025-12-31 23:59:59";
Date parsedDate = formatter.parse(dateStr);
System.out.println("解析后的 Date 对象: " + parsedDate);
} catch (Exception e) {
e.printStackTrace();
}
}
}
SimpleDateFormat 常用模式字符:
| 字符 | 含义 | 示例 |
|---|---|---|
y |
年 | yyyy (2025), yy (23) |
M |
月 | MM (10), M (10) |
d |
日 | dd (27), d (27) |
H |
小时 (24小时制) | HH (14) |
h |
小时 (12小时制) | hh (02) |
m |
分 | mm (30) |
s |
秒 | ss (05) |
S |
毫秒 | SSS (123) |
a |
上午/下午标记 | AM 或 PM |
缺点:SimpleDateFormat 是非线程安全的,在多线程环境下共享同一个实例会导致数据错乱,必须为每个线程创建新的实例。
b. java.sql.Timestamp
这是 java.util.Date 的子类,专门用于与 JDBC 交互,可以精确到纳秒,它的格式化方式与 Date 完全相同。
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
public class SqlTimestampFormat {
public static void main(String[] args) {
// 获取当前时间的 Timestamp 对象
Timestamp now = new Timestamp(System.currentTimeMillis());
// 格式化
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
String formattedTs = formatter.format(now);
System.out.println("原始 Timestamp: " + now);
System.out.println("格式化后: " + formattedTs);
}
}
现代化 API (Java 8+, 强烈推荐)
Java 8 引入了 java.time 包,它彻底解决了旧 API 的设计问题,提供了更强大、更安全、更易用的 API。

a. 核心类
| 类 | 描述 |
|---|---|
Instant |
代表一个时间线上的瞬间,与 java.util.Date 类似,精确到纳秒,可以看作是 UTC 时间。 |
LocalDateTime |
不包含时区的日期和时间,如 "2025-10-27T10:30:00"。 |
ZonedDateTime |
包含时区的日期和时间,如 "2025-10-27T10:30:00+08:00[Asia/Shanghai]"。 |
DateTimeFormatter |
线程安全的日期、时间、时间戳的格式化器。 |
b. 使用 DateTimeFormatter 进行格式化
示例:格式化 LocalDateTime
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
public class ModernDateFormat {
public static void main(String[] args) {
// 1. 获取当前日期时间 (无时区)
LocalDateTime now = LocalDateTime.now();
// 2. 创建 DateTimeFormatter (线程安全)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
// 3. 格式化
String formattedDateTime = now.format(formatter);
System.out.println("格式化后的 LocalDateTime: " + formattedDateTime);
// 4. 定义格式并解析
String dateTimeStr = "2025-12-31 23:59:59";
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime parsedDateTime = LocalDateTime.parse(dateTimeStr, inputFormatter);
System.out.println("解析后的 LocalDateTime: " + parsedDateTime);
}
}
DateTimeFormatter 常用模式字符:
与 SimpleDateFormat 大部分相同,但更丰富。
| 字符 | 含义 |
|---|---|
yyyy |
年 |
MM |
月 |
dd |
日 |
HH |
小时 (24小时制) |
mm |
分 |
ss |
秒 |
SSS |
毫秒 |
nn |
纳秒 |
XXX |
时区偏移 (如 +08:00) |
VV |
时区ID (如 Asia/Shanghai) |
z |
时区名称 (如 CST) |
Timestamp 与 java.time 的转换
在 JDBC 编程中,数据库返回的 java.sql.Timestamp 需要转换为现代的 java.time 类型。
java.sql.Timestamp -> java.time.LocalDateTime
import java.sql.Timestamp;
import java.time.LocalDateTime;
public class TimestampToLocalDateTime {
public static void main(String[] args) {
// 假设这是从数据库获取的 Timestamp
Timestamp sqlTs = new Timestamp(System.currentTimeMillis());
// 转换为 LocalDateTime
// Timestamp.toLocalDateTime() 是 Java 8+ 提供的便捷方法
LocalDateTime ldt = sqlTs.toLocalDateTime();
System.out.println("原始 Timestamp: " + sqlTs);
System.out.println("转换后的 LocalDateTime: " + ldt);
// 另一种方式 (更通用)
// LocalDateTime ldt2 = LocalDateTime.ofInstant(sqlTs.toInstant(), ZoneId.systemDefault());
}
}
java.time.LocalDateTime -> java.sql.Timestamp
import java.sql.Timestamp;
import java.time.LocalDateTime;
public class LocalDateTimeToTimestamp {
public static void main(String[] args) {
// 获取当前 LocalDateTime
LocalDateTime ldt = LocalDateTime.now();
// 转换为 Timestamp
// Timestamp.valueOf() 是 Java 8+ 提供的便捷方法
Timestamp sqlTs = Timestamp.valueOf(ldt);
System.out.println("原始 LocalDateTime: " + ldt);
System.out.println("转换后的 Timestamp: " + sqlTs);
}
}
从时间戳数值(毫秒秒数)创建对象
如果你有一个从 System.currentTimeMillis() 或其他来源获得的 long 类型的时间戳数值。
在旧 API 中
long timestampMillis = 1698379800000L; Date date = new Date(timestampMillis);
在新 API 中
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
long timestampMillis = 1698379800000L;
// 1. 转换为 Instant (UTC 时间点)
Instant instant = Instant.ofEpochMilli(timestampMillis);
System.out.println("Instant: " + instant);
// 2. 转换为指定时区的 LocalDateTime
// 转换为系统默认时区的 LocalDateTime
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
System.out.println("LocalDateTime (系统默认时区): " + ldt);
// 转换为纽约时区的 LocalDateTime
LocalDateTime nycLdt = LocalDateTime.ofInstant(instant, ZoneId.of("America/New_York"));
System.out.println("LocalDateTime (纽约时区): " + nycLdt);
总结与最佳实践
| 特性 | 旧 API (java.util.Date) |
新 API (java.time) |
|---|---|---|
| 核心类 | Date, SimpleDateFormat |
LocalDateTime, Instant, DateTimeFormatter |
| 线程安全 | SimpleDateFormat 不安全 |
DateTimeFormatter 安全 |
| 易用性 | 设计有缺陷,功能分散 | 设计清晰,API 直观 |
| 时区处理 | 较弱 | ZonedDateTime, ZoneId 等提供强大支持 |
| 与数据库 | java.sql.Timestamp |
Timestamp.valueOf() 和 toLocalDateTime() 方便转换 |
| 推荐度 | 不推荐,仅维护旧项目 | 强烈推荐,所有新项目都应使用 |
最佳实践建议:
- 新项目一律使用
java.time包。 - 在应用内部处理日期时间时,优先使用
LocalDateTime(如果不需要时区)或ZonedDateTime(如果需要时区)。 - 只在与数据库交互时,才使用
java.sql.Timestamp,并利用valueOf()和toLocalDateTime()在java.time和java.sql之间进行转换。 - 永远不要将
java.text.SimpleDateFormat声明为static共享变量,如果必须使用旧代码,请为每次格式化/解析都创建新实例。
