如何在java.time中处理完整的句号?
java.time中的Period
类仅处理面向日期的药水:年,月,日。
时间部分怎么样:小时,分钟,秒?
我们如何解析和生成ISO 8601 , PnYnMnDTnHnMnS
定义的完整周期的字符串表示? 例如,一天半: P1DT12H
。 学年是9个月, P9M
。 P17D
,每年我都会有两周P17D
3天的假期。 客户占用了酒店房间2天和17个半小时, P2DT17H30M
。
Joda-Time中的Period
类处理完整时段。 为什么不在java.time? 还有其他一些机制吗?
在Java SE 8中,如果需要,应用程序有责任创建一个链接Period
和Duration
的类。
请注意, 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项目提供了一个结合了Period
和Duration
的课程。 简称为PeriodDuration
。
ISO-8601日历系统中结合了句点和持续时间的时间量。
此类根据期间和持续时间对数量或时间进行建模。 期间是基于日期的时间量,包括年,月和日。 持续时间是基于时间的时间量,包括秒和纳秒。 有关更多详细信息,请参阅Period和Duration类。
一段时间内的日子考虑了夏令时的变化(23或25小时)。 执行计算时,首先添加周期,然后添加持续时间。
警告:请务必阅读JodaStephen的答案,以了解尝试结合时段和Duration
所涉及的问题。 在实践中这样做很少有意义,尽管这与我们的直觉相反。