解析AMAZON.DURATION插槽类型的ISO-8601持续时间值

时间:2017-09-16 21:12:37

标签: java duration java-time alexa-skills-kit period

java.time库是否提供了解析整个ISO-8601 Duration Specification的整合方式?

Alexa Slot Type reference for duration列出了使用AMAZON.DURATION插槽类型时需要的一些示例字符串。所有字符串都在ISO-8601持续时间内,但P2YT3H10java.time.Period无法解析java.time.Duration

Seq(
 "PT10M",
 "PT5H",
 "P3D",
 "PT45S",
 "P8W",
 "P7Y",
 "PT5H10M",
 "P2YT3H10"
).map { s =>
 s -> Try {
   try {
     Period.parse(s)
   } catch {
     case ex: Throwable => Duration.parse(s)
   }
 }.map(x => x.toString -> x.getClass.getSimpleName)
}
.foreach(println)

结果:

(PT10M,Success((PT10M,Duration)))
(PT5H,Success((PT5H,Duration)))
(P3D,Success((P3D,Period)))
(PT45S,Success((PT45S,Duration)))
(P8W,Success((P56D,Period)))
(P7Y,Success((P7Y,Period)))
(PT5H10M,Success((PT5H10M,Duration)))
(P2YT3H10,Failure(java.time.format.DateTimeParseException: Text cannot be parsed to a Duration))

3 个答案:

答案 0 :(得分:5)

Hugos答案仅与ISO-8601标准的一个细节方面有关,即日期和时间部分与" T" -separator的组合。 java.time确实不支持此详细信息,但外部库Threeten-Extra(使用版本v1.2中的类PeriodDuration)支持此详细信息。但是:

ISO-8601标准描述了更多变化。

一种变体是使用周形式" P8W"。 java.time和Threeten-Extra都会自动将其更改为" P56D"但在解析和格式化时不要以与周相关的形式保留它。查看时间组件时可以获得类似的视图。 java.time.Duration无法直接存储小时或分钟,但会自动将其转换为秒。当执行格式化自动规范化时也是如此。例如:

System.out.println(Duration.parse("PT4200S")); // PT1H10M

所以在这两种情况下:在构建期间放入的内容并不总是格式化时的内容

其他要点:

  • ISO-8601中的持续时间表示(如第4.4.4.2节所述)始终被称为"持续时间" (即使与日期相关),java.time使用两个不同的术语,即PeriodDuration(与日期相关或与时间相关)。
  • 与周相关的持续时间是分开处理的,因为描述了ISO-8601-notation中的两种标准方式:" PnnYnnMnnDTnnHnnMnnS"或" PnnW"。
  • 符号不存在于ISO-8601规范中(参见第3.4.2节:符号" n"定义为正整数或零),{{1即使在表示内部也允许符号,并将符号解释为与组件相关的符号。请注意,XML-Schema仅处理整个持续时间表达式之前的符号(在" P"之前),这不是与组件相关的,而是与持续时间相关的。
  • 还指定了持续时间的替代表示,无论是基本格式还是扩展格式:" PYYYYMMDDThhmmss" RESP。 " PYYYY-MM-DDTHH:MM:SS"
  • 小数秒的处理:ISO-8601谈到逗号或点的使用(甚至明确优先使用逗号),而java.time仅支持点。

最后我们可以声明:

java.time.Duration(和Threeten-Extra仅支持类java.timePeriod的组合作为附加细节)仅部分支持ISO-8601标准。

真正的ISO-8601支持的替代解决方案:

如果您想要甚至需要克服java.time.Duration中的限制,那么您可以使用我的库Time4J,它支持ISO-8601的所有其他详细信息。请参阅类net.time4j.Duration的API。以下示例还显示了与java.time的兼容性:

java.time

附注:实际上有86种语言可以格式化持续时间。

答案 1 :(得分:3)

PS :您的输入缺少最后一个字段的指示符(P2YT3H10 - 2年,3小时和10个什么?)。所以,在下面的代码中,我只是假设它是M(分钟) - 它在10之后没有指示符的情况下无法工作。

java.time API分隔了ISO8601持续时间in 2 classes

  • java.time.Period,可以处理date-based fields (years, months and days)
  • java.time.Duration,可以处理time-based fields *(实际上,根据javadoc:"这个类用秒和纳秒来模拟一个数量或时间量。它可以可以使用其他基于持续时间的单位访问,例如分钟和小时"

不幸的是,这些课程无法处理基于日期和时间的字段的ISO8601持续时间。

另一种方法是使用ThreeTen Extra项目,该项目包含java.time API的一些扩展。使用此lib,您可以使用org.threeten.extra.PeriodDuration class,它可以解析完整的ISO8601持续时间:

PeriodDuration pd = PeriodDuration.parse("P2YT3H10M");

然后,您可以从中获取相应的PeriodDuration

System.out.println(pd.getPeriod()); // P2Y
System.out.println(pd.getDuration()); // PT3H10M

另一种方法是拆分String,并分别解析PeriodDuration

// split in 2 parts
String input = "P2YT3H10M";
String[] v = input.split("T");
Period p;
Duration d;
if (v.length == 1) { // has only date-based fields
    p = Period.parse(input);
    d = Duration.ZERO;
} else {
    if ("P".equals(v[0])) { // has only time-based fields
        p = Period.ZERO;
    } else {
        p = Period.parse(v[0]);
    }
    d = Duration.parse("PT" + v[1]);
}

* Duration也接受,由于夏令时,这些时间始终被认为是24小时(Period,一天doesn't necessarily have 24 hours时间效应)。

答案 2 :(得分:0)

Java 8持续时间仅允许天,小时,分钟和秒:

接受的格式基于ISO-8601持续时间格式PnDTnHnMn.nS

https://docs.oracle.com/javase/8/docs/api/java/time/Duration.html#parse-java.lang.CharSequence-