UnixタイムスタンプとEpoch時刻を理解する
Unixエポック、時刻の単位、UTC、整数精度、2038年・2106年問題、うるう秒をコード例で解説します。
タイムスタンプは、ある時間尺度上で出来事の位置を表します。値を交換するには、基準時点、単位、時計の種類を合わせる必要があります。起動後のカウンターはUTC日時そのものではありません。Unixタイムスタンプ / Epoch変換では、入力をサーバーへ送らずに日時と地域の表現を確認できます。
Unixエポックと1970年の意味
原点は1970年1月1日00:00:00 UTCです。Unixに由来する歴史的な取り決めであり、物理的な時間の始まりではありません。原点を変えても出来事は同じで、数値が変わるだけです。NTPは1900年を基準にし、GPSや機器独自のカウンターは別の規則を使います。数値だけで基準を特定することはできません。
カウント方法と負の値
通常のPOSIX暦計算では、名目上のUTCの1日を86400秒として扱います。1970年1月2日00:00 UTCは86400です。ただし現地暦の1日が常に24時間という意味ではありません。正の値はエポック以後、−1は1969年最後の1秒を表します。Unixの数値自体はタイムゾーンに依存しません。
秒・ミリ秒・マイクロ秒・ナノ秒
| タイムスタンプの単位 | 1 s | 1700000000 s |
|---|---|---|
| 秒 (s) | 1 | 1700000000 |
| ミリ秒 (ms) | 1000 | 1700000000000 |
| マイクロ秒 (µs) | 1000000 | 1700000000000000 |
| ナノ秒 (ns) | 1000000000 | 1700000000000000000 |
秒を1000倍するとミリ秒、10億倍するとナノ秒になります。ゼロを増やしても時計の正確さは向上しません。JavaScript Dateの入力はミリ秒で、多くのCのAPIは秒です。フィールド名とデータ仕様に単位を明記してください。
UTC、オフセット、IANA識別子
2023-11-14 22:13:20 UTCとパリの23:13:20は同じ瞬間です。+01:00はその時点の差を示し、Europe/Parisは時期に応じた現地時刻の規則を示します。CSTのような略語は地域によって意味が異なります。
存在しない時刻と2回現れる時刻
パリの2024-03-31 02:30は存在しません。2024-10-27 02:30は2回あり、それぞれ00:30 UTCと01:30 UTCに対応します。この変換ツールは存在しない時刻を拒否し、繰り返し時刻は早い方か遅い方を選択できます。年内の通算日は現地の暦要素から計算し、経過時間を24時間で割る方法は使いません。過去と将来の結果はブラウザーのIANAデータに依存し、政治的な規則変更もあり得ます。
計算例と代表値
1700000000秒を1000倍すると1700000000000ミリ秒で、どちらも2023-11-14T22:13:20Zです。123456789ナノ秒を加えると1700000000123456789 ns、小数部は.123456789になります。Dateでは.123までしか表示できないため、残る456789 nsは別に保持します。
| Unix秒 | ISO 8601 (UTC) |
|---|---|
| -1 | 1969-12-31T23:59:59Z |
| 0 | 1970-01-01T00:00:00Z |
| 1000000000 | 2001-09-09T01:46:40Z |
| 1700000000 | 2023-11-14T22:13:20Z |
| 2147483647 | 2038-01-19T03:14:07Z |
| 4294967295 | 2106-02-07T06:28:15Z |
−1 nsは1969-12-31T23:59:59.999999999Zで、それを含む整数ミリ秒は−1 msです。整数除算をゼロ方向へ丸めると、誤ってエポックになります。負の値は商を負の無限大方向に丸め、余りを保存する必要があります。
符号付き32ビットと2038年問題
範囲は−2³¹~2³¹−1です。最後の正の秒数2147483647は2038-01-19T03:14:07Zで、次の秒は収まりません。Cの符号付き整数のオーバーフローは未定義動作です。1901年に折り返すという観測に依存せず、計算前に型を広げ、ファイルや通信のフィールドも確認してください。
符号なし32ビットと2106年
0~4294967295秒の終端は2106-02-07T06:28:15Zで、1970年以前を直接表せません。unsignedへの変更は終端を移動し負値の意味を変えるだけで、長期運用に向けた全面的な形式移行にはなりません。
64ビットの範囲と数値精度
符号付き64ビットの秒は両方向に約2920億年ですが、同じ幅のナノ秒は約292年で、正側は2262年までです。暦ライブラリの範囲はさらに狭いことがあります。binary64がすべての整数を正確に表せるのは2⁵³−1までです。現在のナノ秒値にはBigIntまたは十進文字列を使います。32ビット浮動小数点は32ビット整数秒と同じ精度ではありません。
うるう秒とPOSIXの限界
POSIXは1970年以後の実際のSI秒をすべて数える尺度ではなく、UTCの:60に通常の一意なタイムスタンプを割り当てません。システムによって時刻の跳躍、繰り返し、平滑化が行われます。TAIやGPSへ永続的に一定の差で変換できると考えないでください。補正をまたぐ物理的な経過時間を暦時計の差だけで保証することもできません。
JavaScript / TypeScriptの例
const timestampNs = BigInt("1700000000123456789");
const divisor = BigInt(1_000_000);
const q = timestampNs / divisor;
const ms = timestampNs < 0 && timestampNs % divisor !== BigInt(0)
? q - BigInt(1) : q;
if (ms < BigInt("-8640000000000000") || ms > BigInt("8640000000000000")) {
throw new RangeError("Date");
}
const iso = new Date(Number(ms)).toISOString();
console.log(iso);
console.log(timestampNs.toString());
表示は2023-11-14T22:13:20.123Zですが、元の整数は小数部をすべて保ちます。変換ツールはDateを作る前にナノ秒全体の範囲を検証し、ISOとRFC 3339の小数部を別に構成します。RFC 3339は4桁年のため0000~9999年の範囲外では利用不可と表示します。RFC 2822は1900年以後の整数秒を表示します。
浮動小数点を介さないPython
from datetime import datetime, timezone, timedelta
epoch = datetime(1970, 1, 1, tzinfo=timezone.utc)
instant = datetime(2023, 11, 14, 22, 13, 20, 123456, tzinfo=timezone.utc)
delta = instant - epoch
timestamp_us = ((delta.days * 86400 + delta.seconds) * 1_000_000
+ delta.microseconds)
restored = epoch + timedelta(microseconds=timestamp_us)
assert restored == instant
print(timestamp_us, restored.isoformat())
UTCを明示すると実行環境の現地設定に依存しません。timedeltaによる計算は整数マイクロ秒を保持します。timestamp()の浮動小数点結果は細かい桁を丸める可能性があり、datetimeはナノ秒を保持しません。IANA地域にはzoneinfoを使い、繰り返し時刻の規則を決めます。
Cと組み込みでの保存
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
int main(void) {
int64_t seconds = INT64_C(1700000000);
int64_t milliseconds = seconds * INT64_C(1000);
int64_t after_2038 = (int64_t)INT32_MAX + INT64_C(1);
printf("%" PRId64 " %" PRId64 "\n", milliseconds, after_2038);
return 0;
}
この例の積はint64_tに収まりますが、汎用コードでは乗算前に範囲確認が必要です。64ビットCPUでもtime_tが64ビットとは限りません。time_tの生バイトを保存するとABIやバイト順に依存します。幅、符号、単位、エポックを通信仕様で定義してください。同期と保存の設計は組み込みシステム・API・データベースでのUnixタイムスタンプで扱います。
よくある間違い
- 秒をDateに渡す、または桁数だけで単位を推測する。
- 長い文字列をNumberにしてからBigIntにし、失った桁を復元できると考える。
- 地域のオフセットを二重に足す。
- 2月31日を自動正規化して受け入れる。
- 表示の細かさと時計の正確さを混同する。
技術FAQ
地域を変えるとタイムスタンプも変わりますか?
同じ瞬間の暦表現が変わるだけです。新しい現地日時の入力を解釈する場合は、地域が必要になります。
負の値に小数を使えますか?
使えます。−0.5秒はエポックの半秒前です。単位変換では符号と余りを保ちます。
現在時刻はネットワーク時刻サービスですか?
端末の時計を読むだけで、NTP通信は行いません。精度はOS側の同期に依存します。
関連ツールと出典
Unixタイムスタンプ / Epoch変換 · 組み込みシステム・API・データベースでのUnixタイムスタンプ · 周波数許容差 · PPMとHzの変換。