将Date对象与Java中的TimeStamp进行比较

时间:2012-01-19 16:03:44

标签: java date timestamp compare equals

当我测试这段代码时:

java.util.Date date = new java.util.Date();
java.util.Date stamp = new java.sql.Timestamp(date.getTime());

assertTrue(date.equals(stamp));
assertTrue(date.compareTo(stamp) == 0);
assertTrue(stamp.compareTo(date) == 0);
assertTrue(stamp.equals(date));

我期待一个真实,真实,真实,虚假。因此:

在java.sql.Timestamp的javadoc中,它声明:

  

注意:此类型是java.util.Date和单独的类型的组合   纳秒值。只有整数秒存储在   java.util.Date组件。分数秒 - 纳米 - 是   分离。 Timestamp.equals(Object)方法永远不会返回true   传递了java.util.Date类型的值,因为a的nanos组件   日期不详。因此,Timestamp.equals(Object)方法是   关于java.util.Date.equals(Object)不对称   方法。此外,hashcode方法使用底层的java.util.Date   实施,因此不包括纳米   计算

     

由于Timestamp类和。之间的差异   上面提到的java.util.Date类,建议代码不行   查看时间戳值通常作为java.util.Date的实例。   Timestamp和java.util.Date之间的继承关系   真的表示实现继承,而不是类型继承。

但相反,我会得到一个真实的,虚假的,真实的,错误的。有什么想法吗?

编辑:当我用equals方法检查两个日期时出现此问题,但是一个Date对象来自Hibernate类并且调试我看到该对象包含TimeStamp。所以equals方法评估为false,然后我发现了这个:http://mattfleming.com/node/141

但是当我尝试代码时,我会得到不同的结果...如果我不能同时使用equals和compareTo,我应该用什么来检查2个日期是否相同?!?!

10 个答案:

答案 0 :(得分:6)

Nican解释了equals部分,关于compareTo

  • TimestampcompareTo(Date)方法,可将其内部转换为Timestamp
  • Date通过向下转换进行比较(因为Timestamp是它的子类);但正如javadoc所说:“Timestamp和java.util.Date之间的继承关系实际上表示实现继承,而不是类型继承”

在我看来,这当然是一个可怕的想法。

答案 1 :(得分:5)

TL;博士

使用现代的 java.time 类,而不是那些麻烦的遗留日期时间类。

myPreparedStatement.setObject(
    … , 
    Instant.now()                // Capture the current moment in UTC.
)

旧日期 - 时间类设计不佳

更坦率地说,java.sql.Timestamp / .Date / .Time类是一个hack,一个糟糕的黑客。与java.util.Date/.Calendar一样,它们是设计选择不佳的结果。

应尽可能简单地使用java.sql类型,仅用于数据传入/传出数据库。不要用于业务逻辑和进一步的工作。

java.time

旧的日期时间类已被Java 8及更高版本中内置的java.time框架所取代。这些新类由JSR 310定义,受到非常成功的Joda-Time库的启发,并由ThreeTen-Extra项目扩展。

最终我们应该看到更新的JDBC驱动程序直接使用这些java.time类型。但直到那天我们需要转换为/从java.sql类型。对于此类转换,请致电new methods added to the old classes

Instant是UTC时间轴上的一个时刻,分辨率为nanoseconds

Instant instant = myJavaSqlTimestamp.toInstant();

走向另一个方向:

java.sql.Timestamp ts = java.sql.Timestamp.valueOf( instant );

应用时区以获取wall-clock time

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );

java.time类有一个明智的选择类设计。因此,您可以按预期使用equalscompareTo。请注意,具有偏离UTC或时区的类也提供isEqualisBeforeisAfter方法。这些方法通过考虑时间轴上的时刻,它们的时间顺序来进行比较。 equalscompareTo方法也会考虑偏移量或时区。

最大限度地减少java.sql的使用,同时最大限度地使用java.time,这使得问题的问题没有实际意义。

在Hibernate中,为java.time使用转换器。

JDBC 4.2

从JDBC 4.2及更高版本开始,您根本不需要使用旧版。您可以通过getObject&更新来直接与数据库交换 java.time 对象。 setObject方法。

myPreparedStatement.setObject( … , instant ) ;

并检索。

Instant instant = myResultSet.getObject( … , Instant.class ) ;

请注意,许多数据库无法存储分辨率与 java.time 中使用的纳秒级一样精细的分钟。您可能希望明确截断,而不是让JDBC driver隐式地这样做。

Instant instant = Instant.now().truncatedTo( ChronoUnit.MILLIS ) ; // Lop off any nanoseconds & microseconds, keeping only the milliseconds, to match limitations of database. 

关于 java.time

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

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

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

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

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 2 :(得分:4)

我在测试中遇到了同样的问题,我想比较java.util.Datejava.sql.Timestamp个对象。

我将它们转换为LocalDate并且有效:

import org.apache.commons.lang.ObjectUtils;

// date1 and date2 can be java.util.Date or java.sql.Timestamp
boolean datesAreEqual = ObjectUtils.equals(toLocalDate(date1), toLocalDate(date2));

其中toLocalDate是:

import org.joda.time.LocalDate;
import java.util.Date;

public static void LocalDate toLocalDate(Date date)
{
    return date != null ? LocalDate.fromDateFields(date) : null;
}

答案 3 :(得分:3)

  1. date.equals(stamp)返回true且戳记等于(日期)返回false。 原因:日期忽略了时间戳的纳秒部分,因为其他部分碰巧相等,所以结果相等。小数秒 - 纳米 - 是分开的。当传递java.util.Date类型的值时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件是未知的。有关详细信息,请参阅here

    1. date.compareTo(stamp)== 0返回false AND stamp.compareTo(date)== 0返回true。 原因:根据此bug,compareTo函数的行为与此相同。

答案 4 :(得分:2)

Timestamp的纳米值不是纳秒数 - 它是毫微秒分辨率的毫秒数(即分数秒)。因此,在Timestamp构造函数中,它将super上的时间设置为毫秒。因此,Timestamp成员fastTime(在日期compareTo()中使用)的值始终低于相应的Date(当然,除非它没有分数)秒)。

在第110行检查the source for Timestamp

答案 5 :(得分:1)

尝试使用" Strings"重新创建对象日期。像这样

Date date = new Date();
Date stamp = Timestamp(date.getTime());

SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String date1String = ft.format(date);
String date2String = ft.format(stamp);

Date date1 = ft.parse(date1String);
Date date2 = ft.parse(date2String);


assertTrue(date1.equals(date2)); // true
assertTrue(date1.compareTo(date2) == 0); //true
assertTrue(date2.compareTo(date1) == 0); //true
assertTrue(date2.equals(date1)); // true

答案 6 :(得分:1)

我已经解决了将Date和TimeStamp转换为Calendar对象的问题,然后我比较了单个Calendar的属性:

Calendar date = Calendar.getInstance();
date.setTimeInMillis(dateObject.getTime());
Calendar timestamp = Calendar.getInstance();
timestamp.setTimeInMillis(timestampObject.getTime());
if (effettoAppendice.get(Calendar.DAY_OF_MONTH) == timestamp.get(Calendar.DAY_OF_MONTH) &&
    effettoAppendice.get(Calendar.MONTH) == timestamp.get(Calendar.MONTH) &&
    effettoAppendice.get(Calendar.YEAR) == timestamp.get(Calendar.YEAR)) {
    System.out.println("Date and Timestamp are the same");
} else {
    System.out.println("Date and Timestamp are NOT the same");
}

希望这有帮助。

答案 7 :(得分:0)

看一下Timestamp的源代码比较方法:

public boolean equals(java.lang.Object ts) {
  if (ts instanceof Timestamp) {
    return this.equals((Timestamp)ts);
  } else {
    return false;
  }
}

http://www.docjar.com/html/api/java/sql/Timestamp.java.html

如果比较对象是时间戳,它将只返回true。 此外,这里是Date源代码:http://www.docjar.com/html/api/java/util/Date.java.html,由于Timestamp继承了Date,它可以比较它。

答案 8 :(得分:0)

遗憾的是,Timestamp类会使用equals(Object)重载equals(Timestamp)方法,因此很难对时间戳进行比较。

equals(Object) javadocs中说:

  

测试此Timestamp对象是否为   等于给定的对象。这个方法的版本等于   添加以修复Timestamp.equals(Timestamp)的错误签名   并保持与现有类文件的向后兼容性。   注意:此方法与equals(Object)不对称   基类中的方法。

我的经验法则是永远不要比较时间戳的相等性(这无论如何都是无用的),但如果你必须检查相等性,则使用getTime()的结果比较它们(毫秒数) 1970年1月1日,00:00)。

答案 9 :(得分:0)

关于实现继承和类型继承的小说明..

"对象的类定义了对象的实现方式。相反,对象的类型仅指其界面。类继承(实现继承)根据另一个对象的实现来定义对象的实现。类型继承描述何时可以使用对象代替另一个对象。"

时间戳和日期类具有实现继承,正如JAVADOC所说。