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

当我测试这段代码时:

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组件中。 分数秒 – 纳米 – 是分开的。 传递类型为java.util.Date的值时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件未知。 因此,Timestamp.equals(Object)方法与java.util.Date.equals(Object)方法不对称。 此外,哈希码方法使用底层的java.util.Date实现,因此在其计算中不包括nanos。

由于Timestamp类和上面提到的java.util.Date类之间存在差异,因此建议代码不要将Timestamp值一般视为java.util.Date的实例。 Timestamp和java.util.Date之间的inheritance关系实际上表示实现inheritance,而不是类型inheritance。

但相反,我会得到一个真实的,虚假的,真实的,虚假的。 有任何想法吗?

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

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

TL;博士

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

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

旧日期时间类设计不佳

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

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

java.time

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

最终我们应该看到更新的JDBC驱动程序直接使用这些java.time类型。 但直到那天我们需要转换为java.sql类型。 对于此类转换,请调用添加到旧类的新方法 。

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

 Instant instant = myJavaSqlTimestamp.toInstant(); 

走向另一个方向:

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

应用时区以获得挂钟时间 。

 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及更高版本开始,您根本不需要使用遗留类。 您可以通过getObjectsetObject方法直接与数据库交换java.time对象。

 myPreparedStatement.setObject( … , instant ) ; 

并检索。

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

请注意,许多数据库无法存储分辨率与java.time中使用的纳秒一样精细的分钟 。 您可能希望显式截断,而不是让JDBC驱动程序隐式执行此操作。

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

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

要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。

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

从哪里获取java.time类?

  • Java SE 8Java SE 9Java SE 10及更高版本
    • 内置。
    • 带有捆绑实现的标准Java API的一部分。
    • Java 9增加了一些小function和修复。
  • Java SE 6Java SE 7
    • 许多java.timefunction都被反向移植到ThreeTen-Backport中的 Java 6和7。
  • Android的
    • 更高版本的Android捆绑java.time类的实现。
    • 对于早期的Android(<26), ThreeTenABP项目采用ThreeTen-Backport (如上所述)。 请参见如何使用ThreeTenABP ….

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

Nican解释了equals部分,关于compareTo

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

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

我在测试中遇到了同样的问题,我想比较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; } 
  1. date.equals(stamp)返回true和stamp equals(date)返回false。 原因 :Date忽略了时间戳的纳秒部分,因为其他部分碰巧相等,所以结果是相等的。 小数秒 – 纳米 – 是分开的。当传递java.util.Date类型的值时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件是未知的。 有关详细信息,请参见此处

    1. date.compareTo(stamp)== 0返回false AND stamp.compareTo(date)== 0返回true。 原因 :根据这个bug, compareTo函数将表现得像它一样。

Timestamp的纳米值不是纳秒数 – 它是毫微秒分辨率的毫秒数(即分数秒)。 因此,在Timestamp构造函数中,它将super上的时间设置为毫秒。 因此,对于成员fastTime (在Date的compareTo() ), Timestamp总是具有比相应Date更低的值(当然,除非它没有小数秒)。

检查第 110行的时间戳来源 。

尝试使用像这样的“字符串”重新创建对象日期

 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 

我已经解决了将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"); } 

希望这可以帮助。

看一下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。 此外,这里是日期源代码: http : //www.docjar.com/html/api/java/util/Date.java.html ,由于Timestampinheritance了Date,它可以比较它。

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

equals(Object) javadocs说:

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

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

关于实现inheritance和类型inheritance的一个小注释..

“对象的类定义了对象的实现方式。相比之下,对象的类型仅指其接口。类inheritance(实现inheritance)根据另一个对象的实现定义对象的实现。类型inheritance描述何时可以使用对象另一个地方。“

JAVADOC表示,时间戳和日期类具有实现inheritance。