基礎知識 · 日付と時刻
Unix タイムスタンプとは?
結論
Unix タイムスタンプは、Unix エポックと呼ばれる1970年1月1日 00:00:00 UTC からの経過秒数で、うるう秒は数えません。タイムゾーンを持たない1つの整数なので、1700000000 はどこでも同じ瞬間、2023年11月14日 22:13:20 UTC を表します。JavaScript や多くの API は代わりにミリ秒を使うため、数字が3桁長くなります。
この数値の定義
POSIX は「エポックからの秒数」を決まった式で定義しています。1日を常にちょうど 86,400 秒とし、1970-01-01T00:00:00Z から数え始めます。エポックより前の時点は負の値になるので、-1 は 1969-12-31T23:59:59Z です。
値は UTC で測るため、タイムゾーンも夏時間も持ちません。壁時計の時刻に変換するのは別の手順で、Asia/Tokyo や America/New_York などのタイムゾーンが必要です。
| タイムスタンプ(秒) | UTC の日時 | 備考 |
|---|---|---|
0 | 1970-01-01T00:00:00Z | Unix エポック |
1000000000 | 2001-09-09T01:46:40Z | 初めての 10 桁の値 |
1234567890 | 2009-02-13T23:31:30Z | よく知られた節目 |
1700000000 | 2023-11-14T22:13:20Z | 最近のきりのいい数 |
1791936000 | 2026-10-14T00:00:00Z | 2026年10月14日 0 時 UTC |
2147483647 | 2038-01-19T03:14:07Z | 符号付き 32 ビットの最大値 |
秒・ミリ秒・その他の単位
本来の Unix タイムスタンプは秒単位ですが、より細かい単位で保存するシステムも多くあります。現在の日付なら、桁数で見分けるのがいちばん手っ取り早い方法です。
| 単位 | 現在の桁数 | 同じ瞬間の例 | 主な使用場面 |
|---|---|---|---|
| 秒 | 10 | 1700000000 | Unix のツール、PHP の time()、Python の time.time()(浮動小数点数)、JWT の exp クレーム |
| ミリ秒 | 13 | 1700000000000 | JavaScript の Date.now()、Java の System.currentTimeMillis() |
| マイクロ秒 | 16 | 1700000000000000 | PostgreSQL の内部、一部のログシステム |
| ナノ秒 | 19 | 1700000000000000000 | Go の time.UnixNano()、高精度のトレーシング |
単位の取り違えは、タイムスタンプで最もよくあるバグです。秒の値を JavaScript の new Date() に渡すと1970年1月になり、ミリ秒の値を秒として読むと数万年先の未来になります。JavaScript では、秒を得るには Math.floor(Date.now() / 1000)、元に戻すには new Date(seconds * 1000) で変換します。
うるう秒は数えない
UTC は地球の自転とずれないよう、ときどきうるう秒を挿入します。1972年以降、27 回追加されました。Unix 時間はこれを無視します。POSIX の式は毎日を 86,400 秒とみなすため、うるう秒はシステムによって、同じ秒を繰り返すか、長い時間に分散して吸収(スメア)されます。
実際には、2つのタイムスタンプの差で求めた経過時間は、その間のうるう秒の数だけずれることがあります。日常のスケジュール管理ならこの誤差は問題になりませんが、科学や金融の時刻管理では TAI や GPS 時刻が使われます。国際的な時刻管理機関は2022年、2035年までにうるう秒の挿入をやめることを決議しました。
2038年問題
古いソフトウェアは Unix 時間を符号付き 32 ビット整数で保存しており、その最大値は 2147483647 です。この値には 2038-01-19T03:14:07Z に達します。その1秒後にカウンターがオーバーフローして -2147483648 になり、1901-12-13T20:45:52Z と解釈されます。
- 最近の 64 ビットの OS、言語、データベースは 64 ビットの
time_tを使っており、約 2920 億年もちます。 - リスクが残るのは、組み込み機器、古いファイル形式、MySQL の
TIMESTAMPのような 32 ビットのデータベース列、時刻に 4 バイトしか確保していないバイナリプロトコルです。 - 20 年有効の証明書、住宅ローン、有効期限など、遠い将来の値はすでに2038年を超えているため、このバグはその日付よりずっと前に表れることがあります。
タイムスタンプと日付文字列の使い分け
瞬間(イベントが起きた時刻、トークンの有効期限など)は、Unix タイムスタンプか UTC の日付文字列で保存しましょう。どちらもあいまいさがなく、正しく並べ替えられます。
人が読むログ、API、ファイルでは、2026-10-14T09:30:00Z のような読みやすい ISO 8601 の文字列を使いましょう。1791970200 を見ても一目では何もわからないからです。来春のパリでの 9 時の会議のような将来のローカルな予定は、ローカル時刻と IANA のタイムゾーン名で保存しましょう。その日が来る前に夏時間のルールが変わることがあり、事前に計算したタイムスタンプは間違いになってしまいます。
よくある質問
Unix タイムスタンプは常に UTC ですか?
はい。1970年1月1日 0 時 UTC から数えると定義されているので、数値そのものにタイムゾーンはありません。タイムゾーンが関わるのは、読みやすいローカル時刻に変換するときだけです。
現在の Unix タイムスタンプを取得するには?
Linux や macOS のターミナルで date +%s、JavaScript で Math.floor(Date.now() / 1000)、Python で int(time.time()) を実行します。いずれもエポックからの秒数を返します。
タイムスタンプを変換すると1970年の日付になるのはなぜですか?
値はほぼ確実に秒単位なのに、ミリ秒として読まれています。JavaScript の new Date() のようにミリ秒を受け取る関数に渡す前に、1,000 を掛けましょう。
Unix タイムスタンプは負の値になりますか?
はい。負の値はエポックからさかのぼって数えるので、-86400 は1969年12月31日 0 時 UTC です。負の値を受け付けない古いシステムもあるので、1970年より前の日付をこの方法で保存する前にテストしましょう。