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

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

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


当前回答

Since dates can contain hours and minutes, final result will be rounded down, which will result in incorrect value. For example, you calculate difference between today at 22:00 p.m and day after tomorrow 00:00 a.m, so the final result will be 1, because in reality it was 1.08 or smth difference, then it gets rounded down when calling TimeUnit.MILLISECONDS.toDays(..). That's why you need to take that in account, so in my solution I subtract the remainder of milliseconds from milliseconds in a day. Additionally, if you want to count the end date, you need to +1 it.

import java.util.Date;
import java.util.concurrent.TimeUnit;

public static long getDaysBetween(Date date1, Date date2, boolean includeEndDate) {
        long millisInDay = 60 * 60 * 24 * 1000;
        long difference = Math.abs(date1.getTime() - date2.getTime());
        long add = millisInDay - (difference % millisInDay);//is used to calculate true number of days, because by default hours, minutes are also counted

        return TimeUnit.MILLISECONDS.toDays(difference + add) + (includeEndDate ? 1 : 0);
    }

测试:

Date date1 = new Date(121, Calendar.NOVEMBER, 27); //2021 Nov 27
Date date2 = new Date(121, Calendar.DECEMBER, 29); //2021 Dec 29
System.out.println( getDaysBetween(date1, date2, false) ); //32 days difference
System.out.println( getDaysBetween(date1, date2, true) ); //33 days difference

其他回答

如果你不想使用JodaTime或类似的,最好的解决方案可能是:

final static long MILLIS_PER_DAY = 24 * 3600 * 1000;
long msDiff= date1.getTime() - date2.getTime();
long daysDiff = Math.round(msDiff / ((double)MILLIS_PER_DAY));

每天的毫秒数并不总是相同的(因为日光节约时间和闰秒),但它非常接近,至少由于日光节约时间的偏差在较长时间内抵消了。因此,除法和舍入将给出正确的结果(至少只要所使用的本地日历不包含DST和闰秒以外的奇怪时间跳转)。

请注意,这仍然假设date1和date2被设置为一天中的同一时间。对于一天中的不同时间,你首先必须定义“日期差异”的含义,正如乔恩·斯基特指出的那样。

使用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));

如果你用d1和d2作为日期,最好的解决方案可能是这样的:

int days1 = d1.getTime()/(60*60*24*1000);//find the number of days since the epoch.
int days2 = d2.getTime()/(60*60*24*1000);

然后说

days2-days1

或者其他

因为您正在使用Scala,所以有一个非常好的Scala库Lamma。在南丫岛,你可以直接用-运算符减去日期

scala> Date(2015, 5, 5) - 2     // minus days by int
res1: io.lamma.Date = Date(2015,5,3)

scala> Date(2015, 5, 15) - Date(2015, 5, 8)   // minus two days => difference between two days
res2: Int = 7

博士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