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

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

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

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

756467 次浏览

不使用标准API,不行。你可以这样做:

class Duration {
private final TimeUnit unit;
private final long length;
// ...
}

或者你可以使用Joda:

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

JDK Date API不幸被严重破坏了。我建议使用Joda时间库

Joda Time有一个时间概念时间间隔:

Interval interval = new Interval(oldTime, new Instant());

编辑:顺便说一下,Joda有两个概念:Interval表示两个时间瞬间之间的时间间隔(表示上午8点到上午10点之间的时间),Duration表示没有实际时间边界的时间长度(例如表示两个小时!)

如果你只关心时间比较,大多数Date实现(包括JDK实现)实现了Comparable接口,该接口允许你使用Comparable.compareTo()

看看Joda的时间,它是一个改进的Java日期/时间API,应该可以很好地与Scala一起工作。

这可能是最直接的方法了——也许是因为我已经用Java编写了一段时间了(它的日期和时间库确实很笨拙),但对我来说,代码看起来“简单而漂亮”!

您是否对以毫秒为单位返回的结果感到满意,或者您的问题的一部分是希望以某种替代格式返回?

一个稍微简单一点的选择:

System.currentTimeMillis() - oldDate.getTime()

至于“更好”,你到底需要什么?将时间持续时间表示为小时数和天数等的问题是,由于日期的复杂性,它可能导致不准确和错误的期望(例如,由于夏令时,一天可能有23或25小时)。

你需要更清楚地定义你的问题。你可以只需要取两个Date对象之间的毫秒数,然后除以24小时内的毫秒数,例如…但是:

  • 这将不考虑时区- Date始终是UTC
  • 这并没有考虑到日光节约时间(例如,有些日子可能只有23小时)
  • 即使在UTC时间内,8月16日晚上11点到8月18日凌晨2点有多少天?只有27个小时,那意味着一天吗?还是应该是三天,因为它涵盖了三个日期?

只需要对每个函数调用getTime,取其差值,然后除以一天中的毫秒数。

int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;

如果你用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

或者其他

请看下面的例子http://www.roseindia.net/java/beginners/DateDifferent.shtml 这个例子给出了天、小时、分钟、秒和毫厘秒的差异:)

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.");
}
}
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime())
/ (1000 * 60 * 60 * 24) )

请注意,这适用于UTC日期,因此如果查看本地日期,差异可能会减小一天。由于夏时制的原因,要让它在本地日期上正确工作,需要一种完全不同的方法。

如果你不想使用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和闰秒以外的奇怪时间跳转)。

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

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

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

在某些地区使用毫秒方法可能会导致问题。

举个例子,03/24/2007和03/25/2007之间的差应该是1天;

然而,如果使用毫秒路径,你将得到0天,如果你在英国运行这个!

/** Manual Method - YIELDS INCORRECT RESULTS - DO NOT USE**/
/* This method is used to find the no of days between the given dates */
public long calculateDays(Date dateEarly, Date dateLater) {
return (dateLater.getTime() - dateEarly.getTime()) / (24 * 60 * 60 * 1000);
}

更好的实现方法是使用java.util.Calendar

/** Using Calendar - THE CORRECT WAY**/
public static long daysBetween(Calendar startDate, Calendar endDate) {
Calendar date = (Calendar) startDate.clone();
long daysBetween = 0;
while (date.before(endDate)) {
date.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween;
}

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

让我来看看Joda Interval和Days之间的差异:

DateTime start = new DateTime(2012, 2, 6, 10, 44, 51, 0);
DateTime end = new DateTime(2012, 2, 6, 11, 39, 47, 1);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();
System.out.println(period.getYears() + " years, " + period.getMonths() + " months, " + period.getWeeks() + " weeks, " + period.getDays() + " days");
System.out.println(period.getHours() + " hours, " + period.getMinutes() + " minutes, " + period.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *1 weeks, 1 days*
//0 hours, 54 minutes, 56 seconds


//Period can set PeriodType,such as PeriodType.yearMonthDay(),PeriodType.yearDayTime()...
Period p = new Period(start, end, PeriodType.yearMonthDayTime());
System.out.println(p.getYears() + " years, " + p.getMonths() + " months, " + p.getWeeks() + " weeks, " + p.getDays() + "days");
System.out.println(p.getHours() + " hours, " + p.getMinutes() + " minutes, " + p.getSeconds() + " seconds ");
//Result is:
//0 years, 0 months, *0 weeks, 8 days*
//0 hours, 54 minutes, 56 seconds

以下是一种解决方案,因为我们有许多方法可以实现这一点:

  import java.util.*;
int syear = 2000;
int eyear = 2000;
int smonth = 2;//Feb
int emonth = 3;//Mar
int sday = 27;
int eday = 1;
Date startDate = new Date(syear-1900,smonth-1,sday);
Date endDate = new Date(eyear-1900,emonth-1,eday);
int difInDays = (int) ((endDate.getTime() - startDate.getTime())/(1000*60*60*24));

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

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

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

简单的diff(不含lib)

/**
* Get a diff between two dates
* @param date1 the oldest date
* @param date2 the newest date
* @param timeUnit the unit in which you want the diff
* @return the diff value, in the provided unit
*/
public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
long diffInMillies = date2.getTime() - date1.getTime();
return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
}

然后你可以调用:

getDateDiff(date1,date2,TimeUnit.MINUTES);

以分钟为单位获取两个日期的差值。

TimeUnitjava.util.concurrent.TimeUnit,一个从纳米到天的标准Java枚举。


人类可读的差异(不含lib)

public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) {


long diffInMillies = date2.getTime() - date1.getTime();


//create the list
List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class));
Collections.reverse(units);


//create the result map of TimeUnit and difference
Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>();
long milliesRest = diffInMillies;


for ( TimeUnit unit : units ) {


//calculate difference in millisecond
long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS);
long diffInMilliesForUnit = unit.toMillis(diff);
milliesRest = milliesRest - diffInMilliesForUnit;


//put the result in the map
result.put(unit,diff);
}


return result;
}

http://ideone.com/5dXeu6

输出类似Map:{DAYS=1, HOURS=3, MINUTES=46, SECONDS=40, MILLISECONDS=0, MICROSECONDS=0, NANOSECONDS=0},单位是有序的。

您只需将该映射转换为用户友好的字符串。


警告

上面的代码段计算两个瞬间之间的简单差。它可能会在夏令时切换期间导致问题,如这篇文章中解释的那样。这意味着如果你计算没有时间的日期之间的差异,你可能会少了一天/小时。

在我看来,日期的差异是主观的,尤其是在日子上。你可以:

  • 计算经过24小时的时间:day+1 - day = 1 day = 24h

  • 计算经过的时间,考虑到夏令时:天+1 -天= 1 = 24小时(但使用午夜时间和夏令时,它可以是0天和23小时)

  • 计算day switches的个数,这意味着day+1 1pm - day 11am = 1天,即使经过的时间只有2h(如果有夏令时则为1h:p)

我的答案是有效的,如果你的日期差异的定义天匹配第一种情况

与JodaTime

如果你正在使用JodaTime,你可以得到2个瞬间的差异(millies支持ReadableInstant)日期:

Interval interval = new Interval(oldInstant, new Instant());

但是你也可以得到本地日期/时间的差异:

// returns 4 because of the leap year of 366 days
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5), PeriodType.years()).getYears()


// this time it returns 5
new Period(LocalDate.now(), LocalDate.now().plusDays(365*5+1), PeriodType.years()).getYears()


// And you can also use these static methods
Years.yearsBetween(LocalDate.now(), LocalDate.now().plusDays(365*5)).getYears()

试试这个:

int epoch = (int) (new java.text.SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse("01/01/1970  00:00:00").getTime() / 1000);

你可以在parse()方法参数中编辑字符串。

@Michael Borgwardt的回答实际上在Android上不能正常运行。存在舍入错误。例如5月19日到21日是1天,因为它是1.99:1。在转换为int型之前使用round。

修复

int diffInDays = (int)Math.round(( (newerDate.getTime() - olderDate.getTime())
/ (1000 * 60 * 60 * 24) ))

请注意,这适用于UTC日期,因此如果查看本地日期,差异可能会减小一天。由于夏时制的原因,要让它在本地日期上正确工作,需要一种完全不同的方法。

以毫秒为单位减去日期是有效的(如另一篇文章所述),但是你在清除日期的时间部分时使用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
}

如果你需要一个格式化的返回字符串 “2 Days 03h 42m 07s”,试试这个:

public String fill2(int value)
{
String ret = String.valueOf(value);


if (ret.length() < 2)
ret = "0" + ret;
return ret;
}


public String get_duration(Date date1, Date date2)
{
TimeUnit timeUnit = TimeUnit.SECONDS;


long diffInMilli = date2.getTime() - date1.getTime();
long s = timeUnit.convert(diffInMilli, TimeUnit.MILLISECONDS);


long days = s / (24 * 60 * 60);
long rest = s - (days * 24 * 60 * 60);
long hrs = rest / (60 * 60);
long rest1 = rest - (hrs * 60 * 60);
long min = rest1 / 60;
long sec = s % 60;


String dates = "";
if (days > 0) dates = days + " Days ";


dates += fill2((int) hrs) + "h ";
dates += fill2((int) min) + "m ";
dates += fill2((int) sec) + "s ";


return dates;
}

博士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定义了时间跨度的简洁文本表示,如年、月、日、小时等。标准将这样的span称为持续时间。格式为PnYnMnDTnHnMnS,其中P表示“期间”,T将日期部分与时间部分分开,中间是数字后面跟着一个字母。

例子:

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

java.time

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

时刻

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

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

最好避免遗留类,如Date/Calendar。但如果必须与尚未更新为java.time的旧代码互操作,则需要来回转换。调用添加到旧类中的新转换方法。从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 );

转储到控制台。

PeriodDuration都使用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.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧遗产日期-时间类,如java.util.DateCalendar, &SimpleDateFormat

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

要了解更多信息,请参见甲骨文教程。搜索Stack Overflow可以找到很多例子和解释。规格是JSR 310

从哪里获取java。时间类?

  • Java SE 8< >强SE 9 < / >强
    • 内置的。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小特性并进行了修复。
    • 李< / ul > < / >
    • Java SE 6SE 7
      • 大部分的java。时间功能向后移植到Java 6 &7在<强> < em > ThreeTen-Backport < / em > < / >强
      • 李< / ul > < / >
      • 安卓 .

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


        Joda-Time

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

        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
        

使用Java 8+内置的java.time框架:

ZonedDateTime now = ZonedDateTime.now();
ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10);
Duration duration = Duration.between(oldDate, now);
System.out.println("ISO-8601: " + duration);
System.out.println("Minutes: " + duration.toMinutes());

输出:

iso - 8601: PT24H10M

分钟:1450

有关更多信息,请参阅甲骨文教程ISO 8601标准。

因为你使用的是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

最好的办法是

(Date1-Date2)/86 400 000

这个数字是一天中毫秒的数量。

一个日期和另一个日期的差异以毫秒为单位。

变量中收集答案。

public static void main(String[] args) {


String dateStart = "01/14/2012 09:29:58";
String dateStop = "01/14/2012 10:31:48";


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


Date d1 = null;
Date d2 = null;


try {
d1 = format.parse(dateStart);
d2 = format.parse(dateStop);


DateTime date11 = new DateTime(d1);
DateTime date22 = new DateTime(d2);
int days = Days.daysBetween(date11.withTimeAtStartOfDay(), date22.withTimeAtStartOfDay()).getDays();
int hours = Hours.hoursBetween(date11, date22).getHours() % 24;
int minutes = Minutes.minutesBetween(date11, date22).getMinutes() % 60;
int seconds = Seconds.secondsBetween(date11, date22).getSeconds() % 60;
if (hours > 0 || minutes > 0 || seconds > 0) {
days = days + 1;
}


System.out.println(days);


} catch (Exception e) {
e.printStackTrace();
}


}

这将为同一天提供日期差异

我喜欢基于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;
}

注意:startDate和endDates为->java.util.Date

import org.joda.time.Duration;
import org.joda.time.Interval;
// Use .getTime() unless it is a joda DateTime object
Interval interval = new Interval(startDate.getTime(), endDate.getTime());
Duration period = interval.toDuration();
//gives the number of days elapsed between start and end date.
period.getStandardDays();

与天类似,你也可以得到小时、分钟和秒

period.getStandardHours();
period.getStandardMinutes();
period.getStandardSeconds();

这是另一个样本。基本上适用于用户定义的模式。

   public static LinkedHashMap<String, Object> checkDateDiff(DateTimeFormatter dtfObj, String startDate, String endDate)
{
Map<String, Object> dateDiffMap = new HashMap<String, Object>();
DateTime start = DateTime.parse(startDate,dtfObj);
DateTime end = DateTime.parse(endDate,dtfObj);
Interval interval = new Interval(start, end);
Period period = interval.toPeriod();


dateDiffMap.put("ISO-8601_PERIOD_FORMAT", period);
dateDiffMap.put("YEAR", period.getYears());
dateDiffMap.put("MONTH", period.getMonths());
dateDiffMap.put("WEEK", period.getWeeks());
dateDiffMap.put("DAY", period.getWeeks());
dateDiffMap.put("HOUR", period.getHours());
dateDiffMap.put("MINUTE", period.getMinutes());
dateDiffMap.put("SECOND", period.getSeconds());


return dateDiffMap;
}

下面的代码可以给你想要的输出:

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());

先回答最初的问题:

将以下代码放入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在日期演算中应用的偏移量。

:)

public static String getDifferenceBtwTime(Date dateTime) {


long timeDifferenceMilliseconds = new Date().getTime() - dateTime.getTime();
long diffSeconds = timeDifferenceMilliseconds / 1000;
long diffMinutes = timeDifferenceMilliseconds / (60 * 1000);
long diffHours = timeDifferenceMilliseconds / (60 * 60 * 1000);
long diffDays = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24);
long diffWeeks = timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 7);
long diffMonths = (long) (timeDifferenceMilliseconds / (60 * 60 * 1000 * 24 * 30.41666666));
long diffYears = (long)(timeDifferenceMilliseconds / (1000 * 60 * 60 * 24 * 365));


if (diffSeconds < 1) {
return "one sec ago";
} else if (diffMinutes < 1) {
return diffSeconds + " seconds ago";
} else if (diffHours < 1) {
return diffMinutes + " minutes ago";
} else if (diffDays < 1) {
return diffHours + " hours ago";
} else if (diffWeeks < 1) {
return diffDays + " days ago";
} else if (diffMonths < 1) {
return diffWeeks + " weeks ago";
} else if (diffYears < 12) {
return diffMonths + " months ago";
} else {
return diffYears + " years ago";
}
}

只需使用下面的方法和两个Date对象。如果你想传递当前日期,只要传递new Date()作为第二个参数,因为它是用当前时间初始化的。

public String getDateDiffString(Date dateOne, Date dateTwo)
{
long timeOne = dateOne.getTime();
long timeTwo = dateTwo.getTime();
long oneDay = 1000 * 60 * 60 * 24;
long delta = (timeTwo - timeOne) / oneDay;


if (delta > 0) {
return "dateTwo is " + delta + " days after dateOne";
}
else {
delta *= -1;
return "dateTwo is " + delta + " days before dateOne";
}
}

此外,除了从天数,如果,你也想要其他参数的差异,使用下面的片段,

int year = delta / 365;
int rest = delta % 365;
int month = rest / 30;
rest = rest % 30;
int weeks = rest / 7;
int days = rest % 7;

p.s. Code完全取自SO答案。

在java中有一个简单的方法来做到这一点

//创建一个实用方法

public long getDaysBetweenDates(Date d1, Date d2){
return TimeUnit.MILLISECONDS.toDays(d1.getTime() - d2.getTime());
}

该方法将返回两个日期之间的天数。您可以使用默认的java日期格式,也可以轻松地从任何日期格式转换。

在阅读了许多关于这个问题的回答和评论后,我的印象是,要么使用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);


}

因为这个问题用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

您可以尝试较早版本的Java。

 public static String daysBetween(Date createdDate, Date expiryDate) {


Calendar createdDateCal = Calendar.getInstance();
createdDateCal.clear();
createdDateCal.setTime(createdDate);


Calendar expiryDateCal = Calendar.getInstance();
expiryDateCal.clear();
expiryDateCal.setTime(expiryDate);




long daysBetween = 0;
while (createdDateCal.before(expiryDateCal)) {
createdDateCal.add(Calendar.DAY_OF_MONTH, 1);
daysBetween++;
}
return daysBetween+"";
}

另一个纯Java变体:

public boolean isWithin30Days(Calendar queryCalendar) {


// 1. Take the date you are checking, and roll it back N days
Calendar queryCalMinus30Days = Calendar.getInstance();
queryCalMinus30Days.setTime(queryCalendar.getTime());
queryCalMinus30Days.add(Calendar.DATE, -30); // subtract 30 days from the calendar


// 2. Get respective milliseconds for the two Calendars: now & queryCal minus N days
long nowL = Calendar.getInstance().getTimeInMillis();
long queryCalMinus30DaysL = queryCalMinus30Days.getTimeInMillis();


// 3. if nowL is still less than the queryCalMinus30DaysL, it means queryCalendar is more than 30 days into future
boolean isWithin30Days = nowL >= queryCalMinus30DaysL;


return isWithin30Days;
}

感谢这里的启动代码:https://stackoverflow.com/a/30207726/2162226

这是一个正确的Java 7解决方案,没有任何依赖。

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;
}

由于这里所有的答案都是正确的,但使用传统java或第三方库,如joda或类似的,我将在java 8及以后使用新的java.time类的另一种方式。看到甲骨文教程

使用LocalDateChronoUnit:

LocalDate d1 = LocalDate.of(2017, 5, 1);
LocalDate d2 = LocalDate.of(2017, 5, 18);


long days = ChronoUnit.DAYS.between(d1, d2);
System.out.println( days );

在涉猎了所有其他答案之后,为了保持Java 7 Date类型,但使用Java 8 diff方法更精确/标准,

public static long daysBetweenDates(Date d1, Date d2) {
Instant instant1 = d1.toInstant();
Instant instant2 = d2.toInstant();
long diff = ChronoUnit.DAYS.between(instant1, instant2);
return diff;
}

如果你想修复日期范围跨越夏令时边界的问题(例如,一个日期在夏季,另一个日期在冬季),你可以使用这个来获得天数的差异:

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);
}

由于日期可以包含小时和分钟,最终结果将四舍五入,这将导致不正确的值。例如,你计算今天晚上22点后天凌晨00:00之间的差值,所以最终结果将是1,因为实际上它是1.08 或smth差值,然后在调用TimeUnit.MILLISECONDS.toDays(..)时将其舍入。这就是为什么你需要考虑到这一点,所以在我的解决方案中,我从一天中的毫秒减去剩余的毫秒。另外,如果要计算结束日期,则需要+1。

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