APIのレスポンスに "created_at": 1713657600 という数字が返ってきて、 「これいつのこと?」と感じた経験はありませんか。このような数値がUNIXタイムスタンプです。 プログラムで日時を扱う際の共通フォーマットとして世界中で使われていますが、 ミリ秒と秒の違いやタイムゾーンの関係で混乱しやすい落とし穴も多くあります。 この記事では仕組みから実践的な使い方・よくある失敗まで、具体的なコード例とともに解説します。
UNIXタイムスタンプとは
UNIXタイムスタンプ(UNIX timestamp)とは、1970年1月1日0時0分0秒(UTC)を起点として、 そこからの経過秒数を整数で表現した値です。この起点のことをエポック(epoch)、 またはUNIX時間の原点と呼びます。
なぜ1970年1月1日が起点になったのでしょうか。UNIXオペレーティングシステムは1969〜1970年頃に開発されており、 設計当時の「近い過去」として1970年1月1日がエポックとして選ばれました。 特別な技術的理由があるわけではなく、設計者の判断による取り決めです。 その後、UNIX系OSが世界標準となったことで、このエポックが事実上のグローバルスタンダードになりました。
たとえば 1713657600 というタイムスタンプは、 エポックから1713657600秒後——つまり2024年4月21日00:00:00 UTCを意味します。 文字列で日時を扱うと「2024/04/21」「April 21, 2024」のようにフォーマットが国やシステムによって異なりますが、 タイムスタンプは単なる整数なのでフォーマットの揺れが一切起きません。 これがコンピューターシステムでUNIXタイムスタンプが広く採用されている最大の理由です。
秒 vs ミリ秒の違いと使い分け
UNIXタイムスタンプには「秒単位」と「ミリ秒単位」の2種類があり、これが混乱の最大の原因です。
| 単位 | 2024-04-21 00:00:00 UTCの値 | 主な用途 |
|---|---|---|
| 秒(s) | 1713657600 | UNIX本来の形式、C言語、Python、shell、多くのAPIレスポンス |
| ミリ秒(ms) | 1713657600000 | JavaScript、ブラウザAPI、Javaの一部 |
JavaScriptではミリ秒が標準です。Date.now()やnew Date().getTime()はどちらもミリ秒を返します。 秒単位に変換するには1000で割る必要があります。
// JavaScriptでのタイムスタンプ取得
Date.now() // ミリ秒(例: 1713657600000)
new Date().getTime() // ミリ秒(Date.now()と同じ)
// 秒単位に変換
Math.floor(Date.now() / 1000) // 秒(例: 1713657600)
逆に秒単位のタイムスタンプをJavaScriptのDateに変換する場合は、1000倍してからDateコンストラクタに渡す必要があります。 1000倍を忘れると、1970年1月の日時として解釈されてしまいます。
// 秒タイムスタンプ → Date(1000倍が必要)
new Date(1713657600 * 1000) // 2024-04-21
// 1000倍を忘れた場合(バグ)
new Date(1713657600) // 1970-01-20(誤り)
タイムゾーンとUNIXタイムスタンプの関係
UNIXタイムスタンプ自体はタイムゾーンを含まない絶対的な値です。 世界中のどのコンピューターで同じ瞬間を計測しても、まったく同じ数値になります。 日本(JST = UTC+9)にいようと、ニューヨーク(EST = UTC-5)にいようと関係ありません。
タイムゾーンが必要になるのは、タイムスタンプを「人間が読める日時文字列」に変換する段階です。 同じタイムスタンプ 1713657600 を変換すると:
- UTC: 2024-04-21 00:00:00
- JST(UTC+9): 2024-04-21 09:00:00
- EST(UTC-5): 2024-04-20 19:00:00
このため、APIの設計では「タイムスタンプで受け渡し、表示時にタイムゾーン変換する」パターンが推奨されます。 日時を文字列で渡すと変換前後のタイムゾーンの食い違いによるバグが発生しやすいですが、 タイムスタンプなら常に一意の瞬間を指すため安全です。
よくある落とし穴:2038年問題
2038年問題とは、32bit符号付き整数(int32)でタイムスタンプを格納しているシステムが、 2038年1月19日03:14:07 UTC(= 2147483647秒 = 2^31 − 1)を超えた瞬間にオーバーフローする問題です。 2^31 − 1の次の瞬間、値が負の最小値(−2147483648)に折り返し、 1901年12月13日の日時として誤って解釈されてしまいます。
現代のOS・プログラミング言語の多くは64bit整数を使用しており、 64bitで表現できる最大の日時は西暦2920億年以上先のため実質的に問題ありません。 しかし次のようなケースでは今も注意が必要です:
- 組み込みシステムや32bitマイコン上のプログラム
- 古いデータベースの
INT(11)(32bit)型カラム - C言語で
time_tを32bitとして扱う古いライブラリ - レガシーな基幹システムや金融系システム
言語別の変換コード例
| 言語 | 現在時刻をタイムスタンプ(秒)で取得 | タイムスタンプ → 日時に変換 |
|---|---|---|
| JavaScript | Math.floor(Date.now() / 1000) | new Date(ts * 1000) |
| Python | import time; time.time() | datetime.fromtimestamp(ts) |
| shell | date +%s | date -d @1713657600 |
JavaScript
// 現在時刻(ミリ秒)
Date.now() // 例: 1713657600000
// 現在時刻(秒)
Math.floor(Date.now() / 1000) // 例: 1713657600
// 秒タイムスタンプ → Dateオブジェクト
new Date(1713657600 * 1000).toISOString() // "2024-04-21T00:00:00.000Z"
Python
# 現在時刻(秒, float)
import time; time.time() # 例: 1713657600.123
# タイムスタンプ → datetimeオブジェクト(ローカルタイム)
from datetime import datetime; datetime.fromtimestamp(1713657600)
# タイムスタンプ → datetimeオブジェクト(UTC)
datetime.utcfromtimestamp(1713657600)
shell(bash / zsh)
# 現在時刻(秒)
date +%s
# タイムスタンプ → 日時文字列(Linux)
date -d @1713657600
# タイムスタンプ → 日時文字列(macOS)
date -r 1713657600
UNIXタイムスタンプ変換ツールの使い方
APIのデバッグ時など「この数値はいつ?」とすぐに確認したい場面では、UNIXタイムスタンプ変換ツールが便利です。コピーした数値を貼り付けるだけで、秒・ミリ秒どちらの形式でも自動判別して日時を表示します。
また、日付計算(今から30日後・特定日までの残り日数)が必要な場合は日付計算ツールも合わせて活用してください。どちらもサーバーへのデータ送信は一切なく、ブラウザ内で完結して動作します。
まとめ
- UNIXタイムスタンプは1970-01-01 00:00:00 UTC(エポック)からの経過秒数を整数で表した値
- JavaScriptはミリ秒が標準。秒に変換するには1000で割り、日時に戻すには1000倍してDateに渡す
- タイムスタンプ自体にタイムゾーンは含まれない。変換時に初めてタイムゾーンが必要になる
- 2038年問題は32bit整数の上限(2147483647 = 2^31-1)のオーバーフロー。現代の64bitシステムは影響なし
- 負のタイムスタンプは1970年より前の日時を表す(JavaScript含む多くの環境で正しく扱える)
- ブラウザ上でのタイムスタンプ確認にはUNIXタイムスタンプ変換ツールが便利