【问题标题】:Compare only the time portion of two dates, ignoring the date part仅比较两个日期的时间部分,忽略日期部分
【发布时间】:2011-12-02 07:59:28
【问题描述】:

给定两个 Date 对象,仅比较它们的时间部分之间的差异,完全忽略年、月和日,有什么好的方法?

这与this question完全相反。

更新:以下是最终代码供将来参考:

private long differenceBetween(Date currentTime, Date timeToRun)
{
    Calendar currentCal = Calendar.getInstance();
    currentCal.setTime(currentTime);

    Calendar runCal = Calendar.getInstance();
    runCal.setTime(timeToRun);
    runCal.set(Calendar.DAY_OF_MONTH, currentCal.get(Calendar.DAY_OF_MONTH));
    runCal.set(Calendar.MONTH, currentCal.get(Calendar.MONTH));
    runCal.set(Calendar.YEAR, currentCal.get(Calendar.YEAR));

    return currentCal.getTimeInMillis() - runCal.getTimeInMillis();
}

【问题讨论】:

  • 是的,确实如此。为什么不呢?
  • 这个解决方案的讽刺之处在于,你需要两个对象,它们是 long 类型的原语的薄包装,调用一个庞大而复杂的 API 来从 long 转换为 Calendar 对象......只是最终回到您再次从 Calendar 对象转换为 long 的地方。
  • @scottb - 请参阅下面的my answer,它不会与Calendar 对象混淆,但仅使用Date 成员。
  • 更新 如今,我们可以使用 java.time 类来 do this in a one-liner 取代可怕的 Date 和 Calendar。更容易,更清洁,并且正确处理时区。

标签: java datetime date time


【解决方案1】:

看看Calendar 类。它支持从给定的Date 中提取小时、分钟和秒。

Calendar calendar = Calendar.getInstance();
calendar.setTime(yourDateObject);
int hour = calendar.get(Calendar.HOUR);
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);

【讨论】:

  • Calendar.HOUR_OF_DAY 更合适(24 小时而不是 12 小时)
【解决方案2】:

如果你不能使用 JODA,

创建2个日历对象,设置年月日为0。

比较它们....

【讨论】:

    【解决方案3】:

    您可以考虑使用 Joda 时间的 DateTimeComparator.getTimeOnlyInstance() 作为比较器,该比较器仅根据时间比较两个 Joda 日期。

    例如:

    DateTimeComparator comparator = DateTimeComparator.getTimeOnlyInstance();
    comparator.compare(date1, date2);
    

    见http://joda-time.sourceforge.net/api-release/org/joda/time/DateTimeComparator.html#getTimeOnlyInstance()

    【讨论】:

    • 如果(java)时间是问题,JODA就是答案:D
    • @bbaja42 不是你使用 GWT :/
    【解决方案4】:

    如果你想比较日期的底层二进制(long int)值,你可以这样做:

    public int compareTimes(Date d1, Date d2)
    {
        int     t1;
        int     t2;
    
        t1 = (int) (d1.getTime() % (24*60*60*1000L));
        t2 = (int) (d2.getTime() % (24*60*60*1000L));
        return (t1 - t2);
    }
    

    附录 1

    这种技术具有速度优势,因为它直接使用Date 对象的底层long 值,而不是在刻度和日历组件之间进行转换(这相当昂贵且缓慢)。这也比处理Calendar 对象简单得多。

    附录 2

    上面的代码将时差返回为int,这对于任何一对时间都是正确的,因为它完全忽略了日期的年/月/日部分,并且任何两个时间之间的差异都是 no超过 86,400,000 毫秒(= 1000 毫秒/秒 × 60 秒/分钟 × 60 分钟/小时 × 24 小时/天)。

    【讨论】:

    • 这是最好的答案,imo。无需使用复杂的 Calendar API 来比较 Date 对象中的时间值。
    • 完美又智能
    • thnx david,正是我想要的 :)
    • 非常好!太好了!
    • 这并不总是有效。示例:currentDate: Tue Oct 20 16:28:57 MESZ 2015 和 validFromTime: Tue Oct 20 01:30:00 MESZ 2015 返回错误的结果。
    【解决方案5】:

    如果 JODA 不是一个选项,那么最短的方法之一可能是将时间转换为字符串,然后进行比较。

    DateFormat df = new SimpleDateFormat("HHmmssSZ");
    df.format(date1).equals(df.format(date2));
    

    【讨论】:

      【解决方案6】:

      不知道这个方法的实践性或效率如何,但我使用 Date 对象编写了一个简单的函数来满足我的目的。它返回真或假是第一个日期值大于第二个。输入 d1 && d2 是 Date 对象。

      function CompareTimes(d1, d2) {
                   if (d1.getHours() < d2.getHours()) {
                       return false;
                   }
                   if (d1.getHours() > d2.getHours()) {
                       return true;
      
                   } else {
                       return (d1.getMinutes() > d2.getMinutes());
                   }
      };
      

      【讨论】:

        【解决方案7】:

        如果您只想比较日期的时间部分,那么这将为您提供正确的结果 -

        public long compareTimes(Date d1, Date d2)
            {
                long     t1;
                long     t2;
                t1 = d1.getHours()*60*60+d1.getMinutes()*60+d1.getSeconds();
                t2 = d2.getHours()*60*60+d2.getMinutes()*60+d2.getSeconds();
                long diff = t1-t2;
                System.out.println("t1 - "+t1+", t2 - "+t2+",  diff - "+diff);
        
                return diff;
            }
        

        【讨论】:

          【解决方案8】:

          tl;博士

          Duration                                  // Span of time, with resolution of nanoseconds.
          .between(                                 // Calculate elapsed time.
              LocalTime.now(                        // Get current time-of-day…
                  ZoneId.of( "Pacific/Auckland" )   // … as seen in a particular time zone.
              )                                     // Returns a `LocalTime` object.
              ,
              myJavaUtilDate                        // Avoid terrible legacy date-time classes such as `java.util.Date`.
              .toInstant()                          // Convert from `java.util.Date` to `java.time.Instant`, both representing a moment in UTC.
              .atZone(                              // Adjust from UTC to a particular time zone. Same moment, same point on the timeline, different wall-clock time.
                  ZoneId.of( "Pacific/Auckland" )   // Specify time zone by proper naming in `Continent/Region` format, never 2-4 letter pseudo-zones such as `PST`, `CEST`, `CST`, `IST`, etc.
              )                                     // Returns a `ZonedDateTime` object.
              .toLocalTime()                        // Extract the time-of-day without the date and without a time zone.
          )                                         // Returns a `Duration` object.
          .toMillis()                               // Calculate entire span-of-time in milliseconds. Beware of data-loss as `Instant` uses a finer resolution the milliseconds, and may carry microseconds or nanoseconds.
          

          我建议传递类型安全且不言自明的 Duration 对象,而不是仅仅整数毫秒。

          java.time

          现代方法使用 java.time 类取代了糟糕的遗留类,例如 Date、Calendar、SimpleDateFormat。

          将您的java.util.Date(UTC 时刻)转换为Instant。使用添加到旧类的新转换方法。

          Instant instant = myJavaUtilDate.toInstant() ;
          

          这代表 UTC 中的一个时刻。确定日期和时间需要 time zone 。对于任何给定的时刻,日期和时间在全球范围内因区域而异。例如,Paris France 中午夜后几分钟是新的一天,而 Montréal Québec 中仍然是“昨天”。

          如果没有指定时区,JVM 会隐式应用其当前的默认时区。该默认值可能在运行时(!)期间change at any moment,因此您的结果可能会有所不同。最好将 desired/expected time zone 明确指定为参数。

          以continent/region 的格式指定proper time zone name,例如America/Montreal、Africa/Casablanca 或Pacific/Auckland。切勿使用 2-4 个字母的缩写,例如 EST 或 IST,因为它们不是真正的时区,没有标准化,甚至不是唯一的 (!)。

          ZoneId z = ZoneId.of( "America/Montreal" ) ;  
          

          如果你想使用 JVM 当前的默认时区,请求它并作为参数传递。如果省略,则隐式应用 JVM 的当前默认值。最好是明确的,因为默认值可能会在任何时候在运行时被 JVM 中任何应用程序的任何线程中的任何代码更改。

          ZoneId z = ZoneId.systemDefault() ;  // Get JVM’s current default time zone.
          

          将ZoneId 分配给Instant 以生成ZonedDateTime 对象。

          ZonedDateTime zdt = instant.atZone( z ) ;
          

          提取时间部分,不带日期和时区。

          LocalTime lt = zdt.toLocalTime() ;
          

          比较。使用Duration 计算经过的时间。

          Duration d = Duration.between( ltStart , ltStop ) ;
          

          请注意,这不是一个公平的比较。日子并不总是 24 小时长,而且并非所有时间值在所有区域的所有日子里都有效。例如,在美国夏令时转换期间,可能根本没有凌晨 2 点。所以凌晨 1 点到凌晨 4 点在一个日期可能是 3 小时,但在另一个日期只有 2 小时。


          关于java.time

          java.time 框架内置于 Java 8 及更高版本中。这些类取代了麻烦的旧 legacy 日期时间类,例如 java.util.Date、Calendar 和 SimpleDateFormat。

          Joda-Time 项目现在位于maintenance mode,建议迁移到java.time 类。

          要了解更多信息,请参阅Oracle Tutorial。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310。

          您可以直接与您的数据库交换 java.time 对象。使用符合JDBC 4.2 或更高版本的JDBC driver。不需要字符串,不需要java.sql.* 类。

          从哪里获得 java.time 类?

          ThreeTen-Extra 项目通过附加类扩展了 java.time。该项目是未来可能添加到 java.time 的试验场。您可以在这里找到一些有用的类,例如Interval、YearWeek、YearQuarter 和more。

          【讨论】:

            猜你喜欢
            • 2012-02-18
            • 2012-05-08
            • 2016-02-14
            • 2019-01-23
            • 2023-04-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多