我在Scala中使用Java的Java .util.Date类,并希望比较Date对象和当前时间。我知道我可以通过使用getTime()来计算delta:

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

然而,这只给我留下一个长表示毫秒。有没有更简单,更好的方法来得到时间?


当前回答

有很多方法可以找到日期和时间之间的区别。我所知道的最简单的方法之一是:

      Calendar calendar1 = Calendar.getInstance();
      Calendar calendar2 = Calendar.getInstance();
      calendar1.set(2012, 04, 02);
      calendar2.set(2012, 04, 04);
      long milsecs1= calendar1.getTimeInMillis();
      long milsecs2 = calendar2.getTimeInMillis();
      long diff = milsecs2 - milsecs1;
      long dsecs = diff / 1000;
      long dminutes = diff / (60 * 1000);
      long dhours = diff / (60 * 60 * 1000);
      long ddays = diff / (24 * 60 * 60 * 1000);

      System.out.println("Your Day Difference="+ddays);

打印语句只是一个示例—您可以按照自己喜欢的方式格式化它。

其他回答

我喜欢基于timeunit的方法,直到我发现它只覆盖了一个时间单元在下一个更高单位中有多少个单位是固定的这种微不足道的情况。当你想知道间隔了多少个月、多少年等时,这个问题就不成立了。

这里有一种计数方法,不像其他方法那么有效,但它似乎对我有用,而且还考虑到了夏令时。

public static String getOffsetAsString( Calendar cNow, Calendar cThen) {
    Calendar cBefore;
    Calendar cAfter;
    if ( cNow.getTimeInMillis() < cThen.getTimeInMillis()) {
        cBefore = ( Calendar) cNow.clone();
        cAfter = cThen;
    } else {
        cBefore = ( Calendar) cThen.clone();
        cAfter = cNow;
    }
    // compute diff
    Map<Integer, Long> diffMap = new HashMap<Integer, Long>();
    int[] calFields = { Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH, Calendar.HOUR_OF_DAY, Calendar.MINUTE, Calendar.SECOND, Calendar.MILLISECOND};
    for ( int i = 0; i < calFields.length; i++) {
        int field = calFields[ i];
        long    d = computeDist( cAfter, cBefore, field);
        diffMap.put( field, d);
    }
    final String result = String.format( "%dY %02dM %dT %02d:%02d:%02d.%03d",
            diffMap.get( Calendar.YEAR), diffMap.get( Calendar.MONTH), diffMap.get( Calendar.DAY_OF_MONTH), diffMap.get( Calendar.HOUR_OF_DAY), diffMap.get( Calendar.MINUTE), diffMap.get( Calendar.SECOND), diffMap.get( Calendar.MILLISECOND));
    return result;
}

private static int computeDist( Calendar cAfter, Calendar cBefore, int field) {
    cBefore.setLenient( true);
    System.out.print( "D " + new Date( cBefore.getTimeInMillis()) + " --- " + new Date( cAfter.getTimeInMillis()) + ": ");
    int count = 0;
    if ( cAfter.getTimeInMillis() > cBefore.getTimeInMillis()) {
        int fVal = cBefore.get( field);
        while ( cAfter.getTimeInMillis() >= cBefore.getTimeInMillis()) {
            count++;
            fVal = cBefore.get( field);
            cBefore.set( field, fVal + 1);
            System.out.print( count + "/"  + ( fVal + 1) + ": " + new Date( cBefore.getTimeInMillis()) + " ] ");
        }
        int result = count - 1;
        cBefore.set( field, fVal);
        System.out.println( "" + result + " at: " + field + " cb = " + new Date( cBefore.getTimeInMillis()));
        return result;
    }
    return 0;
}

博士tl;

将过时的java.util.Date对象转换为它们的替代品java.time.Instant。然后将经过的时间计算为Duration。

Duration d = 
    Duration.between(                   // Calculate the span of time between two moments as a number of hours, minutes, and seconds.
        myJavaUtilDate.toInstant() ,    // Convert legacy class to modern class by calling new method added to the old class.
        Instant.now()                   // Capture the current moment in UTC. About two and a half hours later in this example.
    )
;

d.toString (): PT2H34M56S d.toMinutes (): 154 d.toMinutesPart (): 34

ISO 8601格式:PnYnMnDTnHnMnS

明智的标准ISO 8601定义了时间跨度的简洁文本表示形式,如年、月、日、小时等。标准将这种跨度称为持续时间。格式为PnYnMnDTnHnMnS,其中P表示“周期”,T将日期部分与时间部分分开,中间是数字后面跟着一个字母。

例子:

3年6个月4天12小时30分5秒 四个半小时

java.time

java。Java 8及以后版本中内置的时间框架取代了麻烦的旧Java .util. date / Java .util。日历类。新类的灵感来自于非常成功的Joda-Time框架,该框架作为它的继承者,在概念上类似,但重新构建。由JSR 310定义。由ThreeTen-Extra项目扩展。请参阅教程。

时刻

Instant类表示UTC时间轴上的一个时刻,其分辨率为纳秒(最多为十进制分数的九(9)位)。

Instant instant = Instant.now() ;  // Capture current moment in UTC.

最好避免遗留类,如Date/Calendar。但是如果您必须与尚未更新到java的旧代码进行互操作。时间,来回转换。调用添加到旧类中的新转换方法。从java.util.Date移动到Instant,调用Date::toInstant。

Instant instant = myJavaUtilDate.toInstant() ;  // Convert from legacy `java.util.Date` class to modern `java.time.Instant` class.

时间跨度

java。时间类将这种用年、月、日、小时、分、秒来表示时间跨度的想法分为两部分:

年,月,日 持续时间为天、小时、分、秒

这里有一个例子。

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime now = ZonedDateTime.now ( zoneId );
ZonedDateTime future = now.plusMinutes ( 63 );
Duration duration = Duration.between ( now , future );

转储到控制台。

Period和Duration都使用ISO 8601标准来生成它们值的String表示形式。

System.out.println ( "now: " + now + " to future: " + now + " = " + duration );

现在:2015-11-26T00:46:48.016-05:00[美国/蒙特利尔]到未来:2015-11-26T00:46:48.016-05:00[美国/蒙特利尔]= PT1H3M

Java 9向Duration添加了一些方法,以获取日部分、小时部分、分钟部分和秒部分。

您可以在整个持续时间中获得天或小时或分钟或秒或毫秒或纳秒的总数。

long totalHours = duration.toHours();

在Java 9中,Duration类获得了用于返回日、小时、分钟、秒、毫秒/纳秒的不同部分的新方法。调用to…Part方法:toDaysPart(), toHoursPart(),等等。

ChronoUnit

如果您只关心更简单的时间粒度,比如“经过的天数”,请使用ChronoUnit enum。

long daysElapsed = ChronoUnit.DAYS.between( earlier , later );

另一个例子。

Instant now = Instant.now();
Instant later = now.plus( Duration.ofHours( 2 ) );
…
long minutesElapsed = ChronoUnit.MINUTES.between( now , later );

120


关于java.time

java。时间框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗留日期-时间类,如java.util。日期,日历和简单日期格式。

Joda-Time项目现在处于维护模式,建议迁移到java.time。

要了解更多,请参阅Oracle教程。搜索Stack Overflow可以找到很多例子和解释。规范是JSR 310。

从哪里获取java。时间类?

Java SE 8和SE 9及更高版本 内置的。 带有捆绑实现的标准Java API的一部分。 Java 9增加了一些小特性并进行了修复。 Java SE 6和SE 7 大部分的java。时间功能在ThreeTen-Backport中向后移植到Java 6和7。 安卓 ThreeTenABP项目将ThreeTen-Backport(上文提到过)专门用于Android。 参见如何使用....

ThreeTen-Extra项目扩展了java。额外的课程时间。这个项目是未来可能添加到java.time的一个试验场。你可以在这里找到一些有用的类,比如Interval、YearWeek、YearQuarter等等。


乔达时间

更新:Joda-Time项目现在处于维护模式,团队建议迁移到java。时间类。我把这部分完整地保留下来作为历史。

Joda-Time库使用ISO 8601作为默认值。它的Period类解析并生成这些PnYnMnDTnHnMnS字符串。

DateTime now = DateTime.now(); // Caveat: Ignoring the important issue of time zones.
Period period = new Period( now, now.plusHours( 4 ).plusMinutes( 30));
System.out.println( "period: " + period );

呈现:

period: PT4H30M
Days d = Days.daysBetween(startDate, endDate);
int days = d.getDays();

https://www.joda.org/joda-time/faq.html#datediff

以毫秒为单位减去日期是可行的(如另一篇文章所述),但在清除日期的时间部分时,你必须使用HOUR_OF_DAY而不是HOUR:

public static final long MSPERDAY = 60 * 60 * 24 * 1000;
...
final Calendar dateStartCal = Calendar.getInstance();
dateStartCal.setTime(dateStart);
dateStartCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateStartCal.set(Calendar.MINUTE, 0);
dateStartCal.set(Calendar.SECOND, 0);
dateStartCal.set(Calendar.MILLISECOND, 0);
final Calendar dateEndCal = Calendar.getInstance();
dateEndCal.setTime(dateEnd);
dateEndCal.set(Calendar.HOUR_OF_DAY, 0); // Crucial.
dateEndCal.set(Calendar.MINUTE, 0);
dateEndCal.set(Calendar.SECOND, 0);
dateEndCal.set(Calendar.MILLISECOND, 0);
final long dateDifferenceInDays = ( dateStartCal.getTimeInMillis()
                                  - dateEndCal.getTimeInMillis()
                                  ) / MSPERDAY;
if (dateDifferenceInDays > 15) {
    // Do something if difference > 15 days
}

在阅读了许多关于这个问题的回答和评论后,我的印象是,要么使用Joda时间,要么考虑到日光节约时间的一些特点等等。由于这两种方法我都不想做,所以我最终编写了几行代码来计算两个日期之间的差异,而没有使用任何与日期或时间相关的Java类。

在下面的代码中,年、月和日的数字与现实生活中的数字相同。例如,2015年12月24日,年= 2015,月= 12,日= 24。

我想分享这些代码,以防其他人想要使用它。有3种方法:1)找出给定年份是否是闰年的方法2)计算给定年份1月1日的天数的方法3)计算任意两个日期之间天数的方法2(结束日期减去开始日期)。

方法如下:

1)

public static boolean isLeapYear (int year) {
    //Every 4. year is a leap year, except if the year is divisible by 100 and not by 400
    //For example 1900 is not a leap year but 2000 is

    boolean result = false;

    if (year % 4 == 0) {
        result = true;
    }
    if (year % 100 == 0) {
        result = false;
    }
    if (year % 400 == 0) {
        result = true;
    }

    return result;

}

2)

public static int daysGoneSince (int yearZero, int year, int month, int day) {
    //Calculates the day number of the given date; day 1 = January 1st in the yearZero

    //Validate the input
    if (year < yearZero || month < 1 || month > 12 || day < 1 || day > 31) {
        //Throw an exception
        throw new IllegalArgumentException("Too many or too few days in month or months in year or the year is smaller than year zero");
    }
    else if (month == 4 || month == 6 || month == 9 || month == 11) {//Months with 30 days
        if (day == 31) {
            //Throw an exception
            throw new IllegalArgumentException("Too many days in month");
        }
    }
    else if (month == 2) {//February 28 or 29
        if (isLeapYear(year)) {
            if (day > 29) {
                //Throw an exception
                throw new IllegalArgumentException("Too many days in month");
            }
        }
        else if (day > 28) {
            //Throw an exception
            throw new IllegalArgumentException("Too many days in month");
        }
    }

    //Start counting days
    int days = 0;

    //Days in the target month until the target day
    days = days + day;

    //Days in the earlier months in the target year
    for (int i = 1; i < month; i++) {
        switch (i) {
            case 1: case 3: case 5:
            case 7: case 8: case 10:
            case 12:
                days = days + 31;
                break;
            case 2:
                days = days + 28;
                if (isLeapYear(year)) {
                    days = days + 1;
                }
                break;
            case 4: case 6: case 9: case 11:
                days = days + 30;
                break;
        }
    }

    //Days in the earlier years
    for (int i = yearZero; i < year; i++) {
        days = days + 365;
        if (isLeapYear(i)) {
            days = days + 1;
        }
    }

    return days;

}

3)

public static int dateDiff (int startYear, int startMonth, int startDay, int endYear, int endMonth, int endDay) {

    int yearZero;

    //daysGoneSince presupposes that the first argument be smaller or equal to the second argument
    if (10000 * startYear + 100 * startMonth + startDay > 10000 * endYear + 100 * endMonth + endDay) {//If the end date is earlier than the start date
        yearZero = endYear;
    }
    else {
        yearZero = startYear;
    }

    return daysGoneSince(yearZero, endYear, endMonth, endDay) - daysGoneSince(yearZero, startYear, startMonth, startDay);

}