将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类有一个明智的选择类设计。 所以你可以按预期使用equals
和compareTo
。 请注意,具有从UTC或时区偏移的类还提供isEqual
, isBefore
和isAfter
方法。 这些方法通过考虑时间轴上的时刻,它们的时间顺序来进行比较。 equals
和compareTo
方法也考虑偏移或时区。
最大限度地减少java.sql的使用,同时最大限度地使用java.time,这使得问题的问题没有实际意义。
在Hibernate中,为java.time使用转换器。
JDBC 4.2
从JDBC 4.2及更高版本开始,您根本不需要使用遗留类。 您可以通过getObject
和setObject
方法直接与数据库交换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.Date
, Calendar
和SimpleDateFormat
。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
要了解更多信息,请参阅Oracle教程 。 并搜索Stack Overflow以获取许多示例和解释。 规范是JSR 310 。
您可以直接与数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC驱动程序 。 不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
- Java SE 8 , Java SE 9 , Java SE 10及更高版本
- 内置。
- 带有捆绑实现的标准Java API的一部分。
- Java 9增加了一些小function和修复。
- Java SE 6和Java 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的试验场。 您可以在这里找到一些有用的课程,如Interval
, YearWeek
, YearQuarter
等。
Nican解释了equals
部分,关于compareTo
:
-
Timestamp
有一个compareTo(Date)
方法,可以在内部将其转换为Timestamp
-
Date
通过向下转换进行比较(因为Timestamp
是它的子类); 但正如javadoc所说:“Timestamp和java.util.Date之间的inheritance关系实际上表示实现inheritance,而不是类型inheritance”
在我看来,这当然是一个可怕的想法。
我在测试中遇到了同样的问题,我想比较java.util.Date
和java.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; }
-
date.equals(stamp)返回true和stamp equals(date)返回false。 原因 :Date忽略了时间戳的纳秒部分,因为其他部分碰巧相等,所以结果是相等的。 小数秒 – 纳米 – 是分开的。当传递java.util.Date类型的值时,Timestamp.equals(Object)方法永远不会返回true,因为日期的nanos组件是未知的。 有关详细信息,请参见此处
- 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。