计算两个Javadate实例之间的差异

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

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

但是,这只剩下一个long毫秒数。 有没有更简单,更好的方法来获得时间增量?

不幸的是,JDK Date API非常糟糕。 我build议使用乔达时间库 。

乔达时间有一个时间的概念间隔 :

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

编辑:顺便说一句,乔达有两个概念:代表两个时间点之间的时间间隔(代表时间之间的上午8点到上午10点),以及一个Duration ,代表一段时间没有实际的时间界限(例如代表两个小时!)

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

简单差异(无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); 

以分钟为单位获得2date的差异。

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


人类可读的差异(没有lib)

 public static Map<TimeUnit,Long> computeDiff(Date date1, Date date2) { long diffInMillies = date2.getTime() - date1.getTime(); List<TimeUnit> units = new ArrayList<TimeUnit>(EnumSet.allOf(TimeUnit.class)); Collections.reverse(units); Map<TimeUnit,Long> result = new LinkedHashMap<TimeUnit,Long>(); long milliesRest = diffInMillies; for ( TimeUnit unit : units ) { long diff = unit.convert(milliesRest,TimeUnit.MILLISECONDS); long diffInMilliesForUnit = unit.toMillis(diff); milliesRest = milliesRest - diffInMilliesForUnit; 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}

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


警告

上面的代码片段计算了2个瞬间之间的简单差异。 这可能会导致在夏令时开关问题,就像这篇文章中所解释的那样。 这意味着,如果你计算date之间的差异,没有时间,你可能有一个失踪的一天/小时。

在我看来,date差异是一种主观的,特别是在几天。 你可以:

  • 统计24小时经过时间的数量:天+ 1天= 1天= 24小时

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

  • 请计算day switches ,即即使经过的时间仅为2小时(或者如果有夏令时,则为1小时),即date+ 11下午 – 上午11时= 1天。

如果您的date差异定义与第一种情况相符,我的答案是有效的

随着JodaTime

如果您正在使用JodaTime,则可以使用以下方法得到2个时间点(毫秒支持的ReadableInstant)的差异:

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

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

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

请注意,这与UTCdate一起使用,所以如果您查看当地date,差异可能是一天rest。 要使用当地date正确工作,由于夏令时需要完全不同的方法。

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

  • 这不会考虑时区 – Date始终是UTC
  • 这不会考虑夏令时(例如可能只有23小时的日子)
  • 即使在UTC内,8月16日晚上11点到8月18日凌晨2点还有多less天? 这只有27个小时,这是否意味着有一天? 还是应该是三天,因为它包括三个date?
 Days d = Days.daysBetween(startDate, endDate); int days = d.getDays(); 

http://joda-time.sourceforge.net/faq.html#datediff

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

有关更多信息,请参阅Oracle教程和ISO 8601标准。

TL;博士

 Duration d = Duration.between( then , Instant.now() ); // Two and a half hours ago. 

d.toString():PT2H34M56S

d.toMinutes():154

d.toMinutesPart():34

ISO 8601格式: PnYnMnDTnHnMnS

明智的标准ISO 8601将时间跨度的简明文字表示定义为数年,月,日,小时等。标准调用这样的持续时间 。 格式是PnYnMnDTnHnMnS ,其中P表示“期间”, T将时间部分与时间部分分开,并且在两者之间的数字后跟一个字母。

例子:

  • P3Y6M4DT12H30M5S
    三年,六个月,四天,十二小时,三十分钟和五秒钟
  • PT4H30M
    四个半小时

java.time

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

java.time类已经将这种将时间跨度表示为几年,几个月,几天,几小时,几分钟,几秒的想法分成两部分:

  • Period为几年,几个月,几天
  • Duration几天,几小时,几分钟,几秒钟

这是一个例子。

 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 [America / Montreal] to future:2015-11-26T00:46:48.016-05:00 [America / Montreal] = PT1H3M

Java 9增加了Duration方法来获取date部分,小时部分,分钟部分和秒部分。

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

 long totalHours = duration.toHours(); 

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

ChronoUnit

如果您只关心更简单的大粒度时间(如“经过的天数”),请使用ChronoUnit枚举。

 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及更高版本中。 这些类取代了麻烦的旧的遗留date时间类,如java.util.DateCalendarSimpleDateFormat

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

要了解更多信息,请参阅Oracle教程 。 并search堆栈溢出了很多例子和解释。 规范是JSR 310 。

从何处获取java.time类?

  • Java SE 8SE 9及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6SE 7
    • 大部分的java.timefunction都被移植到了ThreeTen-Backport中的 Java 6&7中。
  • Android的
    • ThreeTenABP项目专门针对Android,采用了ThreeTen-Backport (上文提到)。
    • 请参阅如何使用…。

ThreeTen-Extra项目将java.time扩展到其他类。 这个项目是未来可能增加java.time的一个试验场。 你可能会在这里find一些有用的类,比如IntervalYearWeekYearQuarter 等等 。


乔达时间

更新: Joda-Time项目现在处于维护模式 ,团队build议迁移到java.time类。 我把这部分留给了历史。

乔达时间库默认使用ISO 8601。 它的Period类parsing并生成这些PnYnMnDTnHnMnSstring。

 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 

稍微简单一些的select:

 System.currentTimeMillis() - oldDate.getTime() 

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

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

举例来说,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; } 

有很多方法可以finddate和时间之间的差异。 我所知道的最简单的方法之一是:

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

打印语句只是一个例子 – 你可以格式化它,只要你喜欢。

如果你不想使用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)); 

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

请注意,这仍然假设date1date2设置为一天中的同一时间。 对于一天中的不同时间,您首先必须定义“date差异”的含义,正如Jon Skeet指出的那样。

看看Joda Time ,这是一个改进的Javadate/时间API,应该可以和Scala一起工作。

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

由于这里的所有答案都是正确的,但是使用遗留的java或像joda或类似的第三方libs,我将在Java 8及更高版本中使用新的java.time类别。 请参阅Oracle教程 。

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

让我看看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 

如果你需要格式化的返回string,如“2天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; } 

在这里检查示例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."); } } 

使用GMT时区获取日历的实例,使用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)); 

以下代码可以给你所需的输出:

 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()); 
 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"; } } 
 int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY; 

最好的事情是

 (Date1-Date2)/86 400 000 

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

一个date – 其他date以毫秒为单位给出差异。

收集答案在一个variables。

这可能是最直接的方式 – 也许是因为我已经使用Java编写了一段时间的Java库,但是这段代码对我来说看起来“简单而美好”!

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

不使用标准的API,不。 你可以自己做这样的事情:

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

或者你可以使用乔达 :

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

注意:startDate和endDates是 – > java.util.Date

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

与日子类似,您也可以获得小时,分钟和秒钟

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

只是为了回答最初的问题:

把下面的代码放在一个函数中,例如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在date演算中所应用的偏移量。

🙂

只需使用两个Date对象的下面的方法。 如果您想传递当前date,只需将new Date()作为第二个parameter passing,因为它是用当前时间初始化的。

 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; 

PS代码完全取自一个SO回答。

尝试这个:

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

you can edit the string in the parse() methods param.

Since you are using Scala, there is a very good Scala library Lamma . With Lamma you can minus date directly with - operator

 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 

Earlier versions of Java you can try.

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