首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在YMDHMS (ISO 8601)中获得两个日期/时间之间的持续时间?

如何在YMDHMS (ISO 8601)中获得两个日期/时间之间的持续时间?
EN

Stack Overflow用户
提问于 2022-05-20 15:08:31
回答 3查看 212关注 0票数 3

给定2日期,如何以Year Month Day, Hour Minute Second格式计算它们之间的差异,按照ISO 8601持续时间计算?

我只找到了Java库,它们可以在几天或更小的时间内给出不同的结果。

考虑到月份和年份的天数不固定,我不知道如何用几个月和几年来计算出两者之间的差异。

甚至连Duration.between()都接近了,但它以小时、分钟、秒为单位给出了结果:

代码语言:javascript
复制
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秒。

我想看看这样的东西:

代码语言:javascript
复制
__ years, __ months, __ days, 9 hours, 57 minutes, 58 seconds
EN

回答 3

Stack Overflow用户

发布于 2022-05-20 16:04:37

您可以创建一个自定义类,它将维护PeriodDuration字段(因为他在评论前面提到了@Ole V.V. )。

下面是这样一个类实现的示例,它公开了一个静态方法between(),它需要两个类型为LocalDateTime的参数。

getYears()getHours()这样的方法将把调用委托给PeriodDuration对象。

代码语言:javascript
复制
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() -演示

代码语言:javascript
复制
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);
}

输出

代码语言:javascript
复制
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
票数 2
EN

Stack Overflow用户

发布于 2022-05-20 15:40:59

我相信我已经解决了:

代码语言:javascript
复制
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());

这些指纹:

代码语言:javascript
复制
P2Y10M30DPT25533H57M58S

这是2年10个月30天25533小时57分58秒

在提取单个值时(这正是我所需要的),使用模数可以用小时来解决问题:

代码语言:javascript
复制
 String.valueOf(duration.toHours() % 24)

如果有任何问题的分钟和秒,% 60将修复它。

票数 1
EN

Stack Overflow用户

发布于 2022-05-21 16:35:48

我的库Time4J支持计算和打印这样的持续时间。使用您的输入的示例:

代码语言:javascript
复制
    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

您还可以使用即时/瞬间作为输入,然后以这种方式转换为本地时间戳,如果输入发生变化(一些转换示例):

代码语言:javascript
复制
    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);
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72321174

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档