如何用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
相关产品推荐
相关产品推荐

