2012年7月24日火曜日

Lightweight XMLSchema dateTime parser in Java

To start with the conclusion, XMLSchemaDateTimeParser.parse(String) does the job.

String dateTime = "2005-11-14T02:16:38Z";
Calendar calendar = XMLSchemaDateTimeParser.parse(dateTime);

The XMLSchema specification defines some built-in data types. 'dateTime' is one of them and is a subset of ISO 8601. The format of XMLSchema dateTime is defined as follows.

yyyy-mm-ddThh:mm:ss{milliseconds}{timezone}

{milliseconds} part can be omitted. If it exists, it should follow the format: '.' s+ (one leading period plus one or more digits). One example is ".125" and this means 125 milliseconds.

{timezone} part also can be omitted. If it exists, it should be either a single 'Z' or a timezone offset written in this format: [+-]hh:mm. For example, "+09:00" indicates 9 hours ahead of Coordinated Universal Time (UTC). 'Z' means offset zero (±00:00).

Strictly speaking, the specification allows a leading hyphen ('-') before the year part (yyyy) as a negative sign for B.C. years, but I removed it from the format shown above for brevity.

Below are examples of strings written in the XMLSchema dateTime format.

  • 2005-11-14T02:16:38Z
  • 2005-11-14T02:16:38+09:00
  • 2005-11-14T02:16:38.125

Joda Time (Java date and time API) is a well-known open-source Java library that can parse ISO 8601 just as one of its functions, but if what you want to do is just to parse XMLSchema dateTime, it may be too big. In such a case, consider to use XMLSchemaDateTimeParser (hosted on GitHub) which consists of just one source file (XMLSchemaDateTimeParser.java).

However, note that XMLSchemaDateTimeParser has some (trivial) limitations as listed below.

  1. The specification allows the year part to be a 5-or-mode digit number, but XMLSchemaDateTimeParser assumes only 4-digit numbers at the year part.
  2. The specification allows a leading hyphen ('-') to indicate B.C. years, but XMLSchemaDateTimeParser just ignores the negative sign.
  3. The specification does not mention the length of the millisecond part, but XMLSchemaDateTimeParser assumes that the length is between 1 and 3.


軽量 XMLSchema dateTime パーサー (Java)

結論から先に言うと、XMLSchemaDateTimeParser.parse(String) で作業完了です。

String dateTime = "2005-11-14T02:16:38Z";
Calendar calendar = XMLSchemaDateTimeParser.parse(dateTime);

XMLSchema の仕様では、組み込みのデータ型を幾つか定義しています。'dateTime' はその一つであり、ISO 8601 のサブセットとなっています。XMLSchema dateTime のフォーマットは次のように定義されています。

yyyy-mm-ddThh:mm:ss{ミリ秒}{タイムゾーン}

{ミリ秒} の部分は省略可能です。存在している場合は、「'.' s+ (一つのピリオドと一つ以上の数字)」というフォーマットとなります。例えば ".125" であれば、125ミリ秒を意味します。

{タイムゾーン} の部分も省略可能です。存在している場合は、'Z' 一文字か、もしくは「[+-]hh:mm」というフォーマットでタイムゾーン・オフセットを示します。例えば "+09:00" は協定世界時 (UTC) より 9 時間進んでいることを示します。'Z' はオフセット・ゼロ (±00:00) を意味します。

厳密に言うと、仕様によれば、年の部分 (yyyy) の前にハイフン ('-') を付けて紀元前を示すことが可能ですが、分かりやすくするために上述のフォーマットからは省いています。

下記は XMLSchema dateTime フォーマットで書かれた文字列の例です。


  • 2005-11-14T02:16:38Z
  • 2005-11-14T02:16:38+09:00
  • 2005-11-14T02:16:38.125

Joda Time (Java date and time API) という良く知られたオープンソースの Java ライブラリがあり、機能の一つとして ISO 8601 のパースも可能ですが、やりたいことが XMLSchema dateTime のパースだけであれば、Joda Time ライブラリは大き過ぎるかもしれません。そのような場合は、単一のソースファイル (XMLSchemaDateTimeParser.java) だけで構成される XMLSchemaDateTimeParser (GitHub で公開) の使用を検討してみてください。

但し、XMLSchemaDateTimeParser には幾つか (些細な) 制限があります。

  1. 仕様では年の部分を 5 桁以上の数字にすることを許しているが、XMLSchemaDateTimeParser では年の部分には 4 桁の数字のみを想定している。
  2. 仕様では紀元前を示すために先頭にハイフンを付けることを許しているが、XMLSchemaDateTimeParser は、当該負号を無視する。
  3. 仕様ではミリ秒部分の長さに言及していないが、XMLSchemaDateTimeParser では長さが 1 から 3 の間であると想定している。