在 Java 開發中,經常需要獲取當天零點(00:00:00)的 Timestamp,例如用於資料庫查詢的時間範圍起始值。乍看之下只是格式化輸出,但若忽略時區偏移,極易踩坑。本文將示範如何正確獲取午夜 Timestamp,並解析時區對結果的影響。
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class MidnightTimestampDemo {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
long now = System.currentTimeMillis();
// 錯誤示範:直接對 86400000 取模,未考慮時區
long t1 = now / (1000 * 3600 * 24) * (1000 * 3600 * 24);
System.out.println("未扣時區偏移: " + sdf.format(new Timestamp(t1)));
// 正確做法:扣除當地時區原始偏移量
long t2 = now / (1000 * 3600 * 24) * (1000 * 3600 * 24)
- TimeZone.getDefault().getRawOffset();
System.out.println("扣除時區偏移: " + sdf.format(new Timestamp(t2)));
}
}
1000 * 3600 * 24 = 86,400,000 毫秒,即一天的總毫秒數。對當前時間戳進行整除再乘回,可將時間「對齊」到最近的午夜基準點(UTC 1970-01-01 00:00:00 起算的整天倍數)。
TimeZone.getDefault().getRawOffset() 回傳當地時區相對 UTC 的固定偏移毫秒數(不含夏令時)。若不扣除,輸出會是 UTC 零點對應的本地時間。例如東八區(GMT+8)會顯示為 08:00:00,而非預期的 00:00:00。
import java.time.LocalDate;
import java.time.ZoneId;
import java.sql.Timestamp;
public class ModernMidnight {
public static void main(String[] args) {
// 直接獲取今天零點的 Timestamp,自動處理時區
Timestamp midnight = Timestamp.valueOf(LocalDate.now().atStartOfDay());
System.out.println("Java 8 寫法: " + midnight); // 2024-05-20 00:00:00.0
}
}
LocalDate.now().atStartOfDay() 會依據系統預設時區產生當天 00:00:00 的 LocalDateTime,再轉為 Timestamp 即可,程式碼更簡潔且不易出錯。
TimeZone.getRawOffset()。java.time 套件,語意清晰且自動處理時區。