将 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));
我会期待一个真实的,真实的,真实的,虚假的.正因为如此:
I´ll be expecting a true, true, true, false. Because of this:
在 java.sql.Timestamp 的 javadoc 中,它指出:
In the javadoc for java.sql.Timestamp, it states:
注意:此类型是 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实施,因此不包括纳米计算.
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.
由于 Timestamp 类和上面提到的java.util.Date类,建议代码不要通常将时间戳值视为 java.util.Date 的一个实例.Timestamp 与 java.util.Date 的继承关系真正表示实现继承,而不是类型继承.
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.
但相反,我会得到一个真、假、真、假.有什么想法吗?
But instead I´ll get a true, false, true, false. Any ideas?
当我使用 equals 方法检查两个日期时出现此问题,但其中一个日期对象来自 Hibernate 类并且调试我看到该对象包含一个时间戳.所以equals方法评估为false,然后我发现:http://mattfleming.com/node/141
This problem appear when a I was checking two Dates with the equals method, but one of the Date object come from a Hibernate class and debugging I see that the object contains a TimeStamp. So the equals method evaluate to false, then I found this: http://mattfleming.com/node/141
但是当我尝试代码时,我得到了不同的结果...如果我不能同时使用 equals 和 compareTo,我应该使用什么来检查 2 个日期是否相同?!?!
But when I try the code I get different results...if I can´t use neither equals and compareTo, what I should use to check if 2 Dates are the same?!?!
推荐答案
tl;dr
使用现代的 java.time 类代替那些麻烦的旧日期时间类.
tl;dr
Use the modern java.time classes instead of those troublesome legacy date-time classes.
myPreparedStatement.setObject(
… ,
Instant.now() // Capture the current moment in UTC.
)
旧的日期时间类设计不佳
更坦率地说,java.sql.Timestamp/.Date/.Time 类是一个 hack,一个糟糕的 hack.与 java.util.Date/.Calendar 一样,它们是设计选择不当的结果.
Old Date-Time Classes Poorly Designed
Put more bluntly, the java.sql.Timestamp/.Date/.Time classes are a hack, a bad hack. Like java.util.Date/.Calendar, they are the result of poor design choices.
java.sql 类型应尽可能简短地使用,仅用于将数据传入/传出数据库.不要用于业务逻辑和进一步的工作.
The java.sql types should be used as briefly as possible, used only for transfer of data in/out of the database. Do not use for business logic and further work.
旧的日期时间类已被 java.time 框架内置于 Java 8 及更高版本.这些新类由 JSR 310 定义,受到非常成功的 Joda-Time 库的启发,并由 ThreeTen-Extra 项目扩展.
The old date-time classes have been replaced by the java.time framework built into Java 8 and later. These new classes are defined by JSR 310, inspired by the highly successful Joda-Time library, and extended by the ThreeTen-Extra project.
最终我们应该会看到更新的 JDBC 驱动程序可以直接使用这些 java.time 类型.但直到那一天,我们需要转换为/从 java.sql 类型.对于此类转换,请调用添加到旧类的新方法.
Eventually we should see JDBC drivers updated to work directly with these java.time types. But until that day we need to convert to/from java.sql types. For such conversions, call new methods added to the old classes.
一个 Instant
是 UTC 时间线上的时刻,分辨率为 纳秒.
Instant instant = myJavaSqlTimestamp.toInstant();
去另一个方向:
java.sql.Timestamp ts = java.sql.Timestamp.valueOf( instant );
应用时区以获取挂钟时间.p>
Apply a time zone to get wall-clock time.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
java.time 类有一个干净、明智的类设计.因此,您可以按预期使用 equals
和 compareTo
.请注意,具有与 UTC 或时区偏移的类还提供 isEqual
、isBefore
和 isAfter
方法.这些方法通过考虑时间轴上的时刻及其时间顺序来进行比较.equals
和 compareTo
方法也会考虑偏移量或时区.
The java.time classes have a clean wisely-chosen class design. So you can use the equals
and compareTo
as expected. Note that the classes with an offset-from-UTC or time zone also offer isEqual
, isBefore
, and isAfter
methods. These methods compare by considering moments on the timeline, their chronological order. The equals
and compareTo
methods also consider the offset or time zone.
尽量减少 java.sql 的使用同时最大限度地使用 java.time 会使问题的问题没有实际意义.
Minimizing the use of java.sql while maximizing the use of java.time renders the Question’s issues moot.
在 Hibernate 中,使用 java.time 转换器.
In Hibernate, use converters for java.time.
从 JDBC 4.2 及更高版本开始,您根本不需要使用旧类.您可以通过 getObject
& 直接与数据库交换 java.time 对象.setObject
方法.
As of JDBC 4.2 and later, you need not use the legacy classes at all. You can directly exchange java.time objects with your database via the getObject
& setObject
methods.
myPreparedStatement.setObject( … , instant ) ;
和检索.
Instant instant = myResultSet.getObject( … , Instant.class ) ;
请注意,许多数据库无法以 java.time 中使用的纳秒级分辨率存储时刻.您可能希望显式截断而不是让您的 JDBC 驱动程序隐式执行此操作.
Note that many databases cannot store a moment with a resolution as fine as the nanoseconds used in java.time. You may want to truncate explicitly rather than letting your JDBC driver do so implicitly.
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
, 日历
, &SimpleDateFormat
.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
Joda-Time 项目,现在在 维护模式,建议迁移到 java.time 类.
要了解更多信息,请参阅 Oracle 教程.并在 Stack Overflow 上搜索许多示例和解释.规范是 JSR 310.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
您可以直接与您的数据库交换 java.time 对象.使用符合 JDBC 驱动程序/jeps/170" rel="nofollow noreferrer">JDBC 4.2 或更高版本.不需要字符串,不需要 java.sql.*
类.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
从哪里获得 java.time 类?
Where to obtain the java.time classes?
- Java SE 8,Java SE 9, Java SE 10 及更高版本
- 内置.
- 标准 Java API 的一部分,带有捆绑实现.
- Java 9 添加了一些小功能和修复.
- 大部分 java.time 功能都向后移植到 Java 6 &7 在 ThreeTen-Backport.
- java.time 类的 Android 捆绑包实现的更高版本.
- 对于早期的 Android (<26),ThreeTenABP 项目改编 ThreeTen-Backport(如上所述).请参阅如何使用 ThreeTenABP….
- Later versions of Android bundle implementations of the java.time classes.
- For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
ThreeTen-Extra 项目扩展了 java.time有额外的课程.该项目是未来可能添加到 java.time 的试验场.您可以在这里找到一些有用的类,例如
间隔
,YearWeek
,YearQuarter
和 更多.
相关文章