给定2日期,如何以Year Month Day, Hour Minute Second格式计算它们之间的差异,按照ISO 8601持续时间计算?
我只找到了Java库,它们可以在几天或更小的时间内给出不同的结果。
考虑到月份和年份的天数不固定,我不知道如何用几个月和几年来计算出两者之间的差异。
甚至连Duration.between()都接近了,但它以小时、分钟、秒为单位给出了结果:
ZonedDateTime event1 = ZonedDateTime.of(2022, 2, 2, 2, 2, 2, 0, ZoneId.of("UTC-7"));
ZonedDateTime event2 = ZonedDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC-7"));
//ZonedDateTime now = ZonedDateTime.now(ZoneId.of("UTC-7"));
Duration duration = Duration.between(event1, event2);
Log.d("Duration ISO-8601: ", duration.toString());
Output: PT25533H57M58S这是25533小时,57分钟,58秒。
我想看看这样的东西:
__ years, __ months, __ days, 9 hours, 57 minutes, 58 seconds发布于 2022-05-20 16:04:37
您可以创建一个自定义类,它将维护Period和Duration字段(因为他在评论前面提到了@Ole V.V. )。
下面是这样一个类实现的示例,它公开了一个静态方法between(),它需要两个类型为LocalDateTime的参数。
像getYears()和getHours()这样的方法将把调用委托给Period和Duration对象。
class DateTimeSlot {
private Period period;
private Duration duration;
private DateTimeSlot(Period period, Duration duration) {
this.period = period;
this.duration = duration;
}
public int getYears() {
return period.getYears();
}
public int getMonth() {
return period.getMonths();
}
public int getDays() {
return period.getDays();
}
public int getHours() {
return duration.toHoursPart(); // this method can be safely used instead `toHours()` because `between()` implementation guerantees that duration will be less than 24 hours
}
public int getMinutes() {
return duration.toMinutesPart();
}
public int getSeconds() {
return (int) (duration.getSeconds() % 60);
}
public static DateTimeSlot between(LocalDateTime from, LocalDateTime to) {
if (from.isAfter(to) || from.equals(to)) {
throw new IllegalArgumentException();
}
Duration duration;
Period period;
if (from.toLocalTime().isBefore(to.toLocalTime())) {
duration = Duration.between(from.toLocalTime(), to.toLocalTime());
period = Period.between(from.toLocalDate(), to.toLocalDate());
} else {
duration = Duration.between(to.withHour(from.getHour())
.withMinute(from.getMinute())
.withSecond(from.getSecond())
.minusDays(1), to); // apply shift one day back
period = Period.between(from.toLocalDate()
.plusDays(1), to.toLocalDate()); // apply shift one day forward (to compensate the previous shift)
}
return new DateTimeSlot(period, duration);
}
@Override
public String toString() {
return String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",
getYears(), getMonth(), getDays(), getHours(), getMinutes(), getSeconds());
}
}main() -演示
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.of(2022, 5, 20, 18, 0, 18);
LocalDateTime withTimeBefore = LocalDateTime.of(2020, 12, 31, 15, 9, 27);
LocalDateTime withTimeAfter = LocalDateTime.of(2020, 12, 31, 22, 50, 48);
DateTimeSlot slot1 = DateTimeSlot.between(withTimeBefore, now);
DateTimeSlot slot2 = DateTimeSlot.between(withTimeAfter, now);
System.out.println(slot1);
System.out.println(slot2);
}输出
1 years, 4 months, 20 days, 2 hours, 50 minutes, 51 seconds // between 2020-12-31T15:09:27 and 2022-05-20T18:00:18
1 years, 4 months, 19 days, 19 hours, 9 minutes, 30 seconds // between 2020-12-31T22:50:48 and 2022-05-20T18:00:18发布于 2022-05-20 15:40:59
我相信我已经解决了:
ZonedDateTime event1 = ZonedDateTime.of(2022, 2, 2, 2, 2, 2, 0, ZoneId.of("UTC-7"));
ZonedDateTime event2 = ZonedDateTime.of(2025, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC-7"));
Duration duration = Duration.between(event1, event2);
Period period = Period.between(event1.toLocalDate(), event2.toLocalDate());
Log.d("Duration ISO-8601: ", period.toString() + duration.toString());这些指纹:
P2Y10M30DPT25533H57M58S这是2年10个月30天25533小时57分58秒
在提取单个值时(这正是我所需要的),使用模数可以用小时来解决问题:
String.valueOf(duration.toHours() % 24)如果有任何问题的分钟和秒,% 60将修复它。
发布于 2022-05-21 16:35:48
我的库Time4J支持计算和打印这样的持续时间。使用您的输入的示例:
PlainTimestamp event1 = PlainTimestamp.of(2022, 2, 2, 2, 2, 2);
PlainTimestamp event2 = PlainTimestamp.of(2025, 1, 1, 0, 0, 0);
TZID tzid = ZonalOffset.ofHours(OffsetSign.BEHIND_UTC, 7);
Duration<IsoUnit> duration =
Duration.in(
Timezone.of(tzid),
CalendarUnit.YEARS,
CalendarUnit.MONTHS,
CalendarUnit.DAYS,
ClockUnit.HOURS,
ClockUnit.MINUTES,
ClockUnit.SECONDS)
.between(event1, event2);
System.out.println(PrettyTime.of(Locale.US).print(duration));
// 2 years, 10 months, 29 days, 21 hours, 57 minutes, and 58 seconds一个很大的优势是在这里输出的国际化很好,包括语言相关的复数规则,也见javadoc。
您还可以使用即时/瞬间作为输入,然后以这种方式转换为本地时间戳,如果输入发生变化(一些转换示例):
tzid = () -> "America/Chicago"; // probably better than your fixed offset
event1 = TemporalType.LOCAL_DATE_TIME.translate(LocalDateTime.of(2022, 2, 2, 2, 2, 2));
event2 = Moment.nowInSystemTime().toZonalTimestamp(tzid);https://stackoverflow.com/questions/72321174
复制相似问题