java - 将日期对象与 Java 中的时间戳进行比较

标签 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 中,它指出:

Note: This type is a composite of a java.util.Date and a separate nanoseconds value. Only integral seconds are stored in the java.util.Date component. The fractional seconds - the nanos - are separate. The Timestamp.equals(Object) method never returns true when passed a value of type java.util.Date because the nanos component of a date is unknown. As a result, the Timestamp.equals(Object) method is not symmetric with respect to the java.util.Date.equals(Object) method. Also, the hashcode method uses the underlying java.util.Date implementation and therefore does not include nanos in its computation.

Due to the differences between the Timestamp class and the java.util.Date class mentioned above, it is recommended that code not view Timestamp values generically as an instance of java.util.Date. The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.



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

编辑:当我使用 equals 方法检查两个日期时出现此问题,但其中一个 Date 对象来自 Hibernate 类并且调试时我看到该对象包含一个时间戳。所以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 类是一个hack,一个糟糕的hack。与 java.util.Date/.Calendar 一样,它们是糟糕的设计选择的结果。

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

时间

旧的日期时间类已被 java.time 取代内置于 Java 8 及更高版本中的框架。这些新类由 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 或时区偏移量的类也提供 isEqual , isBefore , 和 isAfter方法。这些方法通过考虑时间轴上的时刻,它们的时间顺序来进行比较。 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.Date , Calendar , & SimpleDateFormat .

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

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

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

从哪里获得 java.time 类?
  • Java SE 8 , Java SE 9 , Java SE 10 , 然后
  • 内置。
  • 具有捆绑实现的标准 Java API 的一部分。
  • Java 9 添加了一些小功能和修复。
  • Java SE 6Java SE 7
  • ThreeTen-Backport 中,大部分 java.time 功能被反向移植到 Java 6 和 7。 .
  • Android
  • java.time 类的更高版本的 Android 捆绑实现。
  • 对于早期的 Android (<26),ThreeTenABP项目适应 ThreeTen-Backport (上文提到的)。见 How to use ThreeTenABP… .

  • ThreeTen-Extra项目使用附加类扩展 java.time。该项目是 future 可能添加到 java.time 的试验场。您可能会在这里找到一些有用的类,例如 Interval , YearWeek , YearQuarter , 和 more .

    关于java - 将日期对象与 Java 中的时间戳进行比较,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8929242/

    相关文章:

    java - Heroku:如何指定JVM buildpack非java项目的路径?

    java - 如何在对 Spring MVC Controller 的 GET 请求中接受日期参数?

    Mysql计算包含文本的同一字段中时间戳之间的时间差?

    java - 使用 EWS java API 将 Content-Type 设置为 text/plain

    java - JDBC中的命名参数

    mysql - Perl 和 MYSQL - 选择年-月-日小时 :minute:seconds (unix? ) 样式时间戳之间的数据

    time - 在 Go 中获取 Unix 时间戳的正确方法是什么

    c++ - 通过 SWIG 从 Python 访问 UtcTimeStamp

    java - 如何在Java中重新对井字棋的二维数组进行移动?

    php - 搜索文档日期低于日期选择器中所选日期的所有记录