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

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

java.time 库是否提供了一种统一的方式来解析整个 ISO-8601 Duration Specification

Alexa Slot Type reference for duration列出了使用 AMAZON.DURATION 插槽类型时预期的一些示例字符串。所有字符串都在 ISO-8601 Duration 中,但是 P2YT3H10 不能被 java.time.Periodjava.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))

最佳答案

Hugos 的回答只涉及 ISO-8601 标准的一个细节方面,即日期和时间部分与“T”分隔符的组合。 java.time 确实不支持此细节,但外部库 Threeten-Extra 支持(使用版本 v1.2 中的类 PeriodDuration)。然而:

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

一种变体是以“P8W”形式使用周。 java.time 和 Threeten-Extra 都会自动将其更改为“P56D”,但在解析和格式化时不要将其保留为与星期相关的形式。查看时间分量时可以获得类似的 View 。 java.time.Duration 不能直接存储小时或分钟,而是自动将其转换为秒。格式化时也会执行自动规范化。示例:

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

所以在这两种情况下:在构建过程中放入的内容并不总是在格式化时得到的内容

其他要点:

  • ISO-8601 中的持续时间表示(如第 4.4.4.2 节中指定) 始终称为“持续时间”(即使与日期相关),而 java.time 使用两个不同的术语,即 PeriodDuration(与日期相关或与时间相关)。
  • 与周相关的持续时间被单独处理,因为描述了 ISO-8601 表示法中的两种标准方式:“PnnYnnMnnDTnnHnnMnnS”或“PnnW”。
  • 符号在 ISO-8601 规范中不存在(参见第 3.4.2 节:符号“n”定义为正整数或零)而 java.time甚至在表示内部也允许符号并将符号解释为与组件相关。请注意,XML-Schema 仅处理整个持续时间表达式之前的符号(“P”之前),这与组件无关但与持续时间相关。
  • 持续时间的替代表示 也以基本格式或扩展格式指定:“PYYYYMMDDThhmmss” resp。 “PYYYY-MM-DDThh:mm:ss”。
  • 处理小数秒:ISO-8601 谈到逗号或点的使用(甚至明确更喜欢逗号),而 java.time.Duration 只支持点.

最后我们可以声明:

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

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

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

Duration<CalendarUnit> d1 = Duration.parseCalendarPeriod("P8W");
System.out.println(d1); // P8W
System.out.println(d1.getPartialAmount(CalendarUnit.WEEKS)); // 8
System.out.println(Duration.Formatter.ofPattern(CalendarUnit.class, "W' weeks'").format(d1)); // 8 weeks
System.out.println(PrettyTime.of(Locale.GERMAN).print(d1)); // 8 Wochen
LocalDate ld = LocalDate.of(2017, 9, 17);
System.out.println(PlainDate.from(ld).plus(d1)); // 2017-11-12
System.out.println(PlainDate.of(2017, 9, 17).plus(d1)); // 2017-11-12

Duration<IsoUnit> d2 = Duration.parsePeriod("P2DT5H10M");
LocalDateTime ldt = LocalDateTime.of(2017, 9, 17, 19, 15);
System.out.println(PlainTimestamp.from(ldt).plus(d2)); // 2017-09-20T00:25
System.out.println(PlainTimestamp.of(2017, 9, 17, 19, 15).plus(d2)); // 2017-09-20T00:25
System.out.println(PrettyTime.of(Locale.GERMAN).print(d2)); // 2 Tage, 5 Stunden und 10 Minuten

Duration<IsoUnit> d3 = Duration.parsePeriod("P0001-01-02T05:10:04");
System.out.println(d3); // P1Y1M2DT5H10M4S
LocalDateTime ldt = LocalDateTime.of(2017, 9, 17, 19, 15);
System.out.println(PlainTimestamp.from(ldt).plus(d3)); // 2018-10-20T00:25:04

旁注:实际上 86 种语言都可以设置持续时间的格式。

关于java - 解析 AMAZON.DURATION 插槽类型的 ISO-8601 持续时间值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46258478/

相关文章:

java - Spring Boot如何创建Auto配置类

java - 使用 try-with-resources java 关闭数据库连接

html - 如何获取 html5 音频的持续时间

android - 来自画廊的视频选择 : Limit only videos up to 30 seconds should be selected

c++ - 将 std::string 转换为 std::chrono::duration

Java Instant 舍入到下一秒

Java 时间段(十进制年数)

java - Play 框架中的简单 ajax post 调用

java - 计算 1918-03-24 之后的天数时,Joda 时间差一错误

java - 如何修复 'com.fasterxml.jackson.databind.JsonMappingException: Problem deserializing property'错误