System.currentTimeMillis() 返回毫秒級時間戳 (1970 至今);System.nanoTime() 返回納秒級相對時間 (無絕對意義,僅用於測量間隔)。本文深度對比精度、用途、陷阱、單位轉換、實戰代碼模板,助你精準選型。
| 維度 | currentTimeMillis() | nanoTime() |
|---|---|---|
| 語義 | 牆鐘時間 | 單調時鐘 |
| 基準點 | 1970-01-01 00:00:00 UTC | JVM 啟動/系統啟動 (實現相關) |
| 返回值 | 毫秒 | 納秒 (10⁻⁹ 秒) |
| 精度 | OS 依賴,通常 10-50ms | CPU 週期級,理論 1ns |
| 單調性 | ❌ 可被 NTP/用戶調時間倒退 | ✅ 單調遞增 (不受調時間影響) |
| 用途 | 業務時間戳、日誌、緩存過期、日期顯示 | 代碼執行耗時、基準測試、超時控制 |
| 轉 Date | new Date(ms) 直接轉 | 無意義,不可轉 |
| 溢出 | 292,278,994 年後 (long 極限) | 292 年後 (2⁶³ ns) |
1 秒 = 1,000 毫秒 (ms)
1 秒 = 1,000,000 微秒 (μs)
1 秒 = 1,000,000,000 納秒 (ns)
1 秒 = 1,000,000,000,000 皮秒 (ps)
1 分 = 60 秒
1 時 = 3,600 秒 = 3,600,000 ms
long now = System.currentTimeMillis(); // 1705574400000
// 1. 轉 Date 格式化
Date date = new Date(now);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(date)); // 2024-01-18 14:40:00
// 2. 時間運算:1 小時後 / 1 分鐘後
long oneHourLater = now + 3600 * 1000; // + 1小時
long oneMinLater = now + 60 * 1000; // + 1分鐘
System.out.println(sdf.format(new Date(oneHourLater)));
// 3. 獲取系統屬性 (順帶)
System.out.println("OS: " + System.getProperty("os.name"));
System.out.println("User: " + System.getProperty("user.name"));


// 標準測量模板
long start = System.nanoTime();
// ... 被測代碼 ...
long elapsedNs = System.nanoTime() - start;
double elapsedMs = elapsedNs / 1_000_000.0;
double elapsedSec = elapsedNs / 1_000_000_000.0;
System.out.printf("耗時: %.3f ms (%.6f s)%n", elapsedMs, elapsedSec);
// 實戰:比較兩個無序 String 數組是否相等 (利用異或特性)
public static boolean equals(String[] a, String[] b) {
if (a.length != b.length) return false;
int n = a[0].hashCode() ^ b[0].hashCode();
for (int i = 1; i < a.length; i++) {
n ^= a[i].hashCode() ^ b[i].hashCode();
}
return n == 0;
}
// 測試
String[] a = {"aaa", "aaa", "ccc"};
String[] b = {"aaa", "bbb", "ccc"};
long start = System.nanoTime();
boolean eq = equals(a, b);
long end = System.nanoTime();
System.out.println("結果: " + eq + ", 耗時: " + (end - start) + " ns");
| 陷阱 | 錯誤做法 | 正確做法 |
|---|---|---|
| 用 currentTimeMillis 測微秒級耗時 | long t=System.currentTimeMillis(); ... System.currentTimeMillis()-t | 精度不夠,必用 nanoTime |
| 用 nanoTime 存業務時間 | 存入 DB 作為創建時間 | 無絕對意義,**用 currentTimeMillis** |
| 跨 JVM 比較 nanoTime | 兩服務器比較 nanoTime 差值 | 基準點不同,**不可跨進程比較** |
| nanoTime 負值恐慌 | 看到負數以為 Bug | 基準點可能在未來,**負值正常**,只關心差值 |
| 頻繁 new Date() | 循環中反複 new Date() | 提取 long now = System.currentTimeMillis() 復用 |
nanoTime 讀取 clock_gettime(CLOCK_MONOTONIC) (vdso 加速,無系統調用開銷);currentTimeMillis 讀 gettimeofday / clock_gettime(CLOCK_REALTIME)。nanoTime 用 QueryPerformanceCounter (高精度計數器);currentTimeMillis 用 GetSystemTimeAsFileTime (100ns 精度但粒度 ~15ms)。nanoTime 非單調 (極少見)。需要「具體年月日時分秒」業務時間戳?
├─ 是 → System.currentTimeMillis()
└─ 否 → 需要「測量間隔/耗時/超時/基準測試」?
├─ 是 → System.nanoTime()
└─ 否 → 重新審視需求
一句话心法:牆鐘看 currentTimeMillis,碼表用 nanoTime。業務邏輯存毫秒戳,性能分析測納秒差。