如何在java.time中处理完整的句号?

java.time中的Period类仅处理面向日期的药水:年,月,日。

时间部分怎么样:小时,分钟,秒?

我们如何解析和生成ISO 8601 , PnYnMnDTnHnMnS定义的完整周期的字符串表示? 例如,一天半: P1DT12H 。 学年是9个月, P9MP17D ,每年我都会有两周P17D 3天的假期。 客户占用了酒店房间2天和17个半小时, P2DT17H30M

Joda-Time中的Period类处理完整时段。 为什么不在java.time? 还有其他一些机制吗?

在Java SE 8中,如果需要,应用程序有责任创建一个链接PeriodDuration的类。

请注意, Duration包含秒数,而不是单独的秒数,分钟数和小时数。 秒数可以超过24小时,因此Duration可以代表“日”。 但这是一个固定的24小时工作日。 相比之下,“ Period日”的表示是描述性的并且考虑了DST。期间的状态由三个单独的字段组成 – 日,月和年。

请记住,“客户占用酒店房间2天17个半小时,P2DT17H30M”有可能因DST切换而变得复杂。 事情很清楚 – Period受DST切换影响而Duration不受影响。

在设计方面,原始java.time Period确实包括小时,分钟和秒。 然而,这导致需要许多方法和复杂的Javadoc来描述规范化和DST周围的所有可能性。 通过分离概念,每个概念与时间线的相互作用更加清晰。 请注意,这两个类还与SQL设计(“年度到月份”和“从天到秒”的概念)有关。

目前没有计划在此领域为Java SE 9添加新类,但是不能完全排除它,因为XML / ISO-8601允许单个组合表示。

java.time (JSR-310)相关的简短回答:

不,该套餐不提供解决方案。

或者,您可以使用包javax.xml.datatype的类Duration来解析字符串,如PnYnMnDTnHnMnS 。 自Java-5以来,这也可用于较旧的JDK版本。 例:

 // parsing String iso = "P2Y4M30DT17H5M57.123S"; javax.xml.datatype.Duration xmlDuration = DatatypeFactory.newInstance().newDuration(iso); int years = xmlDuration.getYears(); int months = xmlDuration.getMonths(); int days = xmlDuration.getDays(); int hours = xmlDuration.getHours(); int minutes = xmlDuration.getMinutes(); int fullSeconds = xmlDuration.getSeconds(); BigDecimal seconds = (BigDecimal) xmlDuration.getField(DatatypeConstants.SECONDS); // generating ISO-string String xml = xmlDuration.toString(); System.out.println(xml); // P2Y4M30DT17H5M57.123S 

如果您要求限制/问题,那么您将获得一个列表:

  • 某些(替代)ISO格式如P0001-04-20T4H无法解析。

  • javax.xml.datatype.Duration定义的某些方法依赖于内部Calendar -instance(已记录),因此如果Duration的实例包含非常大的值,则这些方法可能不起作用。

  • 如果在Calendar -instance上运行,使用小数秒可能很笨拙,有时精度有限。

  • 使用Calendar -instance只有一种规范化方法。 至少这种方法以标准方式考虑DST效应。

  • 不提供格式化(甚至不提及本地化打印)。

如果你想克服这些问题那么你可以考虑一个外部库(是的,我不仅仅考虑Joda-Time的精度受限于毫秒,而且其国际化也是有限的)。 否则,包javax.xml.datatype的优点是可以节省将外部库嵌入类路径的工作量。

更新:

关于与外部库相关的评论中的问题,我知道Joda-Time和我的库Time4J。

第一个( Joda-Time )提供了一个名为ISOPeriodFormat的特殊类。 这个类还能够解析其他ISO格式(尽管原始ISO-8601-paper中没有提到PyyyyWwwddThhmmss,但缺少对PYYYY-DDD的支持)。 Joda-Time为期间格式化程序定义了构建器驱动的方法,该方法也可用于打印持续时间(句点)。 此外,对本地化打印的支持有限(使用13种语言的Joda-Time版本2.9.3)。 最后,类Period提供了各种规范化方法(参见javadoc )。

第二个( Time4J )提供了net.time4j.Duration类和两个格式化工具(用于基于模式的打印/解析的Duration.Formatter和用于实际78种语言的本地化打印的net.time4j.PrettyTime )。 类Duration用于解析ISO字符串静态方法parsePeriod(String)以及各种规范化方法。 与java.time (JSR-310)的互操作性示例,certificate可以将此库视为新java-8-date-time-api的强大扩展:

 // input: using java.time-package LocalDateTime start = LocalDateTime.of(2016, 3, 7, 10, 15, 8); LocalDateTime stop = LocalDateTime.of(2016, 6, 1, 22, 15); // define how you measure the duration (zone correction would also be possible) Duration duration = TimestampInterval.between(start, stop).getDuration( CalendarUnit.YEARS, CalendarUnit.MONTHS, CalendarUnit.DAYS, ClockUnit.HOURS, ClockUnit.MINUTES, ClockUnit.SECONDS ); // generate standard ISO-representation String s = duration.toStringISO(); System.out.println(s); // P2M25DT11H59M52S // parse ISO-String and prove equality with original System.out.println(Duration.parsePeriod(s).equals(duration)); // true // adding duration to  yields  System.out.println(start.plus(duration.toTemporalAmount())); // 2016-06-01T22:15 // format in human time System.out.println(PrettyTime.of(Locale.US).print(duration)); // output: 2 months, 25 days, 11 hours, 59 minutes, and 52 seconds 

为了完整性我还应该提到ocpsoft.PrettyTime,但我不确定该库是否能够处理ISO字符串。 它专为相对时间而设计。

org.threeten.extra.PeriodDuration

ThreeTen-Extra项目提供了一个结合了PeriodDuration的课程。 简称为PeriodDuration

ISO-8601日历系统中结合了句点和持续时间的时间量。

此类根据期间和持续时间对数量或时间进行建模。 期间是基于日期的时间量,包括年,月和日。 持续时间是基于时间的时间量,包括秒和纳秒。 有关更多详细信息,请参阅Period和Duration类。

一段时间内的日子考虑了夏令时的变化(23或25小时)。 执行计算时,首先添加周期,然后添加持续时间。

警告:请务必阅读JodaStephen的答案,以了解尝试结合时段和Duration所涉及的问题。 在实践中这样做很少有意义,尽管这与我们的直觉相反。