当我测试这段代码时:
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个日期是否相同?!?!
答案 0 :(得分:6)
Nican解释了equals
部分,关于compareTo
:
Timestamp
有compareTo(Date)
方法,可将其内部转换为Timestamp
Date
通过向下转换进行比较(因为Timestamp
是它的子类);但正如javadoc所说:“Timestamp和java.util.Date之间的继承关系实际上表示实现继承,而不是类型继承”在我看来,这当然是一个可怕的想法。
答案 1 :(得分:5)
使用现代的 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 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类有一个明智的选择类设计。因此,您可以按预期使用equals
和compareTo
。请注意,具有偏离UTC或时区的类也提供isEqual
,isBefore
和isAfter
方法。这些方法通过考虑时间轴上的时刻,它们的时间顺序来进行比较。 equals
和compareTo
方法也会考虑偏移量或时区。
最大限度地减少java.sql的使用,同时最大限度地使用java.time,这使得问题的问题没有实际意义。
在Hibernate中,为java.time使用转换器。
从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 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类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:4)
我在测试中遇到了同样的问题,我想比较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;
}
答案 3 :(得分:3)
答案 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所说。