Unix エポック — すべての時刻が起点として参照する零点
Unix タイムスタンプは 1970-01-01 00:00:00 UTC からの経過秒 (システムによりミリ秒・マイクロ秒) を数えたものです。この瞬間が 「Unix エポック」であり、AT&T ベル研究所のチームが 1970 年代 前半に採用しました。当時としては表現が小さく済む十分過去であり、 負の日付で扱いにくくなる時期までの余裕も残るタイミングです。 Unix 系環境の時刻認識システムは最終的にこのスカラーに集約されます。
覚えておく価値がある帰結が 2 つあります。1 つ目、タイムスタンプは タイムゾーンを無視します。ソウルとロサンゼルスにある 2 台の マシンが同時刻に取得した Unix 値は同じであり、人間向けの表記 だけが異なります。2 つ目、うるう秒は表現されません。Unix タイムスタンプはすべての日を厳密に 86,400 秒として扱い、IERS が UTC の日末にうるう秒を挿入すると、Unix の値は静かに同じ秒を 繰り返すか平滑化して吸収します。POSIX がこの挙動を規定して おり、ほとんどのアプリは気にする必要がありません。
同じ瞬間が異なる書式でどう表されるか
同じ瞬間がシステムによって半ダースほどの異なる書式で現れます。 どの書式かを把握すれば適切なパーサを選べますし、精度を理解すれば ミリ秒やマイクロ秒の値を「遥か未来の秒」と取り違えるのを防げます。
| 形式 | 例 | 精度 | よく見かける場所 |
|---|
| Unix seconds | 1747353600 | 1 秒 | 多くのデータベース、JWT の exp/iat、Unix のファイル更新時刻。 |
| Unix milliseconds | 1747353600000 | 1 ミリ秒 | JavaScript の Date.now()、Java の System.currentTimeMillis()、Kafka のログ時刻。 |
| Unix microseconds | 1747353600000000 | 1 マイクロ秒 | PostgreSQL の TIMESTAMP、Python の time.time_ns() / 1000、一部のトレーシング基盤。 |
| ISO 8601 | 2025-05-16T00:00:00Z | 可変 | REST API、RFC 3339 (厳密なサブセット)、HTML <time>、ログ形式。 |
| RFC 2822 | Fri, 16 May 2025 00:00:00 +0000 | 1 秒 | メールヘッダ (Date:)、RFC 9110 の HTTP Date ヘッダ。 |
| JS Date.toString | Fri May 16 2025 09:00:00 GMT+0900 (JST) | 1 秒 | V8 既定。標準ではなくエンジンにより異なるため、シリアライズには使わない。 |
タイムゾーン、UTC オフセット、IANA データベース
タイムスタンプ単体は曖昧さがありません。世界中どこでも同じ瞬間を 指します。一方、「2025-05-16 09:00」のような壁掛け時計の日付は 曖昧で、タイムライン上の点として確定させるにはタイムゾーンが 必要です。「瞬間」と「時計の見た目」の間のずれが、日付関連バグ のほぼすべてが棲む場所です。
+09:00 のような UTC オフセットは、ある一瞬における UTC と現地 時刻の差を切り取った値です。タイムゾーンと同じではありません。 America/Los_Angeles はタイムゾーンであり、年 2 回 -07:00 と -08:00 を切り替えます。IANA タイムゾーンデータベース (tzdata) は 1970 年以降の全地域・全切替を記述しており、ほとんどの OS と ランタイムが同梱しています。瞬間を保存するときは UTC + タイム ゾーン識別子か、Unix タイムスタンプを保存します。壁掛けの 文字列だけを保存してはいけません。ユーザー向けに整形するときは タイムゾーンを引いて適用します。今日必要なオフセットが、来週 日曜にも必要なオフセットとは限りません。
Y2038 とその他の時計ロールオーバー期限
Y2038 は Y2K のいとこに当たる問題です。Unix 秒を 32 ビット 符号付き整数で保持していると、2038-01-19T03:14:07Z でオーバー フローします。次の 1 秒で値は負に転じ、多くのコードがこれを 1901 年として読みます。秒数を 32 ビットで保持しているシステム (古い組み込みファームウェア、一部の C 構造体 (32 ビット Linux の time_t)、古いデータベース列など) は、64 ビットへ移行する 前にこの瞬間を迎えると誤動作します。
隣接する書式にも別のロールオーバー期限があります。GPS の週番号 は 10 ビットカウンタで、1999 年と 2019 年に巻き戻りました。 NTP の 32 ビット秒カウンタは 2036 年に溢れます。Windows の FILETIME は 1601-01-01 起点の 100 ナノ秒刻みで、30828 年まで 安全です。JavaScript の Number は 2^53 ミリ秒までの整数を厳密に 表現でき、これは概ね西暦 287396 年に相当する余裕ある値ですが、 自前で算術を書くなら明示的に意識する価値があります。時刻を 保存している箇所を棚卸しし、32 ビット秒が残っていれば期限内に 移行を済ませてください。インシデント発生時に対応するのは最悪の タイミングです。
エンジニアが月に何度も噛まれる落とし穴 5 つ
1 つ目、秒とミリ秒の取り違えです。1747353600 は 2025 年 5 月 ですが、0 を 3 つ足した 1747353600000 もミリ秒として 2025 年 5 月を指します。両者を取り違えると西暦 57344 年付近に飛びます。 上のツールは桁数で自動判定しますが、自分のコードではどちらの 単位を扱っているかを明示してください。
2 つ目、JavaScript の Date は月が 0 始まりです。new Date(2025, 5, 1) は 5 月ではなく 6 月になります。ISO 文字列を使うか、 date-fns や Luxon のようなライブラリを使ってこの罠を回避して ください。
3 つ目、「深夜 0 時」は曖昧です。ローカルの 00:00:00 は、自分の ロケールが UTC でない限り UTC の 00:00:00 と同じ瞬間ではあり ません。日次レポートでは境界がローカル 0 時か UTC 0 時かを最初 に決め、仕様に書き残してください。
4 つ目、DST と歴史的なゾーン変更です。「1 日を加える」を 365 回 繰り返すと DST 境界で 1 時間ずれます。生のミリ秒演算ではなく、 タイムゾーン認識の演算を提供するライブラリを使ってください。 歴史的変更も実在します。ロシアは 2011 年に DST を廃止し 2014 年に復活させました。トルコは 2016 年に夏時間を恒久化しました。 これらは tzdata に取り込まれています。
5 つ目、マイクロ秒精度は失われます。JavaScript の Date は 1 ms 精度で、PostgreSQL の TIMESTAMP を JavaScript 経由でシリアライズ すると末尾のマイクロ秒が静かに切り詰められます。高精度の テレメトリでは、完全精度の値を文字列または BigInt として伝送し、 プレゼンテーション層でのみ変換するようにしてください。
使い方
Unix タイムスタンプ(秒またはミリ秒)、ISO 8601 文字列、RFC 2822 形式の日付、または `new Date()` が解釈できる任意の文字列を貼り付けてください。フォーマットを自動判定し、同じ瞬間を 7 通りで同時に表示します。Unix 秒、Unix ミリ秒、UTC の ISO 8601、ローカルタイムゾーンの ISO 8601、人間向け UTC 表記、人間向けローカル表記、そして毎秒更新される相対時間("3 分前"など)です。
Now ボタンは現在の Unix 秒を入力欄に流し込みます。秒とミリ秒は桁数で判定します。10^12 以上はミリ秒として扱うため、10 桁の値は秒、13 桁の値はミリ秒になります。この閾値は 33658 年まで持つので余裕は十分です。変換はすべて JavaScript の Date と Intl API を使ってブラウザ内で完結し、サーバとの往復はありません。
例
ログ行の Unix 秒タイムスタンプを変換
出力
Unix sec: 1716800400
Unix ms: 1716800400000
UTC: 2024-05-27T09:00:00.000Z
Local: 2024-05-27T18:00:00+09:00 (Asia/Tokyo)
Relative: about 2 years ago
多くのサーバログ(nginx、syslog、Go の `time.Now().Unix()` や Python の `time.time()` 由来のアプリケーションタイムスタンプ)は秒で出力します。ローカル表示はブラウザのタイムゾーンを適用するため、別リージョンのサーバログを照合するときに便利です。
ミリ秒タイムスタンプを自動判定
出力
Unix sec: 1716800400
Unix ms: 1716800400000
UTC: 2024-05-27T09:00:00.000Z
JavaScript の `Date.now()`、Java の `System.currentTimeMillis()`、多くの JSON API はミリ秒で出力します。13 桁の長さでミリ秒判定が走り、同じ瞬間の秒表記は 10 桁になります。どちらの単位かを覚えておく必要はなく、貼り付ければ判別されます。
オフセット付きの ISO 8601 文字列をパース
入力
2024-05-27T18:00:00+09:00
出力
Unix sec: 1716800400
UTC: 2024-05-27T09:00:00.000Z
Local: 2024-05-27T18:00:00+09:00
入力にオフセットが含まれている場合、パースは曖昧さなく決まります — タイムゾーンの推測が入りません。オフセットなしの `2024-05-27 18:00:00` はブラウザのタイムゾーンで読まれます。API 契約では明示的なオフセット(または UTC を示す末尾の `Z`)を優先してください。
よくある質問
秒とミリ秒の判定はどう行っていますか?
桁の大きさで判定します。10^12 以上はミリ秒、それより小さい数値は秒として読みます。閾値は秒換算で 33658 年に相当するため、今世紀のタイムスタンプはすべて曖昧さなく判定できます。どうしても単位を強制したい場合は、秒値に `000` を付けてミリ秒帯へ押し込むか、ミリ秒値を外部で割ってください。
2038 年問題とは何ですか?このツールは影響を受けますか?
2038 年問題は、符号付き 32 ビット Unix タイムスタンプが 2038-01-19 03:14:07 UTC を境にオーバーフローして 1901 年に巻き戻る現象です。本ツールは JavaScript の Number(53 ビットの安全整数範囲)で秒・ミリ秒を扱うため、変換そのものに 2038 境界はありません。リスクは下流に潜みます。32 ビットプラットフォーム上で `time_t` を使う C プログラムに 2^31 を超える値を渡すと誤読されます。エンドツーエンドで 64 ビット(`int64`・`BIGINT`)で保存・伝送してください。
ISO 8601 と RFC 3339 は同じですか?
RFC 3339 はインターネットプロトコル向けに絞った ISO 8601 の厳格な部分集合です。ISO 8601 は基本形式(ハイフンなし)、週日表記、年内通日表記、コンマ小数点など複数のオプション形を認めます。RFC 3339 はこれを狭めます。拡張形式のみ、日付と時刻の区切りは `T` またはスペース、オフセット必須、ドット小数点、というルールです。JavaScript の `Date` パーサは RFC 3339 形式を確実に受け付けますが、ISO 8601 の一部の変種では失敗することがあります。API を設計する際は "ISO 8601" ではなく "RFC 3339" と書いた方が、緩い解釈を避けられます。
ローカル表示が UTC と違う日付になるのはなぜですか?
Unix タイムスタンプは一つの瞬間を表します。同じ瞬間が東京では「今日」、ニューヨークでは「昨日」になることがあるからこそ、両方の表示が必要です。サーバログが `1716800400`、ダッシュボードが `2024-05-27 18:00 JST` と出すとき、カリフォルニアの同僚は同じ行を `2024-05-27 02:00 PDT` として見ます。タイムスタンプを話題にするときは、必ずレンダリング規則(UTC・ローカル・固定タイムゾーンのどれか)を添えてください。
1970 年より前の日付も変換できますか?
はい。負の Unix タイムスタンプも有効です。`−1` は 1969-12-31T23:59:59Z を表します。`1969-06-20T20:17:40Z`(アポロ 11 号月面着陸)のような ISO 8601 文字列を貼り付ければ、対応する負の Unix 値が得られます。JavaScript の Date はエポックから約 ±1 億日を扱えるので、通常の業務で出てくる過去や遠未来の日付は問題なくパースできます。
GPS 時刻と比較すると 18 秒ずれているのはなぜですか?
Unix 時刻は 1 日を厳密に 86400 秒として扱い、うるう秒を静かにスキップします。GPS 時刻はそうではありません。2026 年半ば時点で累積差は 18 秒(Unix が GPS より 18 秒遅れ)です。両端が Unix 時刻を使うソフトウェアでは事実上見えませんが、GNSS 受信機、天文ソフトウェア、TAI / GPS 時刻を保存する旧来システムと連携するときだけ問題になります。
関連する概念
Unix タイムスタンプは 1970-01-01T00:00:00 UTC からの経過秒数で、1 日を 86400 秒として扱う(うるう秒は静かにスキップされる)単純な仕様です。同じ瞬間をカレンダー形式で表示するには、追加で 3 つの情報が必要です。暦(グレゴリオ暦)、タイムゾーン(UTC からのオフセットおよび DST ルール)、ロケール("May" / "5월" / "5月" の言語と順序)。本ツールはこれら 3 層を並べて表示するため、どれが絶対的な瞬間でどれがレンダリングの選択かがはっきりします。
単位の取り違えは想像以上に問題を起こします。Unix 秒は現在 10 桁、ミリ秒は 13 桁、マイクロ秒(データベースや一部ログフレームワークで一般的)は 16 桁、ナノ秒(Go の `time.Now().UnixNano()`、現代の syslog)は 19 桁です。単位を誤ると、ミリ秒のフィールドを秒として読むと 52000 年先に飛びますし、秒のフィールドをミリ秒として読むと 1970 年 1 月に着地します。本ツールが用いる 10 対 13 の桁数判定は現在のタイムスタンプに対しては有効ですが、高精度な値を扱う場合は明示的な変換が必要です。
隣接する 3 つの標準も押さえておく価値があります。**ISO 8601** はカレンダー / 日付の広い標準で、`2024W221` や `2024-148T18:00:00` といった多くの任意形式を含みます。**RFC 3339** はインターネットプロトコル向けに狭めた厳格な部分集合で、多くの API ドキュメントが "ISO 8601" と言うときに実際に意味しているのはこちらです。**TAI** はうるう秒を実際に数える原子時系で、現在 Unix 時刻より 18 秒進んでいます。この差は GNSS、天文、`chrony` を TAI モードで同期しているシステムなどで問題になります。