← 全部文章

Unix 時間轉日期 — 將任意 epoch 轉換為可讀日期

Unix 時間戳是自 1970-01-01 UTC 起的秒數。要將其轉換為日期,先以 UTC 解碼,再在任意時區格式化。本指南提供 JavaScript、Python、PHP、shell、SQL(Postgres、MySQL、SQLite、BigQuery)、Excel 和 Google Sheets 中的做法,涵蓋秒與毫秒的陷阱、UTC 與本地、微秒精度、負時間戳以及 2038 年問題。

一行搞定 Unix 時間轉日期

用一個範例說明整個任務:Unix 時間戳 1700000000 轉換為 2023-11-14T22:13:20Z——即 2023 年 11 月 14 日(星期二)22:13:20 UTC。Unix 時間戳計的是自 1970-01-01 UTC 起的秒數,因此轉換就是把這個計數以 UTC 解碼,再在你需要的時區格式化。唯一會讓轉換出錯的是單位:10 位是秒,13 位是毫秒,16 位是微秒。下表是本指南涵蓋的每種語言和工具、可直接複製的一行寫法。

語言 / 工具函式預期單位預設 UTC?
JavaScriptnew Date(s * 1000)毫秒否 — 傳入 timeZone 選項
Pythondatetime.fromtimestamp(s, tz=timezone.utc)僅當設定了 tz
JavaInstant.ofEpochSecond(s)是(Instant 為 UTC)
C# / .NETDateTimeOffset.FromUnixTimeSeconds(s)是(UTC 偏移)
Gotime.Unix(s, 0).UTC()需呼叫 .UTC()
PHPgmdate('c', s)是(gm = UTC)
Shell (GNU)date -u -d @s加 -u 即可
SQL (Postgres)TO_TIMESTAMP(s)是(TIMESTAMPTZ)
Excel / Sheets=A1/86400 + DATE(1970,1,1)

Unix 時間轉日期是什麼意思

Unix 時間戳是自 1970-01-01 UTC 起的秒數。要將其轉換為日期,先以 UTC 解碼,再在任意時區格式化。這就是一句話說清的全部問題——本指南其餘部分只是每種語言的語法。所有現代程式語言都內建了一個函式,接受 Unix epoch 值並回傳日期物件;你唯一需要留意的是該語言預期的是秒(Python、PHP、Linux date)、毫秒(JavaScript Date)還是微秒(PostgreSQL、BigQuery)。

快速轉換規則

數一數你這個值的位數。10 位的數是 Unix 秒。13 位的數是 Unix 毫秒。16 位的數是 Unix 微秒。Unix epoch 始於 1970-01-01——因此如今(2026 年)10 位的值以 17 或 18 開頭;毫秒以 175 或 176 開頭後跟 10 位;微秒以 1758 或 1759 開頭。在把值傳給任何轉換函式之前先判斷單位,你的輸出就會落在正確的日期,而不是 1970 年。

  • 10 位 → Unix 秒(範圍 2001 至 2286 年)
  • 13 位 → Unix 毫秒(範圍 2001 至 2286 年)
  • 16 位 → Unix 微秒(範圍 2001 至 2286 年)
  • 接近 10^9(1,000,000,000)的數是 2001 年之前的秒——仍是有效的 Unix 時間
  • 負整數是 1970 年之前的日期——多數語言能處理;需驗證
  • INT 欄中超過 2^31 的數會觸及 2038 年上限——見下文

在 JavaScript 中將 Unix 時間轉換為日期

JavaScript 的 Date 建構函式預期毫秒,所以 Unix 秒值必須先乘以 1000。結果是一個 Date 物件;用 toISOString() 取得 UTC 的 ISO 8601,或用 Intl.DateTimeFormat 取得帶時區、人類可讀的字串。務必傳入明確的 timeZone 選項——否則 JavaScript 會使用執行階段的本地時區,而它在開發筆電和正式環境伺服器上各不相同。

  • new Date(1700000000 * 1000).toISOString() // '2023-11-14T22:13:20.000Z'
  • new Date(1700000000 * 1000).toLocaleString('en-US', { timeZone: 'America/New_York' }) // tz-aware
  • new Date(1700000000000).toISOString() // milliseconds — no × 1000 needed
  • new Intl.DateTimeFormat('en-US', { timeZone: 'Asia/Tokyo', dateStyle: 'full', timeStyle: 'long' }).format(new Date(ms))
  • Detect unit at runtime: const toDate = ts => new Date(ts < 1e11 ? ts * 1000 : ts)

在 Python 中將 Unix 時間轉換為日期

datetime.fromtimestamp(ts, tz=timezone.utc) 是 Python 中的標準轉換。tz 參數是取得 UTC 結果所必需的;沒有它,Python 會以系統本地時區回傳時間戳——這是伺服器上時區偏移 bug 的常見來源。utcfromtimestamp() 自 Python 3.12 起已棄用,因為它回傳容易誤用的 naive datetime。毫秒除以 1000;微秒除以 1,000,000——Python 直接接受小數秒。

  • from datetime import datetime, timezone
  • datetime.fromtimestamp(1700000000, tz=timezone.utc) # 2023-11-14 22:13:20+00:00
  • datetime.fromtimestamp(1700000000.123, tz=timezone.utc) # fractional seconds work
  • datetime.fromtimestamp(ms / 1000, tz=timezone.utc) # from milliseconds
  • datetime.fromtimestamp(us / 1_000_000, tz=timezone.utc) # from microseconds
  • Avoid: datetime.utcfromtimestamp(ts) — deprecated in 3.12; returns naive datetime

在 PHP 中將 Unix 時間轉換為日期

PHP 的 gmdate(format, timestamp) 為給定的 Unix 秒回傳 UTC 日期字串;date(format, timestamp) 回傳同一時刻,但用伺服器的本地時區(由 date_default_timezone_set 或 php.ini 控制)。搭配 DateTimeZone 的 DateTime 類別提供現代、不可變的 API,並支援任意 IANA 時區名稱。PHP 預設以秒為單位,因此請先把毫秒值除以 1000。

  • gmdate('c', 1700000000) // '2023-11-14T22:13:20+00:00' (UTC ISO 8601)
  • date('Y-m-d H:i:s', 1700000000) // server-local — depends on date.timezone setting
  • new DateTime('@1700000000') // immutable, UTC by default with the @ prefix
  • (new DateTime('@1700000000'))->setTimezone(new DateTimeZone('Asia/Tokyo'))->format('c')
  • DateTime::createFromFormat('U.u', '1700000000.123456') // sub-second precision

在 Java 中將 Unix 時間轉換為日期

Java 的 java.time API(Java 8+)用 Instant.ofEpochSecond(s) 轉換 Unix 秒,回傳一個 UTC 時刻——Instant 始終是 UTC,因此沒有隱藏的本地時區陷阱。毫秒輸入用 Instant.ofEpochMilli(ms),用 atZone(ZoneId.of(...)) 附加時區以取得掛鐘表示,並用 DateTimeFormatter 格式化。舊版的 java.util.Date 建構函式像 JavaScript 一樣預期毫秒——請先把秒乘以 1000L。

  • Instant.ofEpochSecond(1700000000) // 2023-11-14T22:13:20Z (UTC)
  • Instant.ofEpochMilli(1700000000000L) // from milliseconds
  • Instant.ofEpochSecond(1700000000).atZone(ZoneId.of("Asia/Tokyo")) // tz-aware
  • DateTimeFormatter.ISO_INSTANT.format(Instant.ofEpochSecond(s)) // ISO 8601
  • new java.util.Date(1700000000L * 1000) // legacy API — expects milliseconds

在 C#(.NET)中將 Unix 時間轉換為日期

在 .NET 中,DateTimeOffset.FromUnixTimeSeconds(s) 是現代轉換——它回傳錨定到 UTC(+00:00)的 DateTimeOffset。毫秒輸入用 FromUnixTimeMilliseconds(ms)。讀取 .UtcDateTime 取得 UTC 的 DateTime,或用 TimeZoneInfo.ConvertTime 轉換到特定時區。用往返指定子 "o" 格式化為 ISO 8601。內建的 Unix 方法(.NET 4.6 加入)會處理 epoch 計算,因此請避免舊的 DateTime.AddSeconds(從 1970 起)寫法。

  • DateTimeOffset.FromUnixTimeSeconds(1700000000) // 2023-11-14 22:13:20 +00:00
  • DateTimeOffset.FromUnixTimeMilliseconds(1700000000000) // from milliseconds
  • DateTimeOffset.FromUnixTimeSeconds(s).UtcDateTime // DateTime in UTC
  • TimeZoneInfo.ConvertTime(dto, tzInfo) // tz-aware rendering
  • DateTimeOffset.FromUnixTimeSeconds(s).ToString("o") // ISO 8601 round-trip

在 Go 中將 Unix 時間轉換為日期

Go 的 time.Unix(sec, nsec) 從 Unix 秒(加可選奈秒)建構一個 Time,但它以本地時區回傳值——呼叫 .UTC() 來錨定。Go 1.17 加入了 time.UnixMilli(ms) 和 time.UnixMicro(us),因此你不再需要手動相除。用 RFC3339 常數格式化為 ISO 8601,用 time.LoadLocation 搭配 .In(loc) 指定特定時區。

  • time.Unix(1700000000, 0).UTC() // 2023-11-14 22:13:20 +0000 UTC
  • time.UnixMilli(1700000000000).UTC() // from milliseconds (Go 1.17+)
  • time.UnixMicro(1700000000000000).UTC() // from microseconds (Go 1.17+)
  • time.Unix(1700000000, 0).Format(time.RFC3339) // ISO 8601 string
  • time.Unix(s, 0).In(loc) // tz-aware; loc from time.LoadLocation

在 shell(Linux / macOS)中將 Unix 時間轉換為日期

在 Linux 上,GNU date 命令用 -d @ts 從 Unix 秒轉換;在 macOS 上,BSD date 命令用 -r ts 完成相同任務。這些旗標因歷史實作而異——但 epoch 計算本身是相同的。-u 旗標強制 UTC 輸出,無論 TZ 環境變數為何。兩種實作都透過 +%FORMAT 參數支援任意輸出格式;最有用的格式字串整理如下。

  • GNU (Linux): date -u -d @1700000000 // 'Tue Nov 14 22:13:20 UTC 2023'
  • GNU: date -u -d @1700000000 +'%Y-%m-%dT%H:%M:%SZ' // ISO 8601 UTC
  • BSD (macOS): date -u -r 1700000000 // same result, different flag
  • BSD: date -u -r 1700000000 +'%Y-%m-%dT%H:%M:%SZ'
  • Both: omit -u to use TZ environment variable; export TZ=America/New_York to override
  • Sub-second: date -u -d @1700000000.123 +'%Y-%m-%dT%H:%M:%S.%3NZ' (GNU only)

在 SQL(Postgres、MySQL、SQLite、BigQuery)中將 Unix 時間轉換為日期

每種主流 SQL 方言都有內建函式,把 Unix 秒(或毫秒、微秒)轉換為原生時間戳記欄位。函式名稱各異,但每個函式預期的單位都有文件說明,並在同一資料庫內保持一致。請使用專用函式,而不是用日期算術手動計算——內建函式能正確處理閏年、次秒精度和時區轉換。

  • PostgreSQL: TO_TIMESTAMP(1700000000) // returns TIMESTAMPTZ
  • PostgreSQL: TO_TIMESTAMP(unix_us / 1000000.0) // for microsecond input
  • MySQL: FROM_UNIXTIME(1700000000) // returns DATETIME in session timezone
  • MySQL: CONVERT_TZ(FROM_UNIXTIME(ts), @@session.time_zone, 'UTC') // force UTC
  • SQLite: datetime(1700000000, 'unixepoch') // returns TEXT 'YYYY-MM-DD HH:MM:SS'
  • SQLite: datetime(ms / 1000, 'unixepoch') // from milliseconds
  • BigQuery: TIMESTAMP_SECONDS(1700000000), TIMESTAMP_MILLIS(ms), TIMESTAMP_MICROS(us)
  • ClickHouse: toDateTime(1700000000), fromUnixTimestamp(1700000000)

在 Excel 中將 Unix 時間轉換為日期

Excel 把日期存為序列號——自 1900-01-01 起的天數。把 Unix 時間戳轉換為 Excel 日期只是單位換算:把 Unix 秒除以 86,400(每天的秒數)並加上 1970-01-01 這個日期,然後把儲存格格式化為日期。公式 =A1/86400 + DATE(1970,1,1) 是標準答案,在所有現代 Excel 中都有效。對於毫秒,改為除以 86,400,000。輸入公式後,選取儲存格,開啟「儲存格格式」(Ctrl+1),在「數值」分頁下選擇日期格式。

  • Seconds: =A1/86400 + DATE(1970,1,1) // when A1 holds the Unix seconds value
  • Milliseconds: =A1/86400000 + DATE(1970,1,1)
  • Microseconds: =A1/86400000000 + DATE(1970,1,1)
  • Format cell as Date after entering the formula (Ctrl+1 → Number → Date)
  • Caveat: Excel's epoch is 1900-01-01, not 1970, hence the + DATE(1970,1,1) offset
  • Reverse direction (date to Unix): =(A1 - DATE(1970,1,1)) * 86400

在 Google Sheets 中將 Unix 時間轉換為日期

Google Sheets 接受與 Excel 相同的標準公式,並另外提供專用的 EPOCHTODATE 函式。簡寫形式是 =EPOCHTODATE(A1, 1),其第二個參數是單位代碼:1 表示秒,2 表示毫秒,3 表示微秒。輸出是錨定到 UTC 的日期,Sheets 會依試算表的地區設定呈現。對於在不同時區的團隊間共用的試算表,請在欄標題中註明這些日期應代表哪個時區。

  • =EPOCHTODATE(A1, 1) // seconds — shorthand
  • =EPOCHTODATE(A1, 2) // milliseconds
  • =EPOCHTODATE(A1, 3) // microseconds
  • =A1/86400 + DATE(1970,1,1) // canonical formula — works in Sheets too
  • Reverse direction: =(A1 - DATE(1970,1,1)) * 86400
  • Time zone applied is the sheet's locale; check File → Settings → Time zone

UTC 日期與本地日期——該顯示哪個

Unix 時間戳編碼的是一個時刻,而不是掛鐘顯示。處於不同時區的兩位訪客會把同一個 Unix 時間戳看作不同的掛鐘日期。正確的行為取決於該日期代表什麼:事件記錄和稽核記錄應以 UTC 顯示,以便跨區域比較;面向使用者的日期(截止時間、會議時間、到期提醒)應以使用者的本地時區顯示。請始終擇一並記錄下來;切勿在不一併儲存來源時區的情況下,儲存一個已轉換為本地時間的字串。

  • 伺服器記錄 → 以 UTC 顯示,並明確標註欄位或圖表座標軸
  • 面向使用者的截止時間 → 以使用者的時區顯示(透過 Intl.DateTimeFormat().resolvedOptions().timeZone 自動偵測)
  • 週期性排程(「每週一上午 9 點 Eastern」)→ 與規則一併儲存時區,每次觸發時重新計算下一時刻
  • API 回應 → 帶 Z 後綴的 ISO 8601(UTC)是安全的預設值;讓用戶端去轉換
  • 資料庫儲存 → 始終 UTC;僅在展示層轉換

邊界情況:次秒精度、負時間戳與 2038 年

三種邊界情況會絆倒原本正確的程式碼。微秒時間戳(16 位)需要明確的單位處理;把它們當作秒會得到一個晚 1,000,000 倍的未來日期。負的 Unix 時間戳代表 1970 年之前的日期——多數語言能處理,但 Excel、Google Sheets 和某些 SQL 函式會在 1970 年截斷或回傳錯誤。2038 年問題是 32 位元有號整數溢位,發生在 2038-01-19 03:14:07 UTC;此後的值需要 BIGINT 儲存或 64 位元 time_t。

  • 微秒(16 位)— 在傳給語言層級的秒函式前先除以 1,000,000
  • 負秒 — 1970 年之前的日期;JavaScript Date、Python datetime、PHP DateTime 都能處理
  • Excel 中的負秒 — 會產生 #### 或錯誤日期;公式 =A1/86400 + DATE(1970,1,1) 僅用於正值
  • 2038 年 — INT 和有號 32 位元 time_t 在 2147483647 = 2038-01-19 03:14:07 UTC 溢位
  • 2038 年之後 — 存為 BIGINT(有號 64 位元可涵蓋 epoch 兩側各 2920 億年)
  • Excel 中早於 1900 年 — 應用程式無法呈現;轉換為文字或使用支援西元前的上游函式庫

將 Unix 時間轉換為日期時的常見 bug

每當有人第一次把 Unix 時間轉換為日期時,同一個 bug 都會出現:結果落在 1970 年。原因幾乎總是 JavaScript 中漏掉了 × 1000,或 Python 中缺少 tz 參數,或 Excel 自動截斷了數值欄位。配套的 bug 文章列出了全部 10 個——每一個都會出現在某個時刻轉換 Unix 時間的程式碼中。瀏覽一遍,大多數就再也不會進入正式環境。

  • 日期顯示為 1970 — 在預期毫秒處傳入了秒(JS Date 建構函式)
  • 日期偏差恰好為你的本地 UTC 偏移 — 忘記指定 tz=timezone.utc(Python)或 timeZone 選項(JS)
  • Excel 顯示 ##### 或 #VALUE! 錯誤 — 儲存格未格式化為日期,或值為負
  • SQL FROM_UNIXTIME 回傳錯誤的掛鐘時間 — MySQL 套用 @@session.time_zone;請明確強制 UTC
  • 伺服器與筆電產生不同日期 — 系統時區不同;務必明確傳入 tz

FAQ

如何從 Unix 時間戳取得日期?
判斷該值是秒(10 位)還是毫秒(13 位),然後呼叫所用語言的內建轉換:JavaScript 用 new Date(seconds * 1000),Python 用 datetime.fromtimestamp(seconds, tz=timezone.utc),PHP 用 gmdate('c', seconds),shell 用 date -u -d @seconds。
在 JavaScript 中如何從 Unix 時間戳取得日期?
將秒值乘以 1000(JavaScript 的 Date 建構函式預期毫秒),再用 toISOString() 或 Intl.DateTimeFormat 格式化。例如:new Date(1700000000 * 1000).toISOString() 會回傳 "2023-11-14T22:13:20.000Z"。
在 Python 中如何從 Unix 時間戳取得日期?
使用 datetime.fromtimestamp(unix_seconds, tz=timezone.utc)。tz 參數是取得 UTC 結果所必需的;沒有它,Python 會以系統本地時區回傳時間戳。utcfromtimestamp() 自 Python 3.12 起已棄用。
如何將 Unix 時間轉換為日期?
以正確的單位(秒或毫秒)和 UTC 時區,將該值傳給所用語言內建的 epoch 轉 datetime 函式。結果是同一時刻,格式化為可讀日期。
Linux 時間和 Unix 時間一樣嗎?
是的。Linux、macOS 以及所有 Unix 衍生系統都使用相同的 epoch 基準——自 1970-01-01 00:00:00 UTC 起的秒數。date 命令、time() 系統呼叫和 clock_gettime() 都回傳 Unix 時間。
為什麼我的 Unix 時間戳轉換成了 1970 年?
幾乎總是因為你把秒傳給了預期毫秒的函式(或 0 / null 被轉為數字)。在 JavaScript 中 new Date(1700000000) 會落在 1970 年 1 月——建構函式預期毫秒。請先乘以 1000。
在 Excel 中如何將 Unix 時間轉換為日期?
當 A1 中是 Unix 秒時,使用 =A1/86400 + DATE(1970,1,1)。在「儲存格格式」對話方塊中將結果格式化為日期。對於毫秒,先除以 86400000:=A1/86400000 + DATE(1970,1,1)。
在 Google Sheets 中如何將 Unix 時間轉換為日期?
與 Excel 相同的標準公式:=A1/86400 + DATE(1970,1,1)。Google Sheets 也接受較短的 =EPOCHTODATE(A1, 1),其第二個參數是單位(1 = 秒,2 = 毫秒,3 = 微秒)。
如何處理微秒級 Unix 時間戳(16 位)?
先除以 1,000,000 得到秒,再照常轉換。Python 3.7+ 直接接受小數秒:datetime.fromtimestamp(unix_us / 1_000_000, tz=timezone.utc)。PostgreSQL TO_TIMESTAMP 和 BigQuery TIMESTAMP_MICROS 原生支援微秒。