web-dev-qa-db-ja.com

ISO 8601時間間隔解析Java

ISO 8601 は、時間間隔を表す構文を定義します。

時間間隔を表すには4つの方法があります。

  • 「2007-03-01T13:00:00Z/2008-05-11T15:30:00Z」などの開始と終了
  • 「2007-03-01T13:00:00Z/P1Y2M10DT2H30M」などの開始と期間
  • 「P1Y2M10DT2H30M/2008-05-11T15:30:00Z」などの期間と終了
  • 「P1Y2M10DT2H30M」などの期間のみ、追加のコンテキスト情報

終了値から欠落している要素がある場合、それらは、タイムゾーンを含む開始値と同じであると見なされます。標準のこの機能により、時間間隔の簡潔な表現が可能になります。たとえば、開始時間と終了時間を含む2時間の会議の日付は、「2007-12-14T13:30/15:30」のように単純に表示できます。「/ 15:30」は「/ 2007-12- 14T15:30 "(開始と同じ日付)、または毎月の請求期間の開始日と終了日は" 2008-02-15/03-14 "("/03-14 "は"/2008-03 "を意味する) -14 "(開始と同じ年)。

さらに、繰り返し間隔は、間隔式の先頭に "R [n] /"を追加することによって形成されます。ここで、Rは文字自体として使用され、[n]は繰り返し数に置き換えられます。 [n]の値を省略することは、無限の繰り返し回数を意味します。したがって、「2008-03-01T13:00:00Z」から「P1Y2M10DT2H30M」の間隔を5回繰り返すには、「R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M」を使用します。

この構文を解析するための適切なJava=パーサー(可能な場合は、Joda-Timeライブラリと互換性がある)を探しています。優れたライブラリへのポインタはありますか?

23
fellahst

Java.time

Java 8以降に組み込まれている Java.time フレームワークには、 Duration.parseISO 8601形式の期間を解析するためのメソッド

Java.time.Duration d = Java.time.Duration.parse("PT1H2M34S");
System.out.println("Duration in seconds: " + d.get(Java.time.temporal.ChronoUnit.SECONDS));

プリントDuration in seconds: 3754

24
Shaun Parker

サードパーティライブラリの使用が制限されている可能性のあるプロジェクト(ライセンスの理由など)を問わず、Java 1.6(またはそれ以前)では、Java自体がこの機能の少なくとも一部を提供します。 javax.xml.datatype.DatatypeFactory.newDuration(String) メソッドと Duration クラスを使用します。 DatatypeFactory.newDuration(String)メソッドは、「PnYnMnDTnHnMnS」形式の文字列を解析します。これらのクラスはXML操作を目的としていますが、XMLはISO 8601時間表記を使用しているため、便利な期間解析ユーティリティとしても機能します。

例:

import javax.xml.datatype.*;

Duration dur = DatatypeFactory.newInstance().newDuration("PT5H12M36S");
int hours = dur.getHours(); // Should return 5

私はあなたがリストした4番目以外の期間形式を個人的に使用したことはないため、正常に解析されたかどうかについては保証できません。

15
Ogre Psalm33

Joda-Timeを既に試したことがあると思いますか? Interval.parse(Object)を介して質問から文字列の例を入力すると、「開始と終了」、「開始と継続時間」、および「継続時間と終了」を処理できますが、暗黙のフィールドや繰り返しは処理できません。

2007-03-01T13:00:00Z/2008-05-11T15:30:00Z => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z
2007-03-01T13:00:00Z/P1Y2M10DT2H30M       => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z
P1Y2M10DT2H30M/2008-05-11T15:30:00Z       => from 2007-03-01T13:00:00.000Z to 2008-05-11T15:30:00.000Z
2007-12-14T13:30/15:30                    => Java.lang.IllegalArgumentException: Invalid format: "15:30" is malformed at ":30"
R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M    => Java.lang.IllegalArgumentException: Invalid format: "R5"

私が知っている他の唯一の包括的な日付/時刻ライブラリは JSR-31 で、これはこのような間隔を処理するようには見えません。

この時点で、Joda-Timeの上に独自の改善を構築することがおそらく最良の選択です。 Joda-Timeで既にサポートされているもの以外に、処理する必要がある特定のISO間隔形式はありますか?

10
Barend

必要な間隔解析のすべての機能をモデル化できる唯一のライブラリは、実際には私のライブラリ Time4J (range-module )。例:

_// case 1 (start/end)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/2014-06-20T16:00Z"));
// output: [2012-01-01T14:15:00Z/2014-06-20T16:00:00Z)

// case 1 (with some elements missing at end component and different offset)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/08-11T16:00+00:01"));
// output: [2012-01-01T14:15:00Z/2012-08-11T15:59:00Z)

// case 1 (with missing date and offset at end component)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/16:00"));
// output: [2012-01-01T14:15:00Z/2012-01-01T16:00:00Z)

// case 2 (start/duration)
System.out.println(MomentInterval.parseISO("2012-01-01T14:15Z/P2DT1H45M"));
// output: [2012-01-01T14:15:00Z/2012-01-03T16:00:00Z)

// case 3 (duration/end)
System.out.println(MomentInterval.parseISO("P2DT1H45M/2012-01-01T14:15Z"));
// output: [2011-12-30T12:30:00Z/2012-01-01T14:15:00Z)

// case 4 (duration only, in standard ISO-format)
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P2DT1H45M");

// case 4 (duration only, in alternative representation)
Duration<IsoUnit> isoDuration = Duration.parsePeriod("P0000-01-01T15:00");
System.out.println(isoDuration); // output: P1M1DT15H
_

いくつかの備考:

  • 他の間隔クラスも同様の解析機能で存在します。たとえば、パッケージ内のDateIntervalまたはTimestampIntervalnet.time4j.range です。

  • 期間のみの処理(カレンダーとクロックの両方の単位にまたがることができる)については、 javadoc も参照してください。書式設定機能もあります。ネストされたクラス_Duration.Formatter_またはローカライズ版_net.time4j.PrettyTime_(実際には86言語)を参照してください。

  • 相互運用性はJava-8(_Java.time_- package)で提供されますが、Joda-Timeでは提供されません。例:MomentIntervalの開始コンポーネントまたは終了コンポーネントは、getStartAsInstant()またはgetEndAsInstant()によって簡単にクエリできます。

繰り返し間隔は、クラス IsoRecurrence でサポートされています。例:

_IsoRecurrence<MomentInterval> ir =
    IsoRecurrence.parseMomentIntervals("R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M");
ir.intervalStream().forEach(System.out::println);
_

出力:

_[2008-03-01T13:00:00Z/2009-05-11T15:30:00Z)
[2009-05-11T15:30:00Z/2010-07-21T18:00:00Z)
[2010-07-21T18:00:00Z/2011-10-01T20:30:00Z)
[2011-10-01T20:30:00Z/2012-12-11T23:00:00Z)
[2012-12-11T23:00:00Z/2014-02-22T01:30:00Z)
_
9
Meno Hochschild