首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

Java 日期時間陷阱:謹慎使用 java.sql.Date、Time 避免精度丟失與比較失效

     編輯:Java 程式設計入門

核心問題:精度截斷導致的數據不一致

JDBC 規範中,java.sql.Date 僅保留「年月日」,java.sql.Time 僅保留「時分秒」,java.sql.Timestamp 則保留「納秒級」精度。當資料庫列類型為 DATETIME/TIMESTAMP 且包含完整時間信息時,若分別用 getDate()、getTime() 讀取,會發生靜默截斷:

  • 原值:2002-05-22 17:00:57.123
  • getDate() → 2002-05-22(時分秒毫秒全丟)
  • getTime() → 17:00:57(日期毫秒全丟)
  • getTimestamp() → 完整保留

資料庫差異加劇風險

  • MySQL:DATETIME 精度達微秒(DATETIME(6)),TIMESTAMP 同理。
  • Oracle:DATE 精度至秒,TIMESTAMP 可達納秒;但 java.sql.Date 映射時仍會截斷。
  • SQL Server:DATETIME 精度約 3.33ms,DATETIME2 可達 100ns。

跨資料庫遷移或多數據源場景下,精度不一致極易導致邏輯錯誤。

經典 Bug:equals 比較失效

Timestamp ts1 = new Timestamp(System.currentTimeMillis()); // 含納秒
Timestamp ts2 = new Timestamp(ts1.getTime());              // 納秒歸零

// 看似相等,實則不同
System.out.println(ts1.equals(ts2)); // false!因納秒不同

// 更隱蔽:Date vs Timestamp
Date d = new Date(ts1.getTime());
System.out.println(d.equals(ts1));   // true  (Date 忽略納秒)
System.out.println(ts1.equals(d));   // false (Timestamp 比較納秒)

破壞了 equals 的對稱性,導致集合(Set、Map key)行為異常。

正確獲取完整時間值

// 方案 1:合併毫秒與納秒
long fullTime = timestamp.getTime() + timestamp.getNanos() / 1_000_000;

// 方案 2:直接用 Instant (Java 8+)
Instant instant = timestamp.toInstant(); // 納秒精度
long epochMilli = instant.toEpochMilli(); // 毫秒
int nanoAdjustment = instant.getNano();   // 納秒餘數

最佳實踐建議

  1. 統一使用 java.time (Java 8+):LocalDateTime、Instant、ZonedDateTime 不可變、線程安全、精度納秒、API 清晰。
  2. JDBC 讀寫直接映射:ResultSet.getObject(col, LocalDateTime.class)、PreparedStatement.setObject(idx, localDateTime),避免 java.sql.* 類。
  3. 若必須用舊 API:僅用 Timestamp 承載完整時間,絕不混用 Date/Time 比較或存入集合。
  4. 資料庫列類型對齊:優先用 TIMESTAMP(6) 或 DATETIME(6),明確精度需求。
  5. 測試邊界:單元測試覆蓋毫秒、納秒邊界、跨資料庫場景。

總結

java.sql.Date/Time 為 JDBC 1.0 早期設計,精度缺失是硬傷。現代 Java 應全面遷移至 java.time,從源頭消除精度陷阱,保證時間數據的準確性與一致性。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved