将time4j持续时间<isounit>从P365D转换为P1Y等

时间:2019-05-21 14:48:39

标签: java duration time4j

Instant i1 = Instant.now();
Instant i2 = Instant.now().plusSeconds(60 * 60 * 24 * 365);
Duration<IsoUnit> dur = Duration.from((TemporalAmount) java.time.Duration.between(i1, i2));
System.out.println(dur);

此代码打印出P365D,是否有办法使单元填满下一个更大的单元,所以就变成P1Y,如果我喜欢P334D到P11M,依此类推?

time4j版本为4.38

2 个答案:

答案 0 :(得分:2)

其他评论和答案完全正确,可以说一年并不总是等于365天。

Time4J方法net.time4j.Duration.from(TemporalAmount)使用STD_PERIOD作为归一化器返回归一化的持续时间。该规范化工具的文档说:

  

基于1年= 12个月和1标准化持续时间项目   天= 24小时和1小时= 60分钟和1分钟= 60秒-   无需将天数转换为几个月。

因此,当您以以秒为单位定义的时间量开始时,只能期望结果以天为单位。

如果您仍然想要一年,那么建议您首先使用适当的时区将时间转换为日历日期。但是在leap年中,您的代码在将60 * 60 * 24 * 365秒添加到第二瞬间后仍将产生365天,而不是一年。因此,您添加的秒数也是有缺陷的,因为它是基于错误的假设。

旁注:

如果您想要相反的方式,即一年中有几秒钟,则可以使用类似的代码

Moment m1 = Moment.nowInSystemTime();
Moment m2 = m1.toZonalTimestamp(ZonalOffset.UTC).plus(1, CalendarUnit.YEARS).atUTC();
long seconds = SI.SECONDS.between(m1, m2); // = 366 days in seconds if applied on date 2019-05-22!

有了Time4J的未来版本,并可能在2019年底跳秒,代码甚至可能会产生额外的秒。

无论如何,我建议您将Time4J更新到v5.4,并考虑以下映射:

java.time.Instant as input => net.time4j.MachineTime.from(...)
java.time.LocalDateTime/net.time4j.PlainTimestamp => net.time4j.Duration.from(...)

因此,如果您真的希望在打印持续时间中尽可能多地输出年份,并且有瞬间/力矩,那么在创建适当的持续时间对象之前,请先转换为LocalDateTime / PlainTimestamp(使用时区或偏移量)。

从2019-05-25更新:

版本v5.4(或更高版本)的另一种方式是通过“模糊”持续时间实现。您可以通过应用近似值来标准化持续时间。示例:

    Duration<IsoUnit> d = Duration.of(60 * 60 * 24 * 365, ClockUnit.SECONDS);
    d = d.with(Duration.approximateMaxUnitOnly());
    System.out.println(d); // P1Y

由于这种归一化的性质,您无法期望确切的结果。

答案 1 :(得分:1)

一年没有固定的秒数:

  1. Le年又是2月29日的一天
  2. 有时会添加
  3. Leap seconds

由于上述原因,您必须知道一年中有几秒钟。似乎应该使用InstantDuration来代替LocalDatePeriod(至少在使用java.time时):

LocalDate d1 = LocalDate.now();
LocalDate d2 = d1.plusYears(1);
Period p = Period.between(d1, d2);
System.out.println(p); // P1Y