You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java日期时间API计算含时分秒的跨多单位相对日期时间差

需求:计算跨多单位的日期时间差(含年月时分秒,遵循罗马日历规则)

核心需求

  • 计算两个带具体时间的日期之间的时长,需包含年、月、日、时、分、秒多单位
  • 差值要遵循罗马日历的月份规则(例如1月2日的2个月后为3月2日,而非固定60天后的3月3日)
  • 示例:起始日期3月2日13:00,结束日期5月3日14:00,期望结果为“剩余2个月1天1小时X分钟X秒”

关键要求:月份计算规则

需严格按照罗马日历的月份天数定义计算剩余月份数,不能将“N个月”等价为固定天数。

现有尝试与问题

已知Period类仅能计算日期维度(年、月、日),完全忽略时间部分;Duration类仅能处理时间维度(日、时、分、秒),无法获取月份信息。其他方法只能返回单一单位的结果,无法满足多单位、兼顾月份规则的需求。

测试代码

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;

public class Countdown {

    private DateTimeFormatter dateTimeFormat;

    private ZonedDateTime currentZDT;
    private ZonedDateTime endZDT;

    public Countdown() {

        dateTimeFormat = DateTimeFormatter.ofPattern("EEEE, LLLL dd, yyyy, 'at' hh:mm a");

        setDateTimes(2025, Month.JUNE, 5, 2, 36); // June 5th, 2025, at 2:36 AM

        System.out.println(String.format("%-45s%s", "Current date/time:", currentZDT.format(dateTimeFormat)));
        System.out.println(String.format("%-45s%s", "End event date/time:", endZDT.format(dateTimeFormat)));

        System.out.println();

        System.out.println(String.format("%-45s%s", "Elapsed Time using ChronoUnit:", remainingDays1()));
        System.out.println(String.format("%-45s%s", "Elapsed Time using: ZonedDateTime.until():", remainingDays2()));
        System.out.println(String.format("%-45s%s", "Elapsed Time using the Duration Class:", remainingTimeDuration()));
        System.out.println(String.format("%-45s%s", "Elapsed Time using the Period Class:", remainingTimePeriod()));

    }

    private void setDateTimes(int endYear, Month endMonth, int endDOM /* Day of Month */,
            int endHour /* In 24-hour format */, int endMinute) {

        ZoneId currentZone = ZoneId.systemDefault();

        currentZDT = Instant.now().atZone(currentZone);

        LocalDate endDate = LocalDate.of(endYear, endMonth, endDOM);
        LocalTime endTime = LocalTime.of(endHour, endMinute);

        endZDT = ZonedDateTime.of(endDate, endTime, currentZone);

    }

    // 返回部分所需结果
    public String remainingTimePeriod() {

        /*
         * Period 会考虑不同月份的天数差异
         * 但完全忽略当前和结束时间的时分秒部分
         */
        Period per = Period.between(LocalDate.from(currentZDT), LocalDate.from(endZDT));

        int days = per.getDays();
        int months = per.getMonths();
        int years = per.getYears();

        return String.format("%d year(s), %d month(s), and %d day(s)", years, months, days);

    }

    // 返回另一部分所需结果
    public String remainingTimeDuration() {

        // Duration 无法获取月份信息
        Duration dur = Duration.between(currentZDT, endZDT);

        long days = dur.toDaysPart();
        long hours = dur.toHoursPart();
        long minutes = dur.toMinutesPart();
        long seconds = dur.toSecondsPart();

        return String.format("%02d day(s), %02d hour(s), %02d minute(s), and %02d second(s) left", days, hours, minutes,
                seconds);

    }

    /*
     * 以下方法仅能返回单一单位的总时长,无法拆分到多单位
     */

    public long remainingDays1() {
        return ChronoUnit.DAYS.between(currentZDT, endZDT);
    }

    public long remainingDays2() {
        return currentZDT.until(endZDT, ChronoUnit.DAYS);
    }

}

测试输出

输出1:结束时间晚于当前时间1分钟

Current date/time:                           Sunday, May 04, 2025, at 02:37 AM
End event date/time:                         Thursday, June 05, 2025, at 02:38 AM

Elapsed Time using ChronoUnit:               32
Elapsed Time using: ZonedDateTime.until():   32
Elapsed Time using the Duration Class:       32 day(s), 00 hour(s), 00 minute(s), and 31 second(s) left
Elapsed Time using the Period Class:         0 year(s), 1 month(s), and 1 day(s)

输出2:结束时间早于当前时间1分钟

Current date/time:                           Sunday, May 04, 2025, at 02:37 AM
End event date/time:                         Thursday, June 05, 2025, at 02:36 AM

Elapsed Time using ChronoUnit:               31
Elapsed Time using: ZonedDateTime.until():   31
Elapsed Time using the Duration Class:       31 day(s), 23 hour(s), 58 minute(s), and 21 second(s) left
Elapsed Time using the Period Class:         0 year(s), 1 month(s), and 1 day(s)

问题总结

  • Period类计算的日期差不会随时间变化,但完全忽略时分秒部分
  • Duration类能精确计算时分秒,但无法处理月份,且日期按固定天数计算
  • 其他方法仅能返回单一单位结果,无法满足多单位、兼顾月份规则的需求

内容的提问来源于stack exchange,提问作者Rohan Prabhala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 04:39:50