计算两个Java日期实例之间的差异

501

我在Scala中使用Java的java.util.Date类,想要比较一个Date对象和当前时间。我知道可以通过使用getTime()计算时间差:

(new java.util.Date()).getTime() - oldDate.getTime()

然而,这只给我留下了一个表示毫秒的long。是否有更简单、更好的方法来获得时间差?


12
为什么joda time没有得到更多的喜爱?如果你需要处理Java中的日期,它几乎是最佳选择。 - Doctor Jones
9
请检查我优雅的两行代码解决方案,不使用Joda库并将结果以任何TimeUnit显示,详情请见https://dev59.com/c3I_5IYBdhLWcg3wBub4#10650881。 - Sebastien Lorber
8
谴责那些推荐Joda时间库而不推荐真正的Java解决方案的人... - Zizouz212
5
关于推荐Joda-Time,Java捆绑的旧日期时间类很糟糕,真的很糟糕,设计差、令人困惑且麻烦。这些类非常糟糕以至于Joda-Time成为它们的替代品并取得了巨大成功。甚至Sun/Oracle也放弃了它们,并采用了java.time包作为Java 8及更高版本的一部分。java.time类受到Joda-Time的启发。Joda-Time和java.time都由同一个人Stephen Colbourne领导。我想说,“谁要是推荐使用DateCalendarSimpleDateFormat就太不应该了”。 - Basil Bourque
4
当问题提出时,Joda Time可能是一个很好的答案,但如今对于任何能使用Java 8的人来说,最好的答案是使用java.time.Period和/或Duration。请查看下面的Basil Bourque的答案。 - Ole V.V.
显示剩余4条评论
46个回答

4

点击这里查看示例。

该示例可以给出日期之间的天数、小时数、分钟数、秒数和毫秒数 :)

import java.util.Calendar;
import java.util.Date;

public class DateDifferent {
    public static void main(String[] args) {
        Date date1 = new Date(2009, 01, 10);
        Date date2 = new Date(2009, 07, 01);
        Calendar calendar1 = Calendar.getInstance();
        Calendar calendar2 = Calendar.getInstance();
        calendar1.setTime(date1);
        calendar2.setTime(date2);
        long milliseconds1 = calendar1.getTimeInMillis();
        long milliseconds2 = calendar2.getTimeInMillis();
        long diff = milliseconds2 - milliseconds1;
        long diffSeconds = diff / 1000;
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);
        System.out.println("\nThe Date Different Example");
        System.out.println("Time in milliseconds: " + diff + " milliseconds.");
        System.out.println("Time in seconds: " + diffSeconds + " seconds.");
        System.out.println("Time in minutes: " + diffMinutes + " minutes.");
        System.out.println("Time in hours: " + diffHours + " hours.");
        System.out.println("Time in days: " + diffDays + " days.");
    }
}

3
除非这些日期实例是从UTC时间导出的,否则这是错误的。请参考Jon Skeet的答案。 - sleske

4

使用 GMT 时区获取 Calendar 实例,使用 Calendar 类的 set 方法设置时间。GMT 时区具有 0 偏移量(并不重要),并且夏令时标志设置为 false。

    final Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 9);
    cal.set(Calendar.DAY_OF_MONTH, 29);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date startDate = cal.getTime();

    cal.set(Calendar.YEAR, 2011);
    cal.set(Calendar.MONTH, 12);
    cal.set(Calendar.DAY_OF_MONTH, 21);
    cal.set(Calendar.HOUR, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    final Date endDate = cal.getTime();

    System.out.println((endDate.getTime() - startDate.getTime()) % (1000l * 60l * 60l * 24l));

不要忘记将毫秒部分清零,否则在旧类java.util.Date等情况下这是一个好的答案。使用将时区设置为GMT的技巧可以使代码对夏令时效应不敏感。 - Meno Hochschild

4
以下代码可以为您提供所需的输出:
String startDate = "Jan 01 2015";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy");
LocalDate date = LocalDate.parse(startDate, formatter);

String currentDate = "Feb 11 2015";
LocalDate date1 = LocalDate.parse(currentDate, formatter);

System.out.println(date1.toEpochDay() - date.toEpochDay());

3
你能否解释一下你的代码具体做了什么?问题似乎在询问时间差,初看你的代码似乎返回的是天数差? - GHC

3
最好的做法是:
(Date1-Date2)/86 400 000 

那个数字是一天中的毫秒数

一个日期-另一个日期会给你毫秒级别的差异。

将答案收集在一个双精度变量中。


为什么不呢?在某些方面我不理解问题的重点:OP有毫秒的差异...一天内有一定数量的毫秒(如果偶尔进行某些天文调整就可以了,但OP没有说必须与天文学家所需的精度一样...) - mike rodent

3

这里提供一种正确的Java 7解决方案,时间复杂度为O(1),不需要任何依赖。

public static int countDaysBetween(Date date1, Date date2) {

    Calendar c1 = removeTime(from(date1));
    Calendar c2 = removeTime(from(date2));

    if (c1.get(YEAR) == c2.get(YEAR)) {

        return Math.abs(c1.get(DAY_OF_YEAR) - c2.get(DAY_OF_YEAR)) + 1;
    }
    // ensure c1 <= c2
    if (c1.get(YEAR) > c2.get(YEAR)) {
        Calendar c = c1;
        c1 = c2;
        c2 = c;
    }
    int y1 = c1.get(YEAR);
    int y2 = c2.get(YEAR);
    int d1 = c1.get(DAY_OF_YEAR);
    int d2 = c2.get(DAY_OF_YEAR);

    return d2 + ((y2 - y1) * 365) - d1 + countLeapYearsBetween(y1, y2) + 1;
}

private static int countLeapYearsBetween(int y1, int y2) {

    if (y1 < 1 || y2 < 1) {
        throw new IllegalArgumentException("Year must be > 0.");
    }
    // ensure y1 <= y2
    if (y1 > y2) {
        int i = y1;
        y1 = y2;
        y2 = i;
    }

    int diff = 0;

    int firstDivisibleBy4 = y1;
    if (firstDivisibleBy4 % 4 != 0) {
        firstDivisibleBy4 += 4 - (y1 % 4);
    }
    diff = y2 - firstDivisibleBy4 - 1;
    int divisibleBy4 = diff < 0 ? 0 : diff / 4 + 1;

    int firstDivisibleBy100 = y1;
    if (firstDivisibleBy100 % 100 != 0) {
        firstDivisibleBy100 += 100 - (firstDivisibleBy100 % 100);
    }
    diff = y2 - firstDivisibleBy100 - 1;
    int divisibleBy100 = diff < 0 ? 0 : diff / 100 + 1;

    int firstDivisibleBy400 = y1;
    if (firstDivisibleBy400 % 400 != 0) {
        firstDivisibleBy400 += 400 - (y1 % 400);
    }
    diff = y2 - firstDivisibleBy400 - 1;
    int divisibleBy400 = diff < 0 ? 0 : diff / 400 + 1;

    return divisibleBy4 - divisibleBy100 + divisibleBy400;
}


public static Calendar from(Date date) {

    Calendar c = Calendar.getInstance();
    c.setTime(date);

    return c;
}


public static Calendar removeTime(Calendar c) {

    c.set(HOUR_OF_DAY, 0);
    c.set(MINUTE, 0);
    c.set(SECOND, 0);
    c.set(MILLISECOND, 0);

    return c;
}

2

鉴于该问题标记了Scala,

import scala.concurrent.duration._
val diff = (System.currentTimeMillis() - oldDate.getTime).milliseconds
val diffSeconds = diff.toSeconds
val diffMinutes = diff.toMinutes
val diffHours = diff.toHours
val diffDays = diff.toDays

2
不使用标准API,不行。您可以自己创建类似以下内容的内容:
class Duration {
    private final TimeUnit unit;
    private final long length;
    // ...
}

或者你可以使用Joda

DateTime a = ..., b = ...;
Duration d = new Duration(a, b);

2

仅回答最初的问题:

将以下代码放入一个函数中,例如Long getAge(){}

Date dahora = new Date();
long MillisToYearsByDiv = 1000l *60l * 60l * 24l * 365l;
long javaOffsetInMillis = 1990l * MillisToYearsByDiv;
long realNowInMillis = dahora.getTime() + javaOffsetInMillis;
long realBirthDayInMillis = this.getFechaNac().getTime() + javaOffsetInMillis;
long ageInMillis = realNowInMillis - realBirthDayInMillis;

return ageInMillis / MillisToYearsByDiv;

在进行乘法和除法计算时,最重要的是使用长数字。当然,在Java计算日期时应用的偏移量也很重要。

:)


2

这可能是最直接的方法 - 也许是因为我已经用Java编码(虽然它的日期和时间库确实有些笨重)有一段时间了,但那段代码看起来对我来说“简单而美好”!

你是否满意以毫秒返回结果,或者你的问题的一部分是你希望以其他格式返回结果?


2

如果您想要解决日期范围跨越夏令时边界(例如一个日期在夏季时间,另一个日期在冬季时间)的问题,您可以使用以下方法来获取天数差异

最初的回答

public static long calculateDifferenceInDays(Date start, Date end, Locale locale) {
    Calendar cal = Calendar.getInstance(locale);

    cal.setTime(start);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    long startTime = cal.getTimeInMillis();

    cal.setTime(end);
    cal.set(Calendar.HOUR_OF_DAY, 0);
    cal.set(Calendar.MINUTE, 0);
    cal.set(Calendar.SECOND, 0);
    cal.set(Calendar.MILLISECOND, 0);
    long endTime = cal.getTimeInMillis();

    // calculate the offset if one of the dates is in summer time and the other one in winter time
    TimeZone timezone = cal.getTimeZone();
    int offsetStart = timezone.getOffset(startTime);
    int offsetEnd = timezone.getOffset(endTime);
    int offset = offsetEnd - offsetStart;

    return TimeUnit.MILLISECONDS.toDays(endTime - startTime + offset);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接