RFC 3339とISO 8601の比較
(ijmacd.github.io)- 日付・時刻表記を扱う際、RFC 3339 は Web・インターネットで使いやすい狭い部分集合に近く、ISO 8601-1:2019 ははるかに広い形式集合を含む
- 比較範囲は ISO 8601-1:2019 に限定され、ISO 8601-2:2019 の季節、集合、不確実性修飾、日付演算のような追加表現は表にまだ反映されていない
- 両標準は
2026-06-26、14:08:00Z、2026-06-26T14:08:00Z、+00:00オフセットのような広く使われる 基本的な日付・時刻形式 を共に扱う - ISO 8601 は世紀・十年・通算日・週日付、短縮時刻、カンマ小数点、期間(
P1Y)と範囲(2026-06-26/P1Y)まで包含するが、RFC 3339 では表の大半が除外される - Date-Time 表記では
T区切り文字 と大文字小文字、-00:00オフセットのような差異が実際のパーサ互換性を分けるポイントになる
比較範囲と前提
- 形式表は 完全な一覧ではない
- 対象標準は ISO 8601-1:2019
- 以前の版と草案には重要な差異がある
- ISO 8601-2:2019 は追加表現を含むが、このページにはまだ反映されていない
- 下位年グループ、たとえば季節
- グループ化単位
- 集合
- 不確実性修飾
- 日付演算
- RFC 3339 は下位標準で
Tを別の文字に置き換えられると提案しているが、例としては 空白文字 しか示していない - 各標準は目的別の形式を定義しており、それ以外の形式は推奨されない
日付表記では ISO 8601 のほうが広い
- RFC 3339 と ISO 8601 はどちらも
2026-06-26のような 年-月-日の日付 をサポートする - ISO 8601 は RFC 3339 より多様な日付表現を扱う
- 世紀:
20 - 十年:
202 - 年:
2026 - 年月:
2026-06 - 通算日:
2026-177 - 週日付:
2026-W26,2026-W26-5 - 基本形式:
20260626,2026177,2026W26,2026W265
- 世紀:
- 表では RFC 3339 は上記の ISO 専用日付形式を許可していない
時刻表記の違い
- 両標準は
14:08:00Z、14:08:00+00:00、14:08:00.372+00:00のような 秒単位の時刻とタイムゾーンオフセット を共に許可する - RFC 3339 は大文字小文字を区別しないため、
TとZをそれぞれt、zと書ける- 以前の ISO 8601 版も大文字小文字を区別しなかった
- ISO 8601 では最小の時間値に 小数部 を付けられる
- 表では主に小数1桁の例が示されているが、標準では任意精度を許可する
- 小数区切りとしてカンマとピリオドの両方を許可し、すべての形式で相互に置き換え可能
- ISO 8601-1:2019 は曖昧でない場合、時刻単独表現 で
Tの省略を許可する - ISO 8601 は
14、14:08、14:08:00、140800、T14:08:00、14:08:00,372のような短縮・基本・カンマ小数の時刻表現をサポートする - RFC 3339 は
14:08:00-00:00のような-00:00オフセット を許可するが、表では ISO 8601 はこれを許可していない
Date-Time における T と区切り文字
- RFC 3339 と ISO 8601 はどちらも
2026-06-26T14:08:00Zや2026-06-26T14:08:00+00:00のような Date-Time を許可する - ISO 8601 の Date-Time 表現 では
Tが常に必要- 以前の版では Date-Time での
T省略も許可されていた - 以前の版でも空白やアンダースコアのような代替文字の挿入は許可されていなかった
- 以前の版では Date-Time での
- 表では RFC 3339 は次の Date-Time 変種を許可する
- 小文字
tとz:2026-06-26t14:08:00z - 空白区切り:
2026-06-26 14:08:00Z - アンダースコア区切り:
2026-06-26_14:08:00Z -00:00オフセット:2026-06-26T14:08:00-00:00
- 小文字
- ISO 8601 は
2026-06-26T14、2026-06-26T14:08、2026-06-26T14:08:00、2026-177T14:08、2026-W26-5T14:08のような 短縮 Date-Time と通算日・週日付ベースの Date-Time を扱う
期間と範囲は ISO 8601 中心
- 表では 期間(Periods) 形式は ISO 8601 にのみチェックが付いている
- 例:
P1Y,P1M,P1W,P1D - 時間を含む例:
PT1H,PT1M,PT1S - 組み合わせ例:
P1Y1M1DT1H1M1S - 小数例:
P1.5Y,P1,5W,PT1.5S
- 例:
- 範囲(Ranges) 形式も ISO 8601 にのみチェックが付いている
- 日付と期間:
2026-06-26/P1Y - 日付と日付:
2026-06-26/2026-06-26 - 期間と日付:
P1Y/2026-06-26 - Date-Time と期間:
2026-06-26T14:08/P1DT1H - 反復範囲:
R/2026-06-26/P1Y,R10/2026-06-26/P1Y
- 日付と期間:
形式キーとテストツール
- 形式表は
%Y、%M、%D、%h、%m、%sのような 形式キー を使用する%Y: Year%M: Month%D: Day%V: Week Year%W: Week%w: Week Day%O: Ordinal Day%h: Hour%m: Minute%s: Second%u: Microsecond%n: Nanosecond%Z:+または-を含むタイムゾーン時%z: タイムゾーン分
- 形式チェッカーは入力形式が表内の形式に該当するかどうかだけを確認する
- すべての可能な形式を検査するわけではない
- ISO 8601 as a Service はベータテスト用サービス
- 現在は Date、Time、DateTime のみサポート
- Period と Range はサポートしない
- ソースは GitHub で公開されている
1件のコメント
Hacker News のコメント
特定のタイムゾーンに基づく将来の日付/時刻を指定する方法がないのは奇妙です。たとえば、2030年7月1日のロンドン現地時間午後6時に会議を設定したい場合があり、その間に英国のタイムゾーン規則がどう変わっても「ロンドンの午後6時」のままであるべきです
英国は現在、おおむね11〜3月は Z+00:00、4〜10月は夏時間 Z+01:00 を使っていますが[0]、2030年までに中央ヨーロッパ時間[1]を採用したり、British Double Summer Time[2]を再び試したり、夏時間を廃止したりする可能性もあります。そのため、同じ「午後6時」が特定の epoch 基準では大きく変わり得ます
カレンダーイベントに「その時点のロンドン時間で午後6時」を入れたいのに、2030-07-01 18:00:00 Europe/London を標準的で相互運用可能な方法で表現する手段がありません
[0] https://en.wikipedia.org/wiki/British_Summer_Time
[1] https://en.wikipedia.org/wiki/Central_European_Time
[2] https://en.wikipedia.org/wiki/British_Summer_Time#Periods_of...
tz名としてタイムゾーンを付けられ、現地時刻を表現するには UTC オフセットの推定値も併記する必要がありますたとえば
2030-07-01 18:00:00 Europe/Londonは2030-07-01T18:00:00+01:00[Europe/London]になります。その前に英国の規則が変わるとタイムスタンプは「不一致」となり、アプリケーションが処理方法を決めます。ただし、角括弧内のタイムゾーン名の前に!を入れると、UTC オフセットに盲目的に従わず、問題を検出しなければなりませんこの拡張タイムスタンプ形式は、JavaScript の提案中の Temporal ライブラリ[1]でも使われており、
ZonedDateTime.from()のパース関数[2]では、不一致のタイムスタンプでどちらを優先するかをoffsetオプションで制御できます。UTC オフセットを省略してタイムゾーンだけを書くこともサポートしていますが、夏時間の切り替え時に繰り返される1時間の区間は曖昧だと警告しています[0] https://www.ietf.org/archive/id/draft-ietf-sedate-datetime-e...
[1] https://tc39.es/proposal-temporal/docs/strings.html#iana-tim...
[2] https://tc39.es/proposal-temporal/docs/ambiguity.html#ambigu...
しかしその間にスコットランドが独立住民投票を再び行い、中央ヨーロッパ時間に加わったり、Scottish Standard Time を作ったりする可能性も想像不可能ではありません
2023-11-05 01:30:00 America/New_Yorkは、異なる2つの時刻のどちらかになりますカレンダーでは「壁時計上の同じ時刻」がたいてい意図する意味なので妥当ですが、奇妙な時刻を処理する UI 上の難しさがあり、構文に曖昧性を解消する方法を入れたくなるかもしれません。通常このような切り替えは真夜中なので幸いですが、実務でこうした事例を見たことがあります
夏時間のないタイムゾーンの人を招待すると、その人のカレンダー上では時刻が揺れ、海外の同僚がそれを受け入れなければならない場合があります
[0]: https://www.rfc-editor.org/rfc/rfc5545#section-3.3.5
一般的な日付時刻形式は特定の時点を表すために作られていますが、この場合にはそのような特定の時点はまだ存在しません。毎月最終金曜日の会議、1月31日に始まる月例会議、四半期末の2日前といったように、日付/時刻指定が自明でない構造を持つことはよくあります
人々が思いつくあらゆるケースを網羅する標準を作ろうとすると、すぐに複雑になりそうです。単純な日付、時刻、瞬間では足りないなら、必要な要素をすべて含む別の構造を作るしかなさそうです
ISOの仕様は無料で提供されていないため、通常はRFCに従うほうがよく、多くのオープンソース実装も草案ベースなので、完全にオープンソースフレンドリーとは言いにくい。オープンソース開発者にとっても大きな負担である
将来の日付を扱う何かを作るなら、ほぼ常に壁時計時刻 + 場所を保存したくなる。残念ながら、これに対する標準はない。ヨーロッパや米国ではタイムゾーンがかなり安定しているので実感しにくいかもしれないが、多くの地域ではタイムゾーンが頻繁に変わるため、オフセットを保存するのは安定しない
2026年6月5日 13:30 壁時計、パリが大多数の人の意図するところであり、EUが夏時間をどう扱うかによって UTC+2 かもしれないし UTC+1 かもしれない。過去の時刻を扱うAPIなら、単に秒、ミリ秒、マイクロ秒、ナノ秒単位のPOSIXタイムスタンプを使えばよいiCalも、場所が別のタイムゾーンに再割り当てされる問題までは考慮していない。また、正しいiCalファイルは参照するすべてのタイムゾーンデータを含むため、単一の日時を1つ出力したいだけの場合には面倒である
[1] https://icalendar.org/iCalendar-RFC-5545/3-3-5-date-time.htm...
2026-06-05T13:30+0200[Europe/Paris]https://www.ietf.org/archive/id/draft-ietf-sedate-datetime-e...
標準でしばしば無視される部分が期間の表現である
http://xml.coverpages.org/ISO-FDIS-8601.pdfの5.5.4.2 “Representation of time-interval by duration only”、21ページを見ればよい。静的言語のJSONパーサがフィールドを期間として定義し、有効な形式でシリアライズできるようにしてくれるとよい
Crystalの提案例はここにある: https://github.com/crystal-lang/crystal/issues/11942
たとえば15日5時間20秒は
P15DT5H0M20S、7週間はP7Wになるduration定義を参照してもよいたとえば
"duration": { "days": 15, "hours": 5, "seconds": 20 }のように書けば、JSONパーサがデータの意味を理解する必要はなく、入力バリデータに任せればよい。いずれにせよ、JSONがこのデータをどのように表現するにしても、失敗しうる変換ステップは必要であるRFC 3339とISO 8601は目的が重なる冗長な日時形式を多数含んでいる一方で、あらゆるシステムで最もよく使われ、あまりにも明白な
2023-09-01 15:30:59はどちらにも含まれていないのが「おかしい」また、両標準とも紀元前の日付や
9999-12-31以降、または-9999-01-01以前の日付をどう表現するかが非常に不明確で、一般的なライブラリはたいていまったく扱えない。扱えたとしても、00-01-01の動作は実質的に未定義に近いグレゴリオ暦は紀元前1年の次の年が紀元1年なので奇妙で、専門的な天文ソフトウェアを除けば、ほとんどすべてのソフトウェアは近い将来のUnix時間の範囲外を正しく扱えない。アウグストゥス帝の生没年のように文字列として保存するだけで十分なものについても、標準で明確に定義してくれればよい
Tを空白に置き換えられるISO 8601、という単純な限定を付ければよいだけである。RFC 3339も、ずっと冗長なやり方で同様のことをしている2023-09-01 15:30:59が最もよく使われる日時形式なのかも断言しにくい。最も多く使われている言語は中国語であり、2023年9月1日のような固有の区切り文字が一般的であるISO 8601は相互合意があれば1582年以前や9999年以後の年も許容する。4桁に収まらない場合は、先頭に単一の符号文字を付ける必要がある。このような日付で意味のあることができる場面は少ないため一般にはサポートされないが、特にCとは独立に実装されたライブラリでは、パースする例をかなり見かける
00-01-01は紀元前1年1月1日として定義されている。ISO 8601は年番号が先発グレゴリオ暦(proleptic Gregorian calendar)に従うことを明確にしているため、負の無限大まで外挿される空白以外の文字が必要だった理由はわかるが、少なくともアンダースコアやピリオドを使うこともできたはずだ。そして文字列なのに年の範囲を4桁に制限し、形式の普遍性を犠牲にした理由もわからない
6桁の年は、将来志向に見せるための、実際には起こらない問題への解決策のように感じる。現在の技術や社会規範が8000年も続くはずがない
ISO 8601 が U+2010 HYPHEN と U+2212 MINUS を使い、該当する文字がない文字集合では U+2D HYPHEN-MINUS を使うべきだという説明は誤り
実際の ISO 8601 は、対象の文字集合が ISO/IEC 646 ベースであれば、どちらの場合もハイフンマイナス文字を使うべきだと明記している。これには Unicode が確実に含まれる。多少の曖昧さはあるが、Unicode では解釈は明確で、646 の正規マッピングを指定して 646 ベースの他の文字集合との互換性を保証しようとする迂回的な方法に見える
「日付と時刻の表現に使われるすべての文字は、‘hyphen’, ‘minus’, ‘plus-minus’ を除けば ISO/IEC 646 のレパートリに属する。ISO/IEC 646 ベースの文字レパートリを使う環境では、‘hyphen’ と ‘minus’ はどちらも ‘hyphen-minus’ にマッピングしなければならない」という内容
Unicode は ISO 8859 ベースで、ISO 8859 は ISO 646 ベースなので、Unicode 文字集合では U+2D hyphen-minus を使わせる意図で合っているように見える
Windows ではコロンが特殊文字なので、ファイル名に日付と時刻を入れるときに RFC 3339 に合う方法がない点がよく気になる
日付にはハイフンを使いつつ、コロンは省略しても ISO 8601 準拠にできるとよい。たとえば
20230831T1510-0500は準拠していてファイル名に使えるが、2023-08-31T1510-0500や類似の変形はそうではない。付け加えると、PowerShell のGet-Date関数は、ハイフンもコロンもない最初のタイムスタンプを理解できないこのテーマについて非常によい可視化
日付部分と時刻部分を区切るときは
Tの代わりに空白やアンダースコアを好むが、ISO 8601 だけを処理するものとの問題を避け、一貫性のためにたいていTを使い続けているTを好む。こういう文字列を偶然Tを基準に分割することはないだろうから2 つ気になる。第一に、6 桁の年の根拠は何なのか?今考案したどんなシステムも 100,000 年後に存在するはずがないのでは
第二に、ISO 8601 は広く普及しているが、RFC 3339 も実際のシステムで多く使われ、採用されているのか?
timeパッケージと Rust のChronoには RFC 3339 を扱う組み込みツールがあるが、RFC 8601 用はない記憶では RFC 8601 には RFC 3339 にはない曖昧性の問題があり、Python もこのために日付の往復変換で問題があったと認識している
タイムゾーンがコロンなしの 4 桁で指定される形式はないのに、
date +%zは±NNNNを返す%:zがある。関連して、dateがデフォルトでこのように出力するよう教えることもできる: https://gist.github.com/d081dad407432d53172e30d0d35c39db$ date2023-08-31T11:15:00-07:00±NNNNは「基本形式」の一部として使われるなら、コロンなしでも有効。つまり形式全体のどこにもハイフンやコロンがあってはならないしたがって次の 2 つは同等で、どちらも有効:
2023-09-01T09:40:01+08:0020230901T094001+0800