【问题标题】:Java: Difference between two dates spanning over monthsJava:跨越数月的两个日期之间的差异
【发布时间】:2013-08-17 20:45:08
【问题描述】:

我有以下代码可以成功获取两天之间的差异(以天、小时、分钟、秒为单位):

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
Date d1 = format.parse(startTime);
Date d2 = format.parse(endTime);
long diff = d2.getTime() - d1.getTime();
long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000);
System.out.println("Start: " + startTime);
System.out.println("End: " + endTime);
System.out.println(diffDays + " days, " + diffHours + " hours, " + diffMinutes + " minutes, " + diffSeconds + " seconds");

但是,当日期跨入另一个月份时,这不起作用,例如:

Start: 2013-07-31 10:15:01
End: 2013-08-01 11:22:33
-29 days, -22 hours, -52 minutes, -28 seconds

Start: 2013-05-31 10:15:01
End: 2013-08-01 11:22:33
-29 days, -22 hours, -52 minutes, -28 seconds

是否可以智能地跨越数月并获得准确的时差?我对 Joda 很熟悉,但我想坚持使用标准 Java API,除非没有 Joda 这样的东西是不可能的。

【问题讨论】:

  • 好吧,您可以重新实现 Joda Time 的大量工作 - 毕竟这并不神奇 - 但如果您使用 Joda Time 会更好很多。也就是说,在这种情况下您是否需要 Joda Time 尚不清楚-我认为您的格式化程序损坏了...

标签: java date time


【解决方案1】:

tl;博士

Java 9 及更高版本中……

Duration.between(
    LocalDateTime.parse( "2013-07-31T10:15:01" ) ,
    LocalDateTime.parse( "2013-08-01T11:22:33" )
).getDaysPart()

……和……

.getHoursPart()
.getMinutesPart()
.getSecondsPart()

java.time

其他答案已过时。 Joda-Time 项目现在处于维护模式,建议迁移到 Java 中内置的 java.time 类。

Period

Duration 类以秒和纳秒的总数表示未附加到时间线的时间跨度。这样的跨度可以解释为天数、小时数、分钟数和秒数,假设一般为 24 小时天和 60 分钟小时,因为不包括时区。

LocalDateTime start = LocalDateTime.parse( "2013-07-31T10:15:01" );
LocalDateTime stop = LocalDateTime.parse( "2013-08-01T11:22:33" );
Duration d = Duration.between( start , stop );

跨度:2013-07-31T10:15:01/2013-08-01T11:22:33

d.toString(): PT25H7M32S

这些字符串采用标准ISO 8601 格式。 PT25H7M32S 字符串使用PnYnMnDTnHnMnS 的格式,其中P 标记开始,T 将年-月-日与小时-分钟-秒分开。字符串PT25H7M32S 的意思是“二十五小时七分三十二秒”。

看到code live in IdeOne.com

在 Java 9 及更高版本(但不是 Java 8)中,这些 Duration 方法提取每个部分。

鉴于持续时间为 49H30M20.123S…

  • toDaysPart() = 2
  • toHoursPart() = 1
  • toMinutesPart() = 30
  • toSecondsPart() = 20
  • toMillisPart() = 123
  • toNanosPart() = 123000000

关于java.time

java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧日期时间类,例如 java.util.Date.Calendarjava.text.SimpleDateFormat

Joda-Time 项目现在位于maintenance mode,建议迁移到 java.time。

要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。

大部分 java.time 功能在ThreeTen-Backport 中向后移植到Java 6 和7,并进一步适应ThreeTenABP 中的Android(参见How to use…)。

ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如IntervalYearWeekYearQuartermore

【讨论】:

    【解决方案2】:

    你正在使用

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
    

    应该是

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    

    你会得到正确的结果

    Start: 2013-05-31 10:15:01
    End: 2013-08-01 11:22:33
    62 days, 1 hours, 7 minutes, 32 seconds
    

    Here's 日期模式的 javadoc。 dd 是一个月中的一天。 DD 是一年中的一天。您的 Date 对象没有按照您预期的方式进行解析。基本上,31 的年份值覆盖了月份值。

    调试器是你的朋友。

    【讨论】:

    • 天哪,我想我应该更多地关注那些 Javadocs。谢谢你的回复。
    • @Matt 当然可以。在这种情况下,最好在使用 Date(或其他)对象之前检查它们的值。
    【解决方案3】:

    虽然您应该将 Joda Time 简单地用作 更好的日期/时间 API,但我怀疑问题出在 实际上只是您错误地解析了值。使用格式字符串:

    yyyy-MM-dd HH:mm:ss
    

    ...用dd 代替DDDD 的值是“一年中的一天”,我怀疑这会造成混淆,基本上完全覆盖了月份部分。有关详细信息,请参阅SimpleDateFormat 文档。

    您可以通过在解析后打印出d1d2 来验证问题所在...

    【讨论】:

      【解决方案4】:

      我认为你应该看看 joda-time 图书馆 http://joda-time.sourceforge.net/

      Java 默认的日期实现有点糟糕,使用 joda time 你可以计算出你想要的时间间隔,并且它与 java Date 类兼容。

      http://joda-time.sourceforge.net/quickstart.html(查看间隔和时间段)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-04-07
        • 2022-10-02
        • 2014-10-12
        • 2012-09-20
        • 2011-03-20
        • 2011-06-06
        相关资源
        最近更新 更多