📡

ISO 8601: Date and Time API の基礎知識

24 min read

今回は、Java SE の Date and Time API の礎となっている ISO 8601 規格についてご紹介します。ISO 8601 の知識があると、クラス数からは複雑そうに感じる Date and Time API も容易に理解できるようになります。Date and Time API を習得する上でも、システム間連携で日付・時刻のやり取りをする場合にも ISO 8601 の知識は必須となってきますので、ぜひ基本事項を押さえておいてください。

1. ISO 8601 とは?

ISO 8601 は "Data elements and interchange formats--Information interchange--Representation of dates and times" (和訳: 情報交換のためのデータ要素及び交換方式ー日付及び時刻の表記) というタイトルが表すように、コンピュータ間で日付と時刻の送受信を行うためのフォーマットを規定する規格です。ISO 8601 以前にも日付と時刻の表現を定めた規格は複数存在していましたが、ISO 8601 はそれらを統合した規格となっています。現行版は第 3 版にあたる ISO 8601:2004 です。

日本工業規格 (JIS) では、ISO 8601 の邦訳に日本独自の「元号」に関する記述を付加した JIS X 0301 (現行版は JIS X 0301:2002 および JIS X 0301:2019) を規格化しています。記述のほとんどは ISO 8601 そのものであり、また原文との差分も明確に表現しているため、JIS X 0301 を ISO 8601 の実質的な邦訳と見なして問題ないでしょう。この記事の用語も JIS X 0301 の訳語を用います。

ISO 8601 は、西暦 = グレゴリオ暦 (Gregorian calendar) による年月日で表す日付、時刻および期間の表し方について規定するものです。具体的には以下のものについて規定します。

  1. 年月日を用いて表す日付 (暦日付; calendar date)
  2. 年および年日 (年初からの通算日) を用いて表す日付 (年間通算日; ordinal date)
  3. 年、週および週日 (曜日) を用いて表す日付 (暦週日付; week date)
  4. 1 日 24 時間制に基づいて表す時刻
  5. 日付と時刻の組み合わせ
  6. 地方時 (local time) と協定世界時 (UTC)
  7. 時間間隔 (period of time, time-interval)
  8. 反復時間間隔 (recurring time-interval)

また、上記規定に必要な各種用語や概念についても定義しています (一部は他の規格を参照する形となります)。

ISO 8601 はコンピュータが日付・時刻を扱うための規格であるため、私たちが日常使用している暦をベースとしながらも、電算処理上の合理性を満たすように設計されています。いくつかの例を以下に示します。

  • 日付の年月日の順序は、欧米では英国式の Day Month Year 順と米国式の Month Day Year 順があります。電算処理上は統一する必要があるため、日常表記と混ざらないように英国式・米国式のいずれでもない Year Month Day 順とし、区切り文字も日常的に使われるスペース (' ')、スラッシュ ('/')、ピリオド ('.')、カンマ (',') を避け、ハイフン ('-') としました[1]
  • 時刻の時分秒の順序は各国とも Hour Minute Second 順でブレがないためそのまま採用しています。ただし時刻は 24 時間制に統一しています。
  • 電算処理の都合上、区切り文字は省略可能とし、また日付の年月日、時刻の時分秒はそれぞれ桁数が固定となっています。日本においては '2014/3/21' のような表記が日常的に使用されますが、ISO 8601 では区切り文字ではなく桁数を基準に日付・時刻の要素 (フィールド) を抽出することに注意してください (ここは Date and Time API の format/parse で多くの人がハマるポイントでもあります)。

インターネットのタイムスタンプは、伝統的に RFC 2822 (旧 RFC 822) に則った形式が用いられていましたが、2002 年に ISO 8601 を簡略化した RFC 3339 が制定され、W3C XML Schema の DateTime 型などに採用されています。

2. 日付の表現

第 1 章で紹介した通り、ISO 8601 の日付表現には暦日付 (calendar date)、年間通算日 (ordinal date)、暦週日付 (week date) の 3 種類があります。

2.1. 暦日付 (calendar date)

書式 (拡張形式): YYYY-MM-DD (標準形式: YYYYMMDD)

  • 例 (拡張形式): 2014-03-21 (標準形式: 20140321)

ISO 8601 の日付・時刻表現には区切り文字を含まない「標準形式」と区切り文字を含む「拡張形式」があります。Date and Time API が文字列表現として採用しているのは原則として「拡張形式」です。

YYYY は年を表し、必ず数字 4 桁で、0000 ~ 9999 までの範囲となります。ただし、グレゴリオ暦が制定されたのが 1582 年 10 月であるため、0000 ~ 1582 は当事者間の合意がある場合のみ使用します (= 事前の取り決めがなければ使用してはいけません)。なお、0001 年は西暦 1 年を表すため、0000 年はその前年である紀元前 1 年を意味します。

MM は月を表し、必ず数字 2 桁で、01 ~ 12 までの範囲となります。DD は日を表し、必ず数字 2 桁です。日の最小値は 01 ですが、最大値は下表に示す通り月と閏年によって 28、29、30 または 31 のいずれかとなります。

Table 1. 月と日の対応

01 02 03 04 05 06 07 08 09 10 11 12
平年 31 28 31 30 31 30 31 31 30 31 30 31
閏年 31 29 31 30 31 30 31 31 30 31 30 31

閏年はグレゴリオ暦において 1 年が 366 日となる年をいい、閏年でない年を平年と呼びます。閏年の判定は下表に示すよく知られた方法があります。

Table 2. 平年と閏年の判定

年 mod 4 年 mod 100 年 mod 400 判定
0 以外 N/A N/A 平年
0 0 以外 N/A 閏年
0 0 0 以外 平年
0 0 0 閏年

余談ですが、グレゴリオ暦より以前に用いられていたユリウス暦にも閏年はありましたが、常に 4 年に 1 度設定され、グレゴリオ暦のように「100 年に一度は平年」「400 年に一度は閏年」といった補正はありませんでした。

ユリウス暦は細かな修正を行いながらも 1000 年以上の長きに渡って使用されてきましたが、ユリウス暦の春分の日と観測結果による春分の乖離が無視できない状況になってきました。春分はキリスト教において復活祭の日程を決める基準となるもので、この乖離はキリスト教としては許容できないものでした。そこで 16 世紀に当時のローマ教皇グレゴリウスの指示により、多数の天文学者を招聘してユリウス暦の徹底的な改修を実施し、その結果生まれたのがグレゴリオ暦です。グレゴリオ暦は 1582 年 10 月から施行されており、その直前にはユリウス暦からグレゴリオ暦に移行するための日付のスキップが行われています。なお、グレゴリオ暦の導入は国ごとに異なり、明治維新直後に真っ先に取り入れた日本のような国もあれば、イギリスのように後年になってから切り替えを行った国もあります。

Date and Time API では、閏年の判定に LocalDate.isLeapYear() メソッド、または Year.isLeap() メソッドを使用できます。

【補足】拡大表記

ISO 8601 では、年は必ず 4 桁固定となりますが、当事者間の合意があれば 4 桁よりも大きい桁数やマイナスの値を使用する「拡大表記」が認められています (ただし、桁数は固定する必要があります)。ただし、拡大表記を用いると他システム連携で問題が発生する場合があり得るため、可能な限り ISO 8601 の規定に従うことをお勧めします。

Date and Time API では拡大表記として、年を -999,999,999 ~ 999,999,999 の範囲で指定することが可能です。

2.2. 年間通算日 (ordinal date)

書式 (拡張形式): YYYY-DDD (標準形式: YYYYDDD)

  • 例 (拡張形式): 2014-080 (標準形式: 2014080)

YYYY は暦日付同様に年を表し、必ず数字 4 桁で、0000 ~ 9999 までの範囲となります。取り得る値に関する諸注意や拡大表記に関しても同じ規則が適用されます。

DDD は年初からの通し日となり、必ず数字 3 桁となります。範囲は年初日である 1 月 1 日が 001、年末日である 12 月 31 日が 365 (平年) または 366 (閏年) となります。

年間通算日では「月」は関係ありませんが、年初からの通し日と各月の日数から下表のような対応になります。

Table 3. 月と通し日の対応表

月数 月名 月内の日数 平年の通し日 閏年の通し日
01 1 月 (January) 01-31 001-031 001-031
02 2 月 (February) 01-28 (29) 032-059 032-060
03 3 月 (March) 01-31 060-090 061-091
04 4 月 (April) 01-30 091-120 092-121
05 5 月 (May) 01-31 121-151 122-152
06 6 月 (June) 01-30 152-181 153-182
07 7 月 (July) 01-31 182-212 183-213
08 8 月 (August) 01-31 213-243 214-244
09 9 月 (September) 01-30 244-273 245-273
10 10 月 (October) 01-31 274-304 275-305
11 11 月 (November) 01-30 305-334 306-335
12 12 月 (December) 01-31 335-365 336-366

ただし、

  • 月数は、暦日付における MM の定義域と一致する。
  • 月内の日数は、暦日付における DD の定義域と一致する。
  • 平年の通し日・閏年の通し日は、年間通算日における DDD の定義域と一致する。

さて、暦日付と年間通算日の判別ですが、原則としてフィールドおよび全体の桁数で行います。ISO 8601 は桁数を厳密に規定しているため、このやり方で日付文字列のパース時に暦日付と年間通算日を容易に判別することが可能です。

  • 暦日付: 年 4 桁 + 月 2 桁 + 日 2 桁 = 8 桁
  • 年間通算日: 年 4 桁 + 通し日 3 桁 = 7 桁

Date and Time API では、年間通算日を扱うのに、

の組み合わせを用います。

2.3. 暦週日付

書式 (拡張形式): YYYY-Www-D (標準形式: YYYYWwwD)

  • 例 (拡張形式): 2014-W12-5 (標準形式: YYYYW125)

日付の基本表現の 3 つ目は、その年の週と曜日により指定するものです。ww は 2 桁固定で、その年の何週目か (01 ~ 52/53) を表し、D は ww 週の曜日を表す通算日 1~7 となります。指示記号 'W' は暦日付や年間通算日との識別のため省略はできません。

ISO 8601 に置いては、曜日は以下のように定義されています。

Table 4. ISO 8601 における曜日の定義

通算日 1 2 3 4 5 6 7
曜日 月曜日 火曜日 水曜日 木曜日 金曜日 土曜日 日曜日

また、週と曜日については 4 つの取り決めごとがあります。

  • すべての週について、始まりは「月曜日」 である。
  • ある年の最初の週はその年の最初の木曜日を含む週である。
  • ある年の最後の週は、次の年の最初の週の 1 つ前の週である。
  • 2000 年 1 月 1 日は「土曜日」 と定める。

上記の取り決めから、週については次の定理が成り立ちます。

  • 1 年は 52 週または 53 週からなる。
  • ある年の 1 月 4 日を含む週がその年の最初の週である。
  • 週は年をまたいで定義される場合があるため、暦週日付の合計は、暦日付または年間通算日の合計とは一致しない。例えば以下の通り:
    • 1995 年 1 月 1 日 (日) は、1994 年の 52 番目の週の 7 番目の日である。
    • 1996 年 12 月 31 日 (火) は、1997 年の 1 番目の週の 2 番目の日である。

なお、週は各地の文化により解釈が異なるため、ISO 8601 ではあまり使用しないことを推奨しています。

Date and Time API では 3 種類の日付表現をすべてサポートしますが、使い勝手の良いインタフェースを提供しているのは暦日付です。暦週日付は文字列表現もしくはいくつかの日付演算の組み合わせを用いて実現します。

2.4. 下位省略表記

暦日付と暦週日付については、精度が要求されない場合には「月」「日」または「曜日」を省略することができます。

書式 1 (拡張形式): YYYY-MM

  • 例 1 (拡張形式): 2014-03

書式 2 (拡張形式): YYYY-Www (基本形式: YYYYWww)

  • 例 2 (拡張形式): 2014-W12 (基本形式: 2014W12)

書式 3 (基本形式): YYYY

  • 例 3 (基本形式): 2014

書式 4 (基本形式): YY

  • 例 4 (基本形式): 20

書式 2 は後述の上位省略表記との重複を避けるため、また書式 3 および書式 4 には区切り文字を入れる場所がないため、それぞれ拡張形式は用意されていません。さらに書式 4 は世紀 (2001 年~2100 年) ではなく百年台 (2000 年~2099 年) を表すことに注意してください。

Date and Time API では、YearMonth クラスや Year クラスが下位省略表記を表します (百年台に対応するクラスはありません)。

なお、年間通算日には下位省略表記は用意されていません。

2.5. 上位省略表記

当事者間の合意が取れているの場合は、「年」の一部または全部、「月」を省略することができます。私たちが日常使用している表現に近いものである一方、「年」の一部を省略するもの (書式 5 から書式 7) は「西暦 2000 年問題」を抱え続けているため注意が必要です。

暦日付の上位省略表記

書式 1 (拡張形式): YY-MM-DD (基本形式: YYMMDD)

  • 例 1 (基本形式): 14-03-21 (基本形式: 140321) ※2014-03-21 の上位省略表記

書式 2 (拡張形式): YY-MM (基本形式: YYMM)

  • 例 2 (基本形式): 14-03 (基本形式: 1403) ※2014-03 の上位省略表記

書式 3 (基本形式): YY

  • 例 3 (基本形式): 14 (2014 の上位省略表記)

書式 4 (拡張形式) --MM-DD (基本形式: --MMDD)

  • 例 4 (拡張形式) --03-21 (基本形式: --0321) ※YYYY-03-21 の上位省略表記

書式 5 (基本形式) --MM

  • 例 5 (基本形式) --03 (YYYY-03 の上位省略表記)

書式 6 (基本形式) ---DD

  • 例 6 (基本形式) ---21 (YYYY-MM-21 の上位省略表記)

暦日付の上位省略表記で用いるハイフンのうち、先頭に付加されるものはむしろ指示記号に近いものとして用いられます (これは年間通算日および暦週日付も同様です)。

Date and Time API は、書式 4 に対応する MonthDay クラスと書式 5 に対応する Month クラスを用意しています。また拡張ライブラリ ThreeTen Extra には書式 6 に対応する DayOfMonth クラスが含まれます。

年間通算日の上位省略表記

書式 7 (拡張形式): YY-DDD (基本形式: YYDDD)

  • 例 7 (拡張形式): 14-080 (基本形式: 14080) ※2014-080 の上位省略表記

書式 8 (基本形式): -DDD

  • 例 8 (基本形式): -080 [YYYY-080 の上位省略表記]

年間通算日の上位省略表記は書式 7 のみ拡張形式があります。

Date and Time API には年間通算日の上位省略表記に対応するクラスは用意されていませんが、拡張ライブラリ ThreeTen Extra には対応する DayOfYear クラスが含まれています。

暦週日付の上位省略表記

書式 9 (拡張形式): YY-Www-D (基本形式: YYWwwD)

  • 例 9 (拡張形式): 14-W12-5 (基本形式: 14W125) ※2014-W12-5 の上位省略表記

書式 10 (拡張形式): YY-Www (基本形式: YYWww)

  • 例 10 (拡張形式): 14-W12 (基本形式: 14W12) ※2014-W12 の上位省略表記

書式 11 (拡張形式): Y-Www-D (基本形式: YWwwD)

  • 例 11 (拡張形式): 4-W12-5 (基本形式: 4W125) ※2014-W12-5 の上位省略表記

書式 12 (拡張形式): Y-Www (基本形式: YWww)

  • 例 12 (拡張形式): 4-W12 (基本形式 4W12) ※2014-W12 の上位省略表記

書式 13 (拡張形式): -Www-D (基本形式 -WwwD)

  • 例 13 (拡張形式): -W12-5 (基本形式 -W125) ※YYYY-W12-5 の上位省略表記

書式 14 (基本形式): -Www

  • 例 14 (基本形式): -W12 ※YYYY-W12 の上位省略表記

書式 15 (基本形式): -W-D

  • 例 15 (基本形式): -W-5 ※YYYY-Wdd-5 の上位省略表記

Date and Time API には暦週日付の上位省略表記に対応するクラスは用意されていません。

3. 時刻の表現

3.1. 時刻

書式 1 (拡張形式): hh:mm:ss (基本形式: hhmmss)

  • 例 1-1 (拡張形式): 00:00:00 (基本形式: 000000) ※日の始まり
  • 例 1-2 (拡張形式): 09:30:45 (基本形式: 093045)
  • 例 1-3 (拡張形式): 12:00:00 (基本形式: 120000) ※正午
  • 例 1-4 (拡張形式): 15:30:00 (基本形式: 153000)
  • 例 1-5 (拡張形式): 21:00:00 (基本形式: 210000)
  • 例 1-6 (拡張形式): 23:59:59 (基本形式: 235959)
  • 例 1-7 (拡張形式): 23:59:60 (基本形式: 235960) ※正の閏秒
  • 例 1-8 (拡張形式): 24:00:00 (基本形式: 240000) ※日の終わり = 翌日の 00:00:00 (000000) と同じ

hh の範囲は 00-24、mm の範囲は 00-59、ss の範囲は 00-60 と定められています。ただし、hh = 24 は 24:00:00 (= 翌日 00:00:00) の場合のみ使用できます。また、ss = 60 は正の閏秒が挿入されたときのみ発生しうる値のため、ss の範囲は通常 00-59 の間となります。

Date and Time API では 24:00:00 の表記はサポートされません。必ず翌日の 00:00:00 として表現する必要があります。

3.2. 時刻の下位省略表記と上位省略表記

下位省略表記

書式 1 (拡張形式): hh:mm (基本形式: hhmm)

  • 例 1-1 (拡張形式): 00:00 (基本形式 0000)
  • 例 1-2 (拡張形式): 12:00 (基本形式 1200)
  • 例 1-3 (拡張形式): 15:30 (基本形式 1530)

書式 2 (基本形式): hh

  • 例 2-1 (基本形式): 21

上位省略表記

書式 3 (拡張形式) -mm:ss (基本形式: -mmss)

  • 例 3-1 (拡張形式) -00:00 (基本形式: -0000) ※hh:30:00 (hh; 00-24) の上位省略表記
  • 例 3-2 (拡張形式) -30:00 (基本形式: -3000) ※hh:30:00 (hh; 00-23) の上位省略表記
  • 例 3-3 (拡張形式) -30:45 (基本形式: -3045) ※hh:30:00 (hh; 00-23) の上位省略表記

書式 4 (基本形式) -mm

  • 例 4-1 (基本形式) -00 ※hh:00 (hh; 00-24) の上位省略表記
  • 例 4-2 (基本形式) -30 ※hh:30 (hh; 00-23) の上位省略表記

書式 5 (標準形式) --ss

  • 例 5-1 (基本形式) --00 ※hh:mm:00 (hh; 00-24, mm; 00-59) の上位省略表記
  • 例 5-2 (基本形式) --45 ※hh:mm:45 (hh; 00-23, mm; 00-59) の上位省略表記

3.3. 小数点を含む時刻

書式 1 (拡張形式): hh:mm:ss.ss (標準形式: hhmmss.ss) ※s; 0 文字以上の数字

  • 例 1-1 (拡張形式): 15:30:45.250 (標準形式: 153045.250)
  • 例 1-2 (拡張形式): 18:15:00.5 (標準形式: 181500.5)

秒未満 (ミリ秒、マイクロ秒など) の精度が必要であれば、以下の条件の下で秒の小数点表記を使用することができます。

  • 当事者間の合意に基づき小数点以下の桁数 (固定長) が決定されていること
  • 整数部と小数部はピリオド '.' または カンマ ',' で区切られていること
  • 1 秒未満は必ず整数部を '00' とすること

Date and Time API では、時刻を小数部桁数が 9 桁 (すなわちナノ秒の精度) で扱います。LocalTime.toString() メソッドが返す文字列表現は、hh:mm (下位省略表記)、hh:mm:ss (小数部桁数なし)、小数部桁数 3 桁、6 桁および 9 桁の 5 段階のうち、LocalTime クラスのインスタンスが保持している値を表現するのに最小限必要なものが自動的に選択されます。

書式 2 (拡張形式): hh:mm.mm (標準形式: hhmm.mm) ※m; 0 文字以上の数字

  • 例 2 (拡張形式): 14:00.25 (標準形式: 1400.25) ※14:00:15 と同義

書式 3 (標準形式): hh.hh ※h; 0 文字以上の数字

  • 例3 (標準形式): 12.5 ※12:30:00 と同義

下位省略表記により「秒」または「分」を省略している場合は、それぞれ「分」または「時」の小数点表記を用いることができます。

Date and Time API は、標準では「分」および「時」の小数点表記をサポートしていません。

4. 日付と時刻の組み合わせ

書式 1: 暦日付 'T' 時刻

  • 例1 (拡張形式): 2014-03-21T13:00:00 (標準形式: 20140321T130000)

書式 2: 年間通算日 'T' 時刻

  • 例2 (拡張形式): 2014-080T13:00 (標準形式: 2014080T1300)

書式 3: 暦週日付 'T' 時刻

  • 例 3 (拡張形式): 2014-W12-5T13:00:00.250 (標準形式: 2014W125T130000.250)

日付と時刻は組み合わせて表記することが可能です。ただし下記のルールに従う必要があります。

  • 日付と時刻の間は指示記号 'T' で区切る (当事者間の合意があれば省略も可能だが、'T' 以外の文字、例えば空白文字を使用することは許されない)
  • 日付は「暦日付」「年間通算日」「暦週日付」から任意に選択可能。上位省略表記を使用することは可能だが、下位省略表記は使用できない。
  • 時刻は下位省略表記または小数点表記を使用することが可能である。ただし、上位省略表記は使用できない。
  • 標準形式と拡張形式のいずれを使用しても良いが、両者を混在させてはならず、必ずどちらかに統一する。

ISO 8601 では、適用業務が日付のみを扱うのか、あるいは時刻のみを扱うのか明確でない場合には (本当はこのような曖昧な仕様ではいけないのですが...)、日付と時刻の組み合わせとして扱うように取り決めています。

5. 地方時と協定世界時

5.1. 地方時と協定世界時

地球はおよそ 24 時間で自転しています。これが意味することは、地球の位置関係が同一の瞬間であっても、特定の場所では昼 (太陽に面している) であるが、また別の場所では夜 (太陽から隠れている) ことを意味します。このことはまた、観測地点によって時刻がまちまちであることをも示します。観測地点における時刻を「地方時 (local time)」と呼びます。

さて、地方時のうち世界中時刻の基準となっているものがあります。現在「協定世界時 (UTC)」と呼ばれているものがそれで、本初子午線 (経度 0°) における時刻を表します。本初子午線における時刻には歴史的に「世界時 (UT)」や「グリニッジ標準時 (GMT)」も使われていました。これらは計測方法により若干の誤差はありますが、概ね同じ時刻を表します。

現在の本初子午線であるグリニッジ子午線は、イギリスのグリニッジ天文台が存在する場所の経度を指しています。しかし、歴史的には本初子午線の決定が先で、グリニッジ天文台は本初子午線のランドマークとして建設された天文台だったようです。なお、グリニッジ子午線が国際的な本初子午線として認められたときは、フランスはその決定に不服で、決定から 1 世紀ほど後になるまでフランス独自の本初子午線を使用してとのことです。

GMT は本初子午線における太陽平均時 (天体観測の結果から太陽の動きを逆算して時刻を求める方法で、太陽を直接観測して得られる時刻より高精度です) を基準としています。GMT はあくまで本初子午線における太陽平均時による時刻であるため、観測地点が異なると同じ計測方法でも差異が出ます。そこで、より汎用的な Universal Time (UT) が導入されました。UT には補正の度合いに応じて UT0、UT1、UT2 の 3 種類があり、UT0 は観測地点における太陽平均時 (本初子午線で観測した場合は GMT と同じ)、UT1 は複数の UT0 を平均したものです。通常 UT と行った場合には UT1 を指します。UT2 は UT1 に対して地球の動きを加味した補正を行ったもので最も高精度となります。

UTC は 1972 年以降に導入されたもので、基準を国際原子時 (TAI) として、TAI と UT1 の差分が 0.9 秒以内になるよう時々うるう秒を挿入します。現在はもっぱら UTC が基準時刻として使用されています。

UTC 導入の背景には、TAI があまりに高精度のため、天体観測から導き出した UT1 との差分か無視できなくなったことが挙げられます。TAI は 1950 年代に開始され、1958 年 1 月 1 日に UT2 (UT1 よりも高精度な表現) と同期を取っています。TAI は原子時計が刻む厳密な時刻が基準ですが、UT は天体観測が基準のため徐々に誤差が出始めています。近年、UTC に対する閏秒挿入が増加している背景には、このような理由があります。

5.2. 時差の表現方法

ISO 8601 では、協定世界時からの時差という形で地方時の時間帯を明確にする方法が規定されています。具体的には時刻 (上位省略表記を用いていない) または日付+時刻に時間帯を追加します。

書式 1 (拡張形式): ±hh:mm (基本形式: ±hhmm) -- UTC からの時差 (分までの単位)

  • 例 1-1 (拡張形式): 2014-03-21T13:00+09:00 (基本形式: 20140321T13:00+0900)
  • 例 1-2 (拡張形式): 20:00:00-08:00 (基本形式: 20:00:00-0800)

書式 2 (標準形式): ±hh -- UTC からの時差がちょうど 1 時間単位の場合の省略表記

  • 例 2-1 (標準形式): 2014-03-21T13:00+09 [+0900 と同義]
  • 例 2-2 (標準形式): 20:00:00-08 [-0800 と同義]

書式 3: 協定世界時の場合は指示記号 'Z'

  • 例 3: 2014-03-21T04:00:00Z

6. 時間の表し方

6.1. 時点

長さ 0 とみなされる時間軸上の点を時点 (time-point) といい、時間軸上の位置 (0 点からの距離) によって示します。

ISO 8601 では暦日付の基準として、国際メートル条約が調印された年を 1875 年と定めています。また、暦週日付の基準として、2000 年 1 月 1 日を土曜日と定めています。

Date and Time API では 0 点 (エポック) として 1970 年 1 月 1 日 0 時 0 分 0 秒 (GMT) を使用しています。これは Java が当初から使用してきた Unix 時刻と同じものです。

6.2. 時間長

連続した時間の長さを時間長 (duration) といいます。時間長は主として時間間隔または反復時間間隔を表現するために用いられます。

書式 1: nYnMnDTnHnMnS -- 年月日時分秒の量で指定する

  • 例 1: 2Y10M15DY10H20M30S ※2 年 10 ヶ月 15 日間と 10 時間 20 分 30 秒

書式 2: nW -- 週の数で指定する

  • 例 2: 10W ※10 週間

時間長には下位省略表記、小数点表記および上位省略表記があります。これらは以下のルールに従います。

  • 必要な場合には最下位の構成要素を省略できる。
  • 必要な場合には最下位の構成要素を小数点表記で表すことができる (要領は時刻の小数点表記と同様)。
  • 年、月、日、時、分、秒の数が 0 の場合には、その数と対応する指示記号を省略できる。ただし、すべて 0 の場合でも 1 つは必ず表記すること。
  • 時、分、秒がすべて省略された場合は、指示記号 'T' は省略することができる。

当事者間の合意があれば、時間長の表現として日付または時刻の表現を代用することができます。

Date and Time API では代用形式を使用することはできません。

6.3. 時間間隔

2 つの時点の間の時間部分を時間間隔 (period of time, time-interval)といいます。時間間隔を構成する時点は「始点」および「終点」として表します。時間間隔の書式は下記の 4 通りです。

書式 1 (拡張形式): YYYY-MM-DDThh:mm:ss/YYYY-MM-DDThh:mm:ss (基本形式: YYYYMMDDThhmmss/YYYYMMDDThhmmss) -- 始点 / 終点 (始点と終点を指示記号 '/' で区切る)

  • 例 1: 2012-04-01T12:00:00/2014-03-21T13:30:00 ※2012 年 4 月 1 日 12 時 0 分 0 秒から 2014 年 3 月 21 日 13 時 30 分 0 秒の間の時間間隔

書式 2 (基本形式): PnYnMnDTnHnMnS -- 時間長

  • 例 2: P1Y9M15DT1H30M0S ※1 年 9 ヶ月 15 日間と 1 時間 30 分 0 秒の時間間隔 ※時間軸上の位置は特定されない

書式 3 (拡張形式): YYYY-MM-DDThh:mm:ss/PnYnMnDTnHnMnS (基本形式: YYYYMMDDThhmmss/PnYnMnDTnHnMnS) -- 始点 / 時間長 (始点と時間長を指示記号 '/' で区切る)

  • 例 3: 2014-03-21T13:30:00/P1Y9M15DT1H30M0S ※2014 年 3 月 21 日 13 時 30 分 0 秒から始まる、1 年 9 ヶ月 15 日間と 1 時間 30 分 0 秒の時間間隔

書式 4 (拡張形式): PnYnMnDTnHnMnS/YYYY-MM-DDThh:mm:ss (基本形式: PnYnMnDTnHnMnS/YYYYMMDDThhmmss) -- 時間長 / 終点 (時間長と終点を指示記号 '/' で区切る)

  • 例 4: P1Y9M15DT1H30M0S/2014-03-21T13:30:00 ※2014 年 3 月 21 日 13 時 30 分 0 秒で終わる、1 年 9 ヶ月 15 日間と 1 時間 30 分 0 秒の時間間隔

始点および終点は、日付・時刻の完全表記を用います (基本形式または拡張形式)。時間長は指示記号 'P' を前置します。

Date and Time API では時間間隔を Period クラスおよび Duration クラスで取り扱いますが、ISO 8601 の規定から少しかけ離れた仕様となっています。時間間隔を取り扱う場合には、拡張ライブラリ ThreeTen Extra の Interval クラスや PeriodDuration クラスの併用も検討してください。

6.4. 反復時間間隔

Date and Time API は反復時間間隔をサポートしません。

同じ長さの時間長が切れ目なく続いた期間を反復時間間隔 (recurring time-interval) といいます。反復時間間隔は、時間間隔および反復回数によって指定します。反復時間間隔の具体的な書式は下記の 4 通りです。

書式 1 (拡張形式): Rn/YYYY-MM-DDThh:mm:ss/YYYY-MM-DDThh:mm:ss (基本形式: Rn/YYYYMMDDThhmmss/YYYYMMDDThhmmss) -- 反復回数 / 始点 / 終点 (反復回数、始点、終点をそれぞれ指示記号 '/' で区切る)

  • 例 1: R3/2012-04-01T12:00:00/2014-03-21T13:30:00 ※2012 年 4 月 1 日 12 時 0 分 0 秒から 2014 年 3 月 21 日 13 時 30 分 0 秒の間と、それと同じ長さの時間を計 3 回繰り返した反復時間間隔

書式 2 (基本形式): Rn/PnYnMnDTnHnMnS -- 反復回数 / 時間長 (反復回数と時間長を指示記号 '/' で区切る)

  • 例 2: R6/P1Y9M15DT1H30M0S ※1 年 9 ヶ月 15 日間と 1 時間 30 分 0 秒を 6 回繰り返した反復時間間隔 ※時間軸上の位置は特定されない

書式 3 (拡張形式): Rn/YYYY-MM-DDThh:mm:ss/PnYnMnDTnHnMnS (基本形式: Rn/YYYYMMDDThhmmss/PnYnMnDTnHnMnS) -- 反復回数 / 始点 / 時間長 (反復回数、始点、時間長をそれぞれ指示記号 '/' で区切る)

  • 例 3: R12/2014-03-21T13:30:00/P1Y9M15DT1H30M0S ※2014 年 3 月 21 日 13 時 30 分 0 秒から始まる、1 年 9 ヶ月 15 日間と 1 時間 30 分 0 秒を計 12 回繰り返した反復時間間隔

書式 4 (拡張形式): Rn/PnYnMnDTnHnMnS/YYYY-MM-DDThh:mm:ss (基本形式: Rn/PnYnMnDTnHnMnS/YYYYMMDDThhmmss) -- 反復回数 / 時間長 / 終点 (反復回数、時間長、終点をそれぞれ指示記号 '/' で区切る)

  • 例 4: R12/P1Y9M15DT1H30M0S/2014-03-21T13:30:00 ※2014 年 3 月 21 日 13 時 30 分 0 秒で終わる、1 年 9 ヶ月 15 日間と 1 時間 30 分 0 秒を計 12 回繰り返した反復時間間隔

反復回数は指示記号 'R' を前置します。反復回数が 1 の時は通常の時間間隔と同じ意味になります。反復回数は省略可能で、省略時には反復回数未定 (無限) となります。始点および終点は、日付・時刻の完全表記を用います (基本形式または拡張形式)。時間長は指示記号 'P' を前置します。

7. 年号の表現 (JIS X 0301)

Date and Time API の和暦対応は JIS X 0301 に準拠しておらず、DateTimeFormatter を用いてフォーマットをカスタマイズする必要があります。

ISO 8601 には規定されていませんが、JIS X 0301 ではローカライズに合わせて「元号」の取り扱いについても補足的に触れています。

JIS X 0301 では元号を使用する場合、暦日付を以下の書式で表現することができます。

書式 (拡張形式): NYY.MM.DD (基本形式: YY.MM.DD) ※N: 元号を表す記号

  • 例 1-1: R03.07.01 (基本形式: 03.07.01)
  • 例 1-2: 令03.07.01 (基本形式: 03.07.01)
  • 例 2-1: H26.03.21 (基本形式: なし)
  • 例 2-2: 平26.03.21 (基本形式: なし)

注意点として、年月日の区切りに ISO 8601 で定められているハイフン '-' ではなくピリオド '.' を用いること、年は必ず 2 桁になること、基本形式では現在の元号とみなすことが挙げられます。

現在、元号の符号として定められているものは以下の通りです。

  • 明治: '明', 'M'
  • 大正: '大', 'T'
  • 昭和: '昭', 'S'
  • 平成: '平', 'H'
  • 令和: '令', 'R' (※JIS X 0301:2019 にて追加)

明治より前の元号 (慶応など) は、記号が定められていません。明治以前はグレゴリオ暦と互換性のない天保暦 (太陰太陽暦) が使用されていたため、JIS X 0301 では取り扱わない (西暦を使用する) ことになっています。

Table 5. 元号と西暦の対応表

元号 記号 当該元号の日付 対応する西暦日付
明治 明,M M01.01.01 [2] 1868-01-25
M01.09.08 1868-10-23
M05.12.02 1872-12-31
M06.01.01 [3] 1873-01-01
M45.07.29 1912-07-29
大正 大,T T01.07.30 1912-07-30
T15.12.24 1926-12-24
昭和 昭,S S01.12.25 1926-12-25
S64.01.07 [4] 1989-01-07
平成 平,H H01.01.08 1989-01-08
H31.04.30 2019-04-30
令和 令,R R01.05.01 2019-05-01

8. まとめ

今回は ISO 8601 を解説しました。Data and Time API は ISO 8601 に基づいて設計されており、API の細かな振る舞いについて「ISO 8601 でそのように規定されているから」としか説明できない場合が多々あります。ISO 8601 という前提知識があるだけで Date and Time API の理解は深まります。

【参考文献】

  • 日本工業標準調査会「情報交換のためのデータ要素及び交換形式-日付及び時刻の表記」(JIS X 0301:2002), 日本規格協会, 2002 年 8 月
  • 日本工業標準調査会「情報交換のためのデータ要素及び交換形式-日付及び時刻の表記 (追補 1)」(JIS X 0301:2019), 日本規格協会, 2019 年 5 月
  • Oracle Corporation「Java(tm) Platform, Standard Edition 8 API仕様」
    https://docs.oracle.com/javase/jp/8/docs/api/
  • ThreeTen Project「ThreeTen Extra」
    https://www.threeten.org/threeten-extra/
脚注
  1. しかし、日本における日付表現が Year Month Day 順でかつスラッシュ ('/') 区切りを常用していることは運が悪かったとしか言い様がありません。 ↩︎

  2. 元号が (それまでの慶応から) 明治に改元されたのは、実際には天保暦 (太陰太陽暦) の 9 月 8 日ですが、改元は同年の 1 月 1 日まで遡って適用されました。 ↩︎

  3. 明治 6 年 1 月 1 日をもって、それまでの天保暦からグレゴリオ暦 (西暦) に移行しました。その調整のため、明治 5 年 12 月 2 日の翌日が明治 6 年 1 月 1 日となっています。 ↩︎

  4. 昭和天皇が昭和 64 年 1 月 7 日に崩御し、翌日に改元された後も、システムが「平成」に対応するまでの移行措置として昭和換算の日付を用いる (例えば、1990-12-19 を暫定的に S65.12.19 として処理する) ことが認められていました。 ↩︎

この記事に贈られたバッジ

Discussion

ログインするとコメントできます