ISO 8601 Java时间间隔解析

fel*_*hst 22 java time parsing jodatime intervals

ISO 8601定义了表示时间间隔的语法.

表达时间间隔有四种方式:

  • 开始和结束,例如"2007-03-01T13:00:00Z/2008-05-11T15:30:00Z"
  • 开始和持续时间,例如"2007-03-01T13:00:00Z/P1Y2M10DT2H30M"
  • 持续时间和结束,例如"P1Y2M10DT2H30M/2008-05-11T15:30:00Z"
  • 持续时间,例如"P1Y2M10DT2H30M",带有附加的上下文信息

如果结束值中缺少任何元素,则假定它们与包括时区的起始值相同.标准的这一特征允许简洁地表示时间间隔.例如,包括开始和结束时间在内的两小时会议的日期可以简单地显示为"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"的间隔五次,请使用"R5/2008-03-01T13:00:00Z/P1Y2M10DT2H30M".

我正在寻找一个好的Java解析器(如果可能与Joda-Time库兼容)来解析这个语法.任何指向好图书馆的指针?

小智 23

java.time

Java 8及更高版本中内置的java.time框架具有Duration.parse解析ISO 8601格式持续时间的方法:

java.time.Duration d = java.time.Duration.parse("PT1H2M34S");
System.out.println("Duration in seconds: " + d.get(java.time.temporal.ChronoUnit.SECONDS));
Run Code Online (Sandbox Code Playgroud)

打印 Duration in seconds: 3754

  • 不幸的是,java.time区分持续时间(基于时间)和期间(基于日期),因此Duration.parse()和Period.parse()都不能处理第四种情况("P1Y2M10DT2H30M") (8认同)
  • 此外,读者可能对[ThreeTen-Extra]中提供的[`Interval`](http://www.threeten.org/threeten-extra/apidocs/org/threeten/extra/Interval.html)课程感兴趣( http://www.threeten.org/threeten-extra/)项目.该项目扩展了java.time,由同一个人编写.该项目还可以作为未来可能添加到java.time的试验场.`Interval`类将一段时间定义为一对[`Instant`](http://docs.oracle.com/javase/8/docs/api/java/time/Instant.html)对象.该类解析ISO 8601字符串,例如"2007-03-01T13:00:00Z/2008-05-11T15:30:00Z". (3认同)

Ogr*_*m33 13

对于一个项目的人可能会使用第三方库的限制(许可方面的原因,或其他),Java本身至少提供此功能的一部分,自从Java 1.6(或更早?),使用的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
Run Code Online (Sandbox Code Playgroud)

我没有亲自使用任何持续时间格式,除了你列出的第四个,所以我不能保证它是否成功解析它们.

  • @takacsot 你是对的!示例字符串中的“m”和“s”是小写的,并且应该是大写的以符合 ISO 8601 规范。固定的。 (2认同)

Bar*_*end 9

我认为你已经尝试过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"
Run Code Online (Sandbox Code Playgroud)

我所知道的唯一其他综合日期/时间库是JSR-310,它似乎不会处理这些间隔.

此时,在Joda-Time之上构建自己的改进可能是您的最佳选择,抱歉.除了Joda-Time已经支持的那些之外,是否还需要处理任何特定的ISO间隔格式?

  • 在得到15分之前我不能投票,但是一旦得到它我就会投票:) (2认同)

Men*_*ild 8

唯一能够模拟所需间隔解析功能的库实际上是我的库Time4J(范围模块).例子:

// 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
Run Code Online (Sandbox Code Playgroud)

一些评论:

  • 其他间隔类具有类似的解析功能,例如,DateInterval或者TimestampIntervalnet.time4j.range包中.

  • 仅用于处理持续时间(也可以跨越日历和时钟单位),另请参阅javadoc.还有格式化功能,请参阅嵌套类Duration.Formatter或本地化版本net.time4j.PrettyTime(实际上是86种语言).

  • Java-8(java.time-package)提供互操作性,但Joda-Time不提供.例如:a的起始或结束组件MomentInterval可以通过getStartAsInstant()或轻松查询getEndAsInstant().

IsoRecurrence类支持重复间隔.例:

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

输出:

[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)
Run Code Online (Sandbox Code Playgroud)