ぱんだツールズぱんだツールズ

技術背景

日時フォーマット完全ガイド — ISO 8601・strftime・YYYY-MM-DDの使い分け

約6分

CSVをインポートしようとしたら「日付形式が不正です」と弾かれた——ファイルを見ると2026/4/212026-04-2121/4/2026が 混在していた。そんな経験はないでしょうか。日時フォーマットは地域・言語・システムによってバラバラで、 整えずに扱うと高確率でバグの温床になります。この記事では、国際標準のISO 8601から各言語の書式指定子、 タイムゾーン・ロケールでのハマりどころまで、横断的に整理します。

ISO 8601 — 世界標準の日時表記

ISO 8601(International Organization for Standardization 8601)は、日付と時刻を国際標準として 定めた規格です。基本形式は「YYYY-MM-DDTHH:mm:ss±HH:mm」で、 日付と時刻を「T」で区切り、末尾にタイムゾーンオフセットを付けます。

# ISO 8601 の代表的な表記例

2026-04-21 # 日付のみ

2026-04-21T12:34:56Z # UTC(Zが付く)

2026-04-21T21:34:56+09:00 # JST(+09:00 オフセット)

2026-04-21T12:34:56.789Z # ミリ秒付きUTC

ISO 8601の最大の利点は文字列として辞書順にソートしても時系列順になることです。2026-04-212026-04-22は 文字列比較でも前者の方が「小さい」と判定されます。 一方「21/04/2026」のような形式では、文字列ソートすると月や年で順序が崩れるためログやDBで扱いにくくなります。

strftime系のフォーマット指定子早見表

C言語のstrftime関数に由来する書式指定子は、Python・PHP・Ruby・Goの一部など多くの言語で使われています。 主要な指定子を押さえておくと言語を横断して日時処理ができます。

指定子意味例(2026-04-21 09:05:07 JST)
%Y4桁の年2026
%y2桁の年(下2桁)26
%m月(2桁ゼロ埋め)04
%d日(2桁ゼロ埋め)21
%H時(24時間制・2桁)09
%I時(12時間制・2桁)09
%M分(2桁ゼロ埋め)05
%S秒(2桁ゼロ埋め)07
%A曜日名(ロケール依存)Tuesday / 火曜日
%a曜日名の略Tue / 火
%Zタイムゾーン名JST
%zタイムゾーンオフセット+0900

なお、Pythonの「%f」はマイクロ秒(6桁)、PHPの「u」もマイクロ秒です。 ミリ秒を3桁で欲しい場合はアプリ側での加工が必要になります。 各言語の個別フォーマットは日時フォーマット横断検索ツールで一覧比較できます。

言語・プラットフォーム別のフォーマット指定

「同じ年月日を出したいだけなのに書式指定子が違う」という現象は日常茶飯事です。 代表的な環境での指定方法を比較表にまとめます。

環境「2026-04-21 12:34:56」を出す書式備考
JavaScript(toISOString)date.toISOString()常にUTC・ミリ秒付き
JavaScript(Intl)Intl.DateTimeFormat('ja-JP')ロケール依存・柔軟
Pythonstrftime('%Y-%m-%d %H:%M:%S')strftime系
GoFormat("2006-01-02 15:04:05")Reference Time方式(独自)
Java(DateTimeFormatter)"yyyy-MM-dd HH:mm:ss"「MM」が月・「mm」は分
C#(.NET)"yyyy-MM-dd HH:mm:ss"Javaとほぼ同じ
Excel(セル書式)yyyy/mm/dd hh:mm:ss全て小文字・独自仕様

JavaScript

// ISO 8601(UTC・最もシンプル)

new Date().toISOString() // "2026-04-21T12:34:56.789Z"

// ロケール指定で日本語フォーマット

new Intl.DateTimeFormat('ja-JP', {

year: 'numeric', month: '2-digit', day: '2-digit'

}).format(new Date()) // "2026/04/21"

Python

# strftime で書式指定

from datetime import datetime

datetime.now().strftime('%Y-%m-%d %H:%M:%S')

# ISO 8601 形式(ミリ秒付き)

datetime.now().isoformat() # "2026-04-21T12:34:56.789123"

Go — Reference Timeという独自方式

Goは他の言語と大きく異なり、「2006-01-02 15:04:05」という特定の日時をリファレンスとして書式を指定します。覚え方は「1・2・3・4・5・6」の順に「1月・2日・15時(=3PM)・4分・5秒・2006年」と並んでいることです。

// Go - Reference Timeを使ったフォーマット

t.Format("2006-01-02 15:04:05") // "2026-04-21 12:34:56"

ロケール依存フォーマットの罠

同じ「date」コマンドや言語標準のフォーマッタでも、OSのロケール設定によって出力が変わる場合があります。これが原因で本番環境と開発環境で挙動が違うという事故が起きやすいです。

ロケール短縮日付(例)読み方
en-US(アメリカ)4/21/2026月/日/年
en-GB(イギリス)21/04/2026日/月/年
ja-JP(日本)2026/04/21年/月/日
de-DE(ドイツ)21.04.2026日.月.年

特に「4/21/2026」と「21/4/2026」は、月と日が共に12以下の日付では区別がつかないため深刻です。ログやデータ交換では必ずISO 8601を使い、ロケール依存フォーマットは表示直前だけに留めるのが鉄則です。

タイムゾーンの落とし穴

日時を扱う最大の難関がタイムゾーンです。同じ瞬間でも見る場所によって時刻が異なるため、 「いつ・どのゾーンで保存し、いつ・どこで変換するか」を明確に決めないと容易にバグります。

UTC・JST・ローカルタイム

UTC(Coordinated Universal Time、協定世界時)は世界共通の基準時刻で、タイムゾーンを持ちません。 JST(Japan Standard Time)はUTC+9時間で、日本国内でのみ使われます。 「ローカルタイム」はプログラムが動作している環境のOS設定に従った時刻で、 サーバーの設定次第でUTCだったりJSTだったりします。

よくあるバグ

ローカル環境(JST)では「今日」として保存したのに、本番サーバー(UTC)では「昨日」になっていた—— これはDateオブジェクトを作る際にタイムゾーンを指定しなかったことが原因です。 保存時は必ずUTCに正規化し、表示時にIANA(Internet Assigned Numbers Authority)タイムゾーン名(例: Asia/Tokyo)で変換しましょう。

Date.parse の環境差

JavaScriptのDate.parse()new Date(string)は、 ISO 8601以外の形式では環境依存の挙動をします。たとえばnew Date('2026-04-21')は UTCの00:00として解釈されますが、new Date('2026/04/21')は ローカルタイムの00:00として解釈されます(たった1文字「-」か「/」かの違いで挙動が変わります)。

この挙動の違いは日本のブラウザで「9時間ずれて表示される」バグの主因です。 パースは常にISO形式を使うか、date-fnsやLuxon・day.jsなどのライブラリに任せるのが安全です。

2桁年問題 — Y2KとY2K38

日時フォーマットで2桁年(%y / yy)を使うのは、表示目的でない限り避けるべきです。 歴史的に2つの有名な年問題があり、いずれも2桁年表現・整数型の上限が原因でした。

通称発生時期原因
2000年問題(Y2K)1999→20002桁年「99」→「00」で年度計算が破綻
2038年問題(Y2K38)2038-01-19 03:14:07 UTC32bit符号付き整数のUNIXタイムスタンプがオーバーフロー

2038年問題の詳細とオーバーフロー後の挙動についてはUNIXタイムスタンプ変換ツールのページで実際の変換を試しながら確認できます。 日時を整数で扱うときは必ず64bit整数を使うのが現代の標準です。

UNIXタイムスタンプとISO形式の使い分け

日時を機械的に扱う場面では、UNIXタイムスタンプ(秒またはミリ秒の整数)とISO 8601文字列のどちらを使うかで迷います。 それぞれの得意領域を整理しておくと選択が楽になります。

  • UNIXタイムスタンプ: 計算(差分・加算)・ソート・DB保存のプリミティブとして最適
  • ISO 8601: 人が目視で確認可能・APIやログでの可読性に優れる
  • 実装上はDBにUTCで保存(timestamptzまたはBIGINT)し、APIレスポンスはISO 8601で返す組み合わせが定番

日付だけの計算(今から30日後など)を気軽に試したい場合は日付計算ツールが便利です。ブラウザ上で即座に結果が出るため、API設計時の動作確認に使えます。

まとめ

  • 機械可読な日時表現はISO 8601(YYYY-MM-DDTHH:mm:ss±HH:mm)で統一する
  • strftime系(%Y・%m・%d)とExcel書式(yyyy・mm・dd)は別物。大文字小文字を混同しない
  • GoのみReference Time(2006-01-02 15:04:05)という独自方式
  • ロケール依存フォーマット(4/21/2026 vs 21/4/2026)は表示直前だけに留める
  • DB保存はUTC、表示時にIANAタイムゾーン名(Asia/Tokyo等)で変換するのが鉄則
  • new Date('2026/4/21')のようなスラッシュ区切りパースは環境依存で危険
  • 2桁年・32bit整数の使用はY2K・Y2K38の再現を招くため避ける
  • 各言語のフォーマット指定子は日時フォーマット横断検索で横断比較できる

よくある質問

ISO 8601で推奨される日時フォーマットは?

完全形式は「YYYY-MM-DDTHH:mm:ss.sssZ」です。たとえば「2026-04-21T12:34:56.789Z」のように、日付と時刻を「T」で区切り、末尾に「Z」(=UTCを示す記号。Zulu Timeの略)またはオフセット(例: +09:00)を付けます。ミリ秒部分は任意ですが、APIレスポンスやログでは含めておくと順序保証やデバッグで有利です。JavaScriptのDate.prototype.toISOString()が返す形式がこの標準形です。

JavaScriptで「new Date('2026/4/21')」と書いていますが問題ありますか?

主要ブラウザでは動作しますが、ECMAScript仕様では保証されていない「実装依存の挙動」です。Safariの一部バージョンや古いブラウザではInvalid Dateになることがあります。ISO 8601形式の「new Date('2026-04-21')」や「new Date('2026-04-21T00:00:00+09:00')」を使うのが安全です。日付文字列をパースする際は、できるだけISO形式に正規化してからDateに渡しましょう。

Excelの日付書式「yyyy/mm/dd」はなぜ小文字なのですか?

Excelのセル書式は独自仕様で、年は「yyyy」・月は「mm」・日は「dd」と小文字で書きます。一方、strftime系(Python・C言語など)は「%Y/%m/%d」と大文字のYを使います。さらに「mm」はExcelでは月と分の両方に使われ、時刻コンテキスト(「hh:mm」など時刻と並ぶ位置)では分として解釈される点にも注意してください。Excel書式とstrftime書式は別物として区別して覚えるのが安全です。

日本の元号(令和)を日時フォーマットで扱うには?

JavaScriptではIntl.DateTimeFormat('ja-JP-u-ca-japanese', { era: 'long', year: 'numeric' })で「令和8年」のように出力できます。Javaの場合はDateTimeFormatterに「japanese」カレンダーを指定します。ただし内部的にはグレゴリオ暦で保持し、表示時のみ元号に変換する運用が鉄則です。元号は改元時に過去データの解釈が変わるため、DB保存は必ずISO形式のグレゴリオ暦で行いましょう。

タイムゾーン指定で「JST」と「+09:00」はどう違いますか?

「+09:00」は固定オフセットで曖昧さがありません。一方「JST」は略称で、実は世界に同名のゾーンが複数あり(Japan Standard Time以外にも過去にJordan Standard Timeなど)、パース時の環境差で解釈が揺れます。より厳密には「Asia/Tokyo」のようにIANAタイムゾーン名を使うと、夏時間や過去の時刻修正まで含めて正確に扱えます。DB保存はUTC(+00:00 or Z)、表示時にIANA名で変換するのが定石です。

ミリ秒を含めたい場合のフォーマットは?

strftime系には標準ではミリ秒指定子がなく、Pythonでは「%f」がマイクロ秒(6桁)として使われます。ミリ秒3桁が欲しい場合はdatetime.strftime('%Y-%m-%dT%H:%M:%S.') + f'{dt.microsecond // 1000:03d}'のように加工するのが一般的です。JavaやC#では「SSS」(大文字S 3つ)でミリ秒を表現します。JavaScriptのtoISOString()は自動で「.sss」が付くので、そのまま使うのが最も簡単です。

データベースで日付を保存するときの推奨形式は?

鉄則は「UTCで保存し、表示時にローカルタイムへ変換」です。MySQLなら「DATETIME型でUTC値を入れる」か「TIMESTAMP型(自動でUTC保存・セッションTZで変換)」を使います。PostgreSQLは「TIMESTAMP WITH TIME ZONE」(timestamptz)が推奨で、これは内部でUTC保存+セッションTZ表示を自動でやってくれます。タイムゾーン情報を文字列で持つとサマータイム切替や国際化対応でバグの温床になります。

曜日を日本語(月・火・水…)で出力するには?

JavaScriptならnew Intl.DateTimeFormat('ja-JP', { weekday: 'short' }).format(date)で「月」「火」のような1文字表記が得られます。「long」を指定すると「月曜日」です。Pythonはロケール設定+strftime('%A')が使えますが、環境依存で不安定なため、自前の配列(例: ['月', '火', '水', '木', '金', '土', '日'])を使ってdatetime.weekday()のインデックス(月=0〜日=6)で引く方が堅牢です。

ぱんだツールズに入力した日時データはサーバーに送信されますか?

送信されません。日時フォーマット横断検索(/tools/datetime-format-search)・UNIXタイムスタンプ変換(/tools/unix-timestamp)・日付計算(/tools/date-calculator)はいずれも、処理をすべてブラウザ内のJavaScriptで完結させています。入力値がサーバーに送られたり、ログに保存されたりすることはありません。社外の予定データや本番ログのタイムスタンプ整形にも安心して使えます。

この記事で紹介したツール