【问题标题】:Difference Between two dates in minutes - different months - Java以分钟为单位的两个日期之间的差异 - 不同的月份 - Java
【发布时间】:2017-07-06 11:27:20
【问题描述】:

我想找出两个日期之间的分钟差。如果两个日期在同一个月(和同一年),我的代码运行良好,但似乎差异认为每个月都是 31 天,因此对于日期:

 2016-02-29 12:21
 2016-03-1 12:21

我得到 4320 分钟或 72 小时

为:

 2016-04-30 12:21
 2016-05-01 12:21

我得到 2880 分钟或 48 小时

我的代码,其中 d1 和 d2 是 Date 对象:

long getDateDiff(Date d1, Date d2, TimeUnit timeUnit) {
    long diff = d2.getTime() - d1.getTime(); //in millisec
    long diffMinutes = TimeUnit.MILLISECONDS.toMinutes(diff);
    return diffMinutes;
}

【问题讨论】:

  • Java 中的Date 仅表示自纪元以来的一个时间点,因此,如果您希望两个日期之间的差异为分钟、小时或天,您当前的方法应该有效。如果你想要几个月的差异,这将需要更多的工作。
  • 您的日期可能被错误地解析或计算。 getDateDiff 对我有用,除了 timeUnit 在函数中根本没有使用。两个日期我都得到 1440。
  • 根据您的输入,您应该得到 24 小时和 24 小时,而不是 72 小时和 48 小时
  • 如何创建Date 实例?我问是因为new Date(2016, 2, 29, 12, 21) 给出的不是你期望的日期(你得到的日期是3916-03-29 12:21

标签: java date date-arithmetic


【解决方案1】:

tl;博士

解析您的输入字符串。

LocalDateTime startLdt = LocalDateTime.parse( "2016-04-30T12:21" ) ;
LocalDateTime stopLdt = LocalDateTime.parse( "2016-05-01T12:21") ;

指定时区或与 UTC 的偏移量,但在输入中省略。我假设您打算使用 UTC 本身(偏移量为零)。

OffsetDateTime start = startLdt.atOffset( ZoneOffset.UTC );
OffsetDateTime stop = stopLdt.atOffset( ZoneOffset.UTC ) ;

以天(24 小时的时间块)、小时、分钟、秒和纳秒为单位计算经过的时间。

Duration d = Duration.between( start , stop ) ;

d.toString(): PT24H

您的第一个示例结果为 24 小时,如 code runs live at IdeOne.com 所见。

您的第二个示例也是 24 小时,如 seen in IdeOne.com

详情

问题和其他答案都使用麻烦的旧日期时间类或Joda-Time 库。两者都被 java.time 类所取代。

使用 java.time

将您的 Date 对象转换为 Instant 对象,在 java.time 中等效。 Instant 类代表UTC 时间线上的时刻,分辨率为nanoseconds(最多九 (9) 位小数)。

Instant start = d1.toInstant();
Instant stop = d2.toInstant();

使用Duration(或Period)作为两者之间的时间跨度。

Duration d = Duration.between( start , stop );

提取整个时间跨度的总分钟数。

long minutes = d.toMinutes() ;

时区

您没有提及用于例如日期时间值的时区。他们的上下文是UTC 吗?或者您是否打算使用某个特定的时区。在不同的时区,夏令时 (DST) 等异常意味着日子并不总是 24 小时长。所以时区很关键。

让我们看看 UTC。

// of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneOffset offset)
OffsetDateTime odtStart1 = OffsetDateTime.of ( 2016 , 2 , 29 , 12 , 21 , 0 , 0 , ZoneOffset.UTC );
OffsetDateTime odtStop1 = OffsetDateTime.of ( 2016 , 3 , 1 , 12 , 21 , 0 , 0 , ZoneOffset.UTC );
Duration d1 = Duration.between ( odtStart1 , odtStop1 );

OffsetDateTime odtStart2 = OffsetDateTime.of ( 2016 , 4 , 30 , 12 , 21 , 0 , 0 , ZoneOffset.UTC );
OffsetDateTime odtStop2 = OffsetDateTime.of ( 2016 , 5 , 1 , 12 , 21 , 0 , 0 , ZoneOffset.UTC );
Duration d2 = Duration.between ( odtStart2 , odtStop2 );

System.out.println ( odtStart1 + "/" + odtStop1 + " = " + d1 );
System.out.println ( odtStart2 + "/" + odtStop2 + " = " + d2 );

2016-02-29T12:21Z/2016-03-01T12:21Z = PT24H

2016-04-30T12:21Z/2016-05-01T12:21Z = PT24H

toString 生成的字符串是标准的ISO 8601 format for durationsP 标志着开始,T 将任何年-月-日部分与任何小时-分钟-秒部分分开。

在这两种情况下,结果都是二十四小时。这是正确的,因为在每种情况下,您都选择从一个月的最后一天到下个月的第一天。 UTC 没有异常,因此我们预计正好经过 24 小时。

您可以通过调用compareTo 来比较Duration 对象。你可以做数学来区分它们。在这种情况下,我们期望一个不同的零。

Duration difference = d1.minus( d2 );

difference.toString(): PT0S

看到这个code run live at IdeOne.com


关于java.time

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

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

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

您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

从哪里获得 java.time 类?

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

【讨论】:

  • 提问者仍然必须正确创建 Date 对象,使用从零开始的月份,或者更好地完全避免旧的 Date 类。
【解决方案2】:

你的结果对我来说很奇怪。于是我试了一下:

    @Test
public void differenceDateTest() throws ParseException {
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm");
    Date date = dateFormat.parse("2016-02-29 12:21");
    Date date2 = dateFormat.parse("2016-03-01 12:21");
    System.out.println(date2.getTime() - date.getTime());
    long mili = date2.getTime() - date.getTime();
    System.out.println(TimeUnit.MILLISECONDS.toHours(mili)); // 24 hours.
}

它正好 24 小时返回。

【讨论】:

  • 我创建的日期错误。就像@Thomas Kläger 注意到的那样
【解决方案3】:

我认为日期对象的顺序并不重要,所以我使用了Math.abs()

public long getMinuteDifference(Date date1, Date date2) {
  long millis = Math.abs(date2.getTime() - date1.getTime());

  return TimeUnit.MILLISECONDS.toMinutes(millis);
}

此方法为您的测试用例返回 1440 分钟:

Date d1 = convert(new org.joda.time.LocalDateTime(2016, 4, 30, 12, 0, 0, 0));
Date d2 = convert(new org.joda.time.LocalDateTime(2016, 5, 1, 12, 0, 0, 1));
assertEquals(1440, getMinuteDifference(d1, d2));

Date d3 = convert(new org.joda.time.LocalDateTime(2016, 2, 29, 12, 0, 0, 0));
Date d4 = convert(new org.joda.time.LocalDateTime(2016, 3, 1, 12, 0, 0, 1));
assertEquals(1440, getMinuteDifference(d3, d4));

【讨论】:

    猜你喜欢
    • 2012-01-03
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 2012-09-20
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    相关资源
    最近更新 更多