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

Posted

技术标签:

【中文标题】计算两个 Java 日期实例之间的差异【英文标题】:Calculating the difference between two Java date instances 【发布时间】:2010-12-06 00:44:04 【问题描述】:

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

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

但是,这只会给我留下一个代表毫秒的long。有没有更简单、更好的方法来获得时间增量?

【问题讨论】:

为什么不喜欢joda time?如果您要在 java 中处理日期,这几乎是最好的选择。 请检查我的优雅 2 班轮解决方案,不使用 Joda 并在 ***.com/a/10650881/82609 的任何 TimeUnit 中给出结果 对所有推荐 Joda time 的人感到羞耻,并且不推荐真正的 Java 答案...... @Zizouz212 关于推荐 Joda-Time,与 Java 捆绑的旧日期时间类很糟糕,非常糟糕,设计不佳,令人困惑和麻烦。太糟糕了,Joda-Time 作为他们的替代品获得了巨大的成功。太糟糕了,甚至 Sun/Oracle 都放弃了它们,并采用 java.time 包作为 Java 8 及更高版本的一部分。 java.time 类的灵感来自 Joda-Time。 Joda-Time 和 java.time 都由同一个人领导,Stephen Colbourne。我会说,“任何推荐使用 DateCalendarSimpleDateFormat 的人都感到羞耻”。 当被问到这个问题时,Joda Time 可能是一个很好的答案,但今天对于任何可以使用 Java 8 的人来说,最好的答案是使用java.time.Period 和/或Duration。见Basil Bourque’s answer below。 【参考方案1】:

试试这个:

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

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

【讨论】:

【参考方案2】:
int diffInDays = (int)( (newerDate.getTime() - olderDate.getTime()) 
                 / (1000 * 60 * 60 * 24) )

请注意,这适用于 UTC 日期,因此如果您查看当地日期,差异可能是一天。由于夏令时,要让它与本地日期正常工作需要完全不同的方法。

【讨论】:

这实际上在 android 中无法正常工作。存在舍入错误。示例 5 月 19 日至 21 日表示 1 天,因为它将 1.99 转换为 1。在转换为 int 之前使用 round。 这是最好最简单的答案。在计算两个日期之间的差异时,本地时区相互减去......因此正确的答案(作为双精度数)简单地由 ((double) (newer.getTime() - old.getTime()) / (86400.0 * 1000.0); ... 作为双精度,您也有小数日,可以轻松转换为 HH:MM:ss。 @scottb:本地日期的问题是你可以有夏令时,这意味着有些日子有 23 或 25 小时,可能会弄乱结果。 @Steve:当我像这样定义新的 Date(115, 2, 26); 时,我是 28 岁。 (注意参数的 API 文档)。您是否有可能使用美国日期格式和宽松模式解析它们,以便将 26/03/2015 解释为 2015 年第 26 个月的第 3 天? @Steve:嗯,不知道为什么我之前得到了不同的结果,但现在我可以重现你的错误。您的代码中的大括号与我的答案不同,这导致 (endDate.getTime() - startDate.getTime()) 被强制转换为 int 而不是最终结果,并且您得到一个整数溢出。【参考方案3】:

以下是一种解决方案,我们可以通过多种方式实现这一目标:

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

【讨论】:

【参考方案4】:

让我展示一下 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 

【讨论】:

【参考方案5】:

使用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 等的上下文中这是一个很好的答案。使用 hack 将时区设置为 GMT 会使代码对夏令时效果不敏感.【参考方案6】:

在某些语言环境中使用毫秒方法可能会导致问题。

例如,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;  
  

【讨论】:

能否请您注明这段代码的原作者和第三句话的原作者blog entry is dated back to 2007? 是不是有点无效? 它不能正常工作。 daysBetween(新公历(2014,03,01),新公历(2014,04,02)));返回 31,它应该返回 32:timeanddate.com/date/… @marcolopes——你错了——因为日历月是从零开始的。我确定您的意思是三月/四月,但您要测试的是四月/六月,即 31 日。为了安全起见,请写成 -> new GregorianCalendar(2014, Calendar.MARCH, 1).... @UncleIroh,你是对的!我错过了这个重要的事实(日历月是从零开始的)。我必须重新审视这个问题。【参考方案7】:

如果你不想使用 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 设置为一天中的同一时间。正如 Jon Skeet 所指出的,对于一天中的不同时间,您首先必须定义“日期差异”的含义。

【讨论】:

问题出在date1.getTime() vs date2.getTime()。所以 2016-03-03 到 2016-03-31 的差异将计算 27 天,而您需要 28 天。 @malat:抱歉,我听不懂。我刚刚尝试过 - 用我的代码将 2016-03-03 与 2016-03-31 区分开来计算 28 天。如果它在您的示例中计算了其他内容,请考虑将其作为一个单独的问题提出。 另外,您是否阅读了我的警告? “这仍然假设 date1 和 date2 设置为一天中的同一时间”。您是否可能在测试中使用了一天中的不同时间? 啊对!我错过了Math.round() 的诀窍,这在“现实世界”日历中似乎是安全的。抱歉打扰了。【参考方案8】:

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

【讨论】:

-1 这是错误的,除非 Date 实例是从 UTC 时间派生的。请参阅 Jon Skeet 的回答。【参考方案9】:

如果您有 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

什么的

【讨论】:

-1 这是错误的,除非 Date 实例是从 UTC 时间派生的。请参阅 Jon Skeet 的回答。 这是不正确的。在内部, Date 实例是代表 POSIX Epoch Time 的 long 的薄包装器。这仅针对 UTC 定义。因此,dateObject.getTime() 返回的值始终为 UTC。【参考方案10】:
int daysDiff = (date1.getTime() - date2.getTime()) / MILLIS_PER_DAY;

【讨论】:

-1 这是错误的,除非 Date 实例是从 UTC 时间派生的。请参阅 Jon Skeet 的回答。 @sleske 你不对。他已经使用Date 丢失了时区信息,所以这种比较是在这种情况下可以实现的最好的比较。 好吧,猜我们都是对的。确实,这取决于 Date 实例的来源。尽管如此,这是一个应该提及的常见错误。 当我使用您的解决方案时,它说:类型不匹配:无法从 long 转换为 int。我认为您还应该添加演员表还是我错过了什么?【参考方案11】:

只需在每个上调用 getTime,获取差值,然后除以一天中的毫秒数。

【讨论】:

-1 这是错误的,除非 Date 实例是从 UTC 时间派生的。请参阅 Jon Skeet 的回答。【参考方案12】:

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

这不会考虑时区 - Date 始终采用 UTC 这不会考虑夏令时(例如,有些日子可能只有 23 小时) 即使在 UTC 范围内,8 月 16 日晚上 11 点到 8 月 18 日凌晨 2 点有多少天?只有27小时,所以是一天吗?还是应该是三天,因为它涵盖了三个日期?

【讨论】:

我以为是 java.util。 Date 只是时间毫秒表示的一个小包装,在本地(默认)时区中解释。打印出 Date 给我一个本地时区表示。我在这里感到困惑吗?【参考方案13】:

一个稍微简单的替代方案:

System.currentTimeMillis() - oldDate.getTime()

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

【讨论】:

【参考方案14】:

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

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

或者你可以使用Joda:

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

【讨论】:

【参考方案15】:

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

您是否对以毫秒为单位返回的结果感到满意,或者您希望以其他格式返回结果的一部分?

【讨论】:

以上是关于计算两个 Java 日期实例之间的差异的主要内容,如果未能解决你的问题,请参考以下文章

如何计算两个日期之间的差异

如何计算两个日期之间的差异?

在 Swift 中计算两个日期之间的差异

以小时和分钟计算两个日期之间的差异

计算两个日期时间odoo 10之间的差异[重复]

NetSuite 保存的搜索计算两个相关记录之间的日期差异