我不确定我是否在Java Period
和Duration
之间获得了微妙之处。
当我阅读甲骨文的explanation时,它说我可以找出自生日以来多少天(使用他们使用的示例日期):
LocalDate today = LocalDate.now();
LocalDate birthday = LocalDate.of(1960, Month.JANUARY, 1);
Period birthdayPeriod = Period.between(birthday, today);
int daysOld = birthdayPeriod.getDays();
但正如他们所指出的那样,这并没有考虑到你出生的时区和你现在的时区。但这是一台电脑,我们可以准确,对吗?那么我会使用Duration
吗?
ZoneId bornIn = ZoneId.of("America/New_York");
ZonedDateTime born = ZonedDateTime.of(1960, Month.JANUARY.getValue(), 1, 2, 34, 56, 0, bornIn);
ZonedDateTime now = ZonedDateTime.now();
Duration duration = Duration.between(born, now);
long daysPassed = duration.toDays();
现在实际时间是准确的,但如果我理解正确,那么日期可能无法正确表示日历日,例如与DST等。
那我该怎么做才能根据我的时区得到一个精确的答案?我唯一能想到的是回到使用LocalDate
,但首先从ZonedDateTime
值开始标准化时区,然后使用Duration
。
ZoneId bornIn = ZoneId.of("America/New_York");
ZonedDateTime born = ZonedDateTime.of(1960, Month.JANUARY.getValue(), 1, 2, 34, 56, 0, bornIn);
ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime nowNormalized=now.withZoneSameInstant(born.getZone());
Period preciseBirthdayPeriod = Period.between(born.toLocalDate(), nowNormalized.toLocalDate());
int preciseDaysOld = preciseBirthdayPeriod.getDays();
但为了得到准确答案,这看起来真的很复杂。
答案 0 :(得分:5)
您对Java-8课程Period
和Duration
的分析或多或少是正确的。
java.time.Period
仅限于日历日期精确度。java.time.Duration
仅处理第二(和纳秒)精度但处理天数始终相当于24小时= 86400秒。 通常在计算人的年龄时忽略时钟精度或时区是完全足够的因为护照等个人文件没有记录某人出生时的确切时间。如果是这样,那么Period
- 类就可以完成它的工作(但是请小心处理getDays()
之类的方法 - 见下文)。
但是你需要更高的精确度并根据考虑时区的本地字段描述结果。嗯,第一部分(精度)由Duration
支持,但不是第二部分一部分。
使用Period
也没有帮助,因为确切的时差(Period
忽略)可能会影响天数增量。此外(只打印代码的输出):
Period preciseBirthdayPeriod =
Period.between(born.toLocalDate(), nowNormalized.toLocalDate());
int preciseDaysOld = preciseBirthdayPeriod.getDays();
System.out.println(preciseDaysOld); // 13
System.out.println(preciseBirthdayPeriod); // P56Y11M13D
正如您所看到的,使用方法preciseBirthdayPeriod.getDays()
以获得以天为单位的总增量非常危险。不,它只是总delta的部分数量。还有11个月和56年。我认为不仅在几天内打印三角洲也是明智的,因为人们可以更容易地想象三角洲有多大(参见经常看到的打印持续时间的用例)社交媒体,如“3年,2个月,4天”)。
显然,您需要一种方法来确定持续时间,包括日历单位以及特殊时区的时钟单位(在您的示例中:某人出生的时区)。 Java-8-time-library的坏处是:它不支持Period
和Duration
的任何组合。导入外部库Threeten-Extra-class Interval
也无济于事,因为long daysPassed = interval.toDuration().toDays();
仍会忽略时区效应(1天== 24小时),也无法在其他单位中打印delta像几个月等。
<强>要点:强>
您已尝试Period
- 解决方案。 @swiedsw给出的答案尝试了基于Duration
的解决方案。两种方法在精度方面都有缺点。您可以尝试在实现TemporalAmount
的新类中组合这两个类,并自己实现必要的时间算法(不是那么简单)。
旁注:
我已经在我的时间库Time4J中实现了您所寻找的内容,因此它可能对您自己的实现有所帮助。例如:
Timezone bornZone = Timezone.of(AMERICA.NEW_YORK);
Moment bornTime =
PlainTimestamp.of(1960, net.time4j.Month.JANUARY.getValue(), 1, 22, 34, 56).in(
bornZone
);
Moment currentTime = Moment.nowInSystemTime();
MomentInterval interval = MomentInterval.between(bornTime, currentTime);
MachineTime<TimeUnit> mt = interval.getSimpleDuration();
System.out.println(mt); // 1797324427.356000000s [POSIX]
net.time4j.Duration<?> duration =
interval.getNominalDuration(
bornZone, // relevant if the moments are crossing a DST-boundary
CalendarUnit.YEARS,
CalendarUnit.MONTHS,
CalendarUnit.DAYS,
ClockUnit.HOURS,
ClockUnit.MINUTES
);
// P56Y11M12DT12H52M (12 days if the birth-time-of-day is after current clock time)
// If only days were specified above then the output would be: P20801D
System.out.println(duration);
System.out.println(duration.getPartialAmount(CalendarUnit.DAYS)); // 12
这个例子也证明了我的一般态度,即使用像月,日,小时等单位并不是严格意义上的确切。唯一严格精确的方法(从科学的角度来看)将使用十进制秒内的机器时间(最好在SI秒内,也可能在1972年之后的Time4J中使用)。
答案 1 :(得分:3)
Period
的JavaDoc声明它的模型:
ISO-8601日历系统中基于日期的时间量,例如“2年,3个月和4天”。
我知道它没有提及时间点。
您可能需要检查项目Interval
中的ThreeTen-Extra模型:
两个时刻之间不可变的时间间隔。
项目网站称该项目“[...]由Java 8日期和时间库的主要作者Stephen Colebourne策划。”
您可以通过在Interval上调用toDuration()
来检索Duration
。
我将转换你的代码给出一个例子:
ZoneId bornIn = ZoneId.of("America/New_York");
ZonedDateTime born = ZonedDateTime.of(1960, Month.JANUARY.getValue(), 1, 2, 34, 56, 0, bornIn);
ZonedDateTime now = ZonedDateTime.now();
Interval interval = Interval.of(born.toInstant(), now.toInstant());
long daysPassed = interval.toDuration().toDays();
答案 2 :(得分:0)
两个类之间的主要区别是:
java.time.Period
使用基于日期的值(2018年5月31日)java.time.Duration
更精确,但它使用基于时间的值(“2018-05-31T11:45:20.223Z”)答案 3 :(得分:0)
java.time.Period
更适合人类阅读
java.time.Duration
用于机器。