JavaでのISO 8601形式の日時の処理についての雑多なメモ
java.text.SimpleDateFormat
Java標準のSimpleDateFormatの場合、タイムゾーンを指定する大文字の"Z"が「+0900」となってしまい、「+09:00」のように区切りを入れてくれない。そのため、区切り文字を使用しないISO 8601の基本形式(Basic format)にするか、UTCにするかということになる。
ミリ秒のparseでエラー?
SimpleDateFormatでミリ秒を指定した文字列をparse()したところParseExceptionになってしまった。java versionは"1.6.0_22"。
Exception in thread "main" java.text.ParseException: Unparseable date: "20110214T164254.418+0900" at java.text.DateFormat.parse(Unknown Source)
いろいろやってみたらミリ秒を「S」だとエラー。3文字の「SSS」ならOKのようだ。
- OK→"yyyyMMdd'T'HHmmss.SSSZ"
- NG→"yyyyMMdd'T'HHmmss.SZ"、これはformat()はできてもparse()ができない。
org.apache.commons.lang.time
Apacheのcommons langの場合
org.apache.commons.lang.time.FastDateFormat
java.text.SimpleDateFormatとほぼ同機能だが、タイムゾーン出力では、大文字2文字の'ZZ'を使うと、「+09:00」のように出力される。
org.apache.commons.lang.time.DateUtils
FastDateFormatではparse()はサポートされていないようで、代わりにDateUtilsクラスにparseDate(String str, String[] parsePatterns)というのがある。フォーマット文字列を複数指定して解析できるみたいだ。内部的にSimpleDateFormatを使っているので、やはりミリ秒が「SSS」でないとエラーになるようだ。
Joda-Time
- Joda-Time - Java date and time API - Home
http://joda-time.sourceforge.net/
DateTimeクラスで普通にISO 8601の拡張形式で扱える。ISODateTimeFormatに基本形式に対応するフォーマッターがあるみたい。
コード
試しに使ってみたコード片
import java.text.SimpleDateFormat; import java.util.Date; import java.util.TimeZone; import org.apache.commons.lang.time.DateUtils; import org.apache.commons.lang.time.FastDateFormat; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.ISODateTimeFormat; public class ISO8601FormatTest { public static void main(String[] args) throws Exception { Date now = new Date(); String str; Date date; // ISO 8601の基本形式 SimpleDateFormat sdfIso8601BasicFormat = new SimpleDateFormat("yyyyMMdd'T'HHmmss.SSSZ"); str = sdfIso8601BasicFormat.format(now); System.out.println(str); date = sdfIso8601BasicFormat.parse(str); System.out.println(sdfIso8601BasicFormat.format(date)); // ISO 8601の拡張形式(UTC) SimpleDateFormat sdfIso8601ExtendedFormatUtc = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); sdfIso8601ExtendedFormatUtc.setTimeZone(TimeZone.getTimeZone("UTC")); str = sdfIso8601ExtendedFormatUtc.format(now); System.out.println(str); date = sdfIso8601ExtendedFormatUtc.parse(str); System.out.println(sdfIso8601ExtendedFormatUtc.format(date)); // Apache commons langでformat() FastDateFormat fdfIso8601ExtendedFormat = FastDateFormat.getInstance("yyyy-MM-dd'T'HH:mm:ss.SSSZZ"); str = fdfIso8601ExtendedFormat.format(now); System.out.println(str); // Apache commons langでparse() String[] parsePatterns = { "yyyy-MM-dd'T'HH:mm:ss.SSSZZ", }; date = DateUtils.parseDate(str, parsePatterns); System.out.println(fdfIso8601ExtendedFormat.format(date)); // Joda-timeで普通に文字列にするとISO 8601の拡張形式 DateTime dtNow = new DateTime(now); str = dtNow.toString(); System.out.println(str); DateTime fromString = new DateTime(str); System.out.println(fromString); // Joda-timeでISO 8601の基本形式 DateTimeFormatter dftIsoBasic = ISODateTimeFormat.basicDateTime(); str = dftIsoBasic.print(dtNow); System.out.println(str); fromString = dftIsoBasic.parseDateTime(str); System.out.println(dftIsoBasic.print(fromString)); } }
実行結果
20110219T155422.302+0900 20110219T155422.302+0900 2011-02-19T06:54:22.302Z 2011-02-19T06:54:22.302Z 2011-02-19T15:54:22.302+09:00 2011-02-19T15:54:22.302+09:00 2011-02-19T15:54:22.302+09:00 2011-02-19T15:54:22.302+09:00 20110219T155422.302+0900 20110219T155422.302+0900
log4j
log4jではISO8601形式でタイムスタンプを出力するという指定ができるが、厳密にはISO 8601になっていないようだ。「2010-12-15 16:16:59,140」というように空白を使ってしまっている。
以下のバグ報告を見ると修正されたような回答があるが、実際にはlog4j 1.2系では修正されていないような感じだ。
- Bug 3736 ? log4j timestamps are not ISO 8601 compatible
http://bugzilla.globus.org/globus/show_bug.cgi?id=3736
logbackでどうなっているかは見てない。
Axis2/Java
xsd:dateTimeとjava.util.Calendar間の変換処理。org.apache.axis2.databinding.utils.ConverterUtilあたりで自前でやっているようだ。
正規表現でのマッチング
- ISO Date Validation RegEx ≪ Infovark Underground
http://underground.infovark.com/2008/07/22/iso-date-validation-regex/
ISOやJISの規約
URLメモ
XML関連の規約
XML関連の規約では、基本ISO 8601と同じなんだけど、もう少し限定して使いましょうみたいな感じらしい。
以下、ちゃんと読んでない。
- Date and Time Formats
http://www.w3.org/TR/NOTE-datetime
ISO 8601の基本形式は使わないで、拡張形式だけで、表記の揺れをなくしましょうというスタンスのようだ。
- XML Schema Part 2: Datatypes Second Edition
http://www.w3.org/TR/xmlschema-2/#dateTime - XML Schema Part 2: Datatypes Second Edition
http://www.w3.org/TR/xmlschema-2/#isoformats
付録のDにISO 8601 Date and Time Formatsというのがあるようだ。