首先看一个测试用例:
import org.junit.Assert; import org.junit.Test; import java.sql.Time; import java.sql.Timestamp; import java.util.Date; /** * <p>User: Zhang Kaitao * <p>Date: 13-5-26 下午5:43 * <p>Version: 1.0 */ public class DateTest { //when only millisecond part is different @Test public void testDateAfter() { Date d1 = new Date(1369461400000L); Date d2 = new Date(1369461400001L); Assert.assertTrue(d2.after(d1)); } @Test public void testTimestampAfterOK() { Timestamp d1 = new Timestamp(1369461400000L); Timestamp d2 = new Timestamp(1369461400001L); Assert.assertTrue(d2.after(d1)); } @Test public void testTimestampCastToDateAfterFail() { Date d1 = new Timestamp(1369461400000L); Date d2 = new Timestamp(1369461400001L); Assert.assertFalse(d2.after(d1)); } @Test public void testDateCompare() { Date d1 = new Date(1369461400000L); Date d2 = new Date(1369461400001L); Assert.assertTrue(d2.compareTo(d1) == 1); } @Test public void testTimestampCompareOK() { Timestamp d1 = new Timestamp(1369461400000L); Timestamp d2 = new Timestamp(1369461400001L); Assert.assertTrue(d2.compareTo(d1) == 1); } @Test public void testTimestampCastToDateCompareOK() { Date d1 = new Timestamp(1369461400000L); Date d2 = new Timestamp(1369461400001L); Assert.assertTrue(d2.compareTo(d1) == 1); } }
大家可能看到testTimestampCastToDateAfterFail测试用例,d2.after(d1) 是false。
从网络上找了下,类似的bug如下:
http://bugs.sun.com/view_bug.do?bug_id=5008227
EVALUATION
This is a side effect caused by the 4340146 fix. Because Date.after() no longer calls getTime(), after() and equals() in Timestamp work compare different time values.
Timestamp.after and before should call compareTo which works correctly.
###@###.### 2004-03-15
其也是建议使用compareTo,而不是after/before。
还一篇是在stackoverflow上的:
http://stackoverflow.com/questions/15629222/java-sql-timestamp-comparison-bug
有一个compareTo的,也有过类似的问题,不过1.5已经修复。
http://icedtea.classpath.org/bugzilla/show_bug.cgi?id=676
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103041
其中的主要问题是:
Timestamp没有重载(public boolean after(Date d) );
Date中的fastTime 存储了毫秒值;但Timestamp的fastTime只存储到秒,毫秒值部分存储到nanos部分。具体细节可参考jdk代码。
有细心的朋友可能注意到了:我的d1 和 d2 实际上是Timestamp类型啊
@Test public void testTimestampCastToDateAfterFail() { Date d1 = new Timestamp(1369461400000L); Date d2 = new Timestamp(1369461400001L); Assert.assertFalse(d2.after(d1)); }
那比较的时候,怎么会发生这种事情?而且有朋友还注意到了compareTo就没有这个问题。
首先看下jdk的文档:
注:此类型由 java.util.Date 和单独的毫微秒值组成。只有整数秒才会存储在 java.util.Date 组件中。小数秒(毫微秒)是独立存在的。传递不是 java.sql.Timestamp 实例的对象时,Timestamp.equals(Object) 方法永远不会返回 true,因为日期的毫微秒组件是未知的。因此,相对于 java.util.Date.equals(Object) 方法而言,Timestamp.equals(Object) 方法是不对称的。此外,hashcode 方法使用底层 java.util.Date 实现并因此在其计算中不包括毫微秒。
鉴于 Timestamp 类和上述 java.util.Date 类之间的不同,建议代码一般不要将 Timestamp 值视为 java.util.Date 的实例。Timestamp 和 java.util.Date 之间的继承关系实际上指的是实现继承,而不是类型继承。
此处 可能已经注意到了:
1、Timestamp 和 java.util.Date 之间的继承关系实际上指的是实现继承,而不是类型继承。
2、Timestamp.equals(Object) 方法是不对称的。此外,hashcode 方法使用底层 java.util.Date 实现并因此在其计算中不包括毫微秒。
此处我们大体能概括出来:
1、Date和Timestamp并不是继承关系。。。。。
2、after方法也是双向不对称的。。。。
关于不对称,再来看两个测试用例:
@Test public void testTimestampAfterOK2() { Date d1 = new Timestamp(1369461400000L); Timestamp d2 = new Timestamp(1369461400001L); Assert.assertFalse(d2.after(d1)); } @Test public void testTimestampAfterOK3() { Timestamp d1 = new Timestamp(1369461400000L); Date d2 = new Timestamp(1369461400001L); Assert.assertFalse(d2.after(d1)); }
主要原因是Timestamp没有重载(public boolean after(Date d) );而且仔细思考了下,如果从JDK文档上总结的话,不应该算作bug;但是从compareTo上看那就应该是bug。
真是混乱啊。。。 JSR 310 新的日期和时间API 在JDK8会添加进去
更好的选择是使用如joda-time/或者使用JSR-310。
比较时应该注意自己的情况,如果不知道当前类型(Date/Timestamp)那么请使用compareTo;是什么使用日期,应该要做好单元测试。有了单元测试,才有了保险。。。。
此处如果你的java.sql.Time,JDK也没有提供只比较Time部分的API。。。。。。。
commons-lang也没有提供类似的API,不过commons-lang也在犹豫是否添加:
DateUtils.isAfterDay
https://issues.apache.org/jira/browse/LANG-400
=================分割线==================================================
关于mysql的Timestamp:
假设表结构是:
create table `personal_message`( `id` bigint not null auto_increment, `sender_id` bigint, `receiver_id` bigint, `send_date` timestamp, }
如果有人执行:
update receiver_id=1 where id=?
你可能会发现:你的send_date改成了当前时间!具体原因仔细看mysql官方文档,官方文档说的很明白:
http://dev.mysql.com/doc/refman/5.6/en/timestamp-initialization.html
因为像send_date发送时间,一旦确定是不需要改的,解决方案是只加个默认值:
`send_date` timestamp default 0,
而且mysql还一个问题是timestamp不是存储到毫秒值,所以如果想存到毫秒值级别 请使用如bigint直接存储毫秒值。
=================分割线==================================================
jpa中映射日期类型,可以使用:
@Temporal(TemporalType.TIMESTAMP) private Date sendDate;
TemporalType表示日期类型,分别对应:
public enum TemporalType { /** * Map as <code>java.sql.Date</code> */ DATE, /** * Map as <code>java.sql.Time</code> */ TIME, /** * Map as <code>java.sql.Timestamp</code> */ TIMESTAMP }
如果想在hibernate中映射其他日期类型,如Calendar:
可以使用hibernate的@org.hibernate.annotations.Type,如@Type(type = "timestamp"),默认支持的是:
Type mappings from java.util.Date and its subclasses to SQL types DATE, TIME and TIMESTAMP (or equivalent).
calendar, calendar_date
Type mappings from java.util.Calendar to SQL types TIMESTAMP and DATE (or equivalent).
http://docs.jboss.org/hibernate/orm/4.2/manual/en-US/html_single/#mapping-types
当然,你也可以选择如joda-time,已经有hibernate集成了:
https://github.com/JodaOrg/joda-time-hibernate
如果你存储到数据库的是毫秒值,取回来想变成日期,可以自定义UserType,这个可以参考:
对于hibernate 写原生SQL时,还需要注意这个问题:《hibernate createSQLQuery的问题》,解决方案是:
如果hibernate4 addScalar("m_apiendtime ",TimestampType.INSTANCE)
其他 addScalar("m_apiendtime ",Hibernate.TIMESTAMP)
如果有些拿不准的,可以考虑上单元测试,好处多多。
相关推荐
这个版本的主要目标是充分利用JDK 8的新特性,如lambda表达式、Stream API和新日期时间API。Spring 5.0对反应式编程的支持是一大亮点,它引入了Spring WebFlux模块,这使得开发者可以构建非阻塞、高性能的Web应用...
标题中的"jdk api 1.8、jQuery3.1-api、jQuery3.3.1-api、jqueryapi2.2"代表了两个主要的IT技术领域:Java开发工具包(Java Development Kit, JDK)和jQuery JavaScript库的不同版本。这些API文档是开发者在编写代码...
4. **Date和Time API的增强**:用`java.time`包取代了过时的`java.util.Date`和`java.util.Calendar`,提供了更强大且易用的时间日期处理功能。 5. **方法引用**:允许直接引用类或对象的方法,进一步减少了代码量...
4. Date/Time API更新:JDK 8对日期和时间API进行了重构,提供了新的java.time包,包括LocalDate、LocalTime、LocalDateTime和ZonedDateTime等类,更加符合现代编程需求。 5. 默认方法:接口中可以定义具有实现的...
每个JDK的更新(如u25、u111等)通常会修复之前版本中的bug,提高性能,以及添加一些新的特性和功能。例如,u181可能是为了修复安全漏洞或性能优化,而u201可能包含了一些重要的安全更新。这些版本的JDK适用于...
Java 8对日期和时间API进行了重大重构,引入了`java.time`包,提供了更强大、更易用的日期和时间处理类,如LocalDate、LocalTime、LocalDateTime等。 ### 2. JDK 1.8.0_161的更新与改进 JDK 1.8.0_161是一个重要的...
4. **日期与时间API的增强**:Java 8引入了全新的java.time包,替代了之前不完善的日期和时间API,提供了更强大的日期、时间和时区处理功能。 5. **默认方法**:接口中新增了默认方法,允许接口定义方法的实现,这...
5. **Date与Time API的改进**:Java 8对日期和时间API进行了全面改革,引入了`java.time`包,提供了更强大、更易用的日期、时间和时区处理功能。 6. **新的 Nashorn JavaScript引擎**:JDK 1.8包含了一个新的...
5. Date和Time API改进:Java 8对日期和时间的API进行了全面升级,提供了更加强大和易于使用的类,如LocalDate、LocalTime和ZonedDateTime。 6. Optional类:这个类用于表示可能为空的值,有助于防止...
**JDK 1.8** (也称为Java 8)是另一个重大升级,带来了诸如Lambda表达式、函数式编程接口(如java.util.Function)、日期和时间API(java.time包)、默认方法在接口中、新的Stream API、改进的并发库等革新。...
总的来说,JDK 1.8.0_101是Java 8的一个重要版本,它带来了Lambda表达式、Stream API、接口默认方法和新的日期时间API等强大功能,同时持续进行安全性和性能的改进。对于Java开发者而言,理解和掌握这些特性对于提高...
在日期和时间处理上,引入了新的java.time包,替换了原有的日期和时间API,提供了更强大且易于使用的类。 JDK1.8U221作为该版本的一个更新,通常会包含之前版本的bug修复和性能提升。这些更新可能涉及到JVM的优化,...
Java 8是Java历史上的一个里程碑,引入了诸多新特性,如lambda表达式、函数式接口、流API(Stream API)、日期与时间API、默认方法以及新的并发改进等。这些特性极大地提升了Java的编程效率和灵活性。 Lambda表达式...
在JDK 1.8.0_241这个特定版本中,可能包括了一些安全更新、性能优化和bug修复,这些都是Oracle对Java平台持续维护和改进的一部分。对于开发者来说,及时更新到最新的JDK版本可以确保程序的稳定性和安全性。 关于...
附带的`jdk1.6.txt`文件可能包含了关于这个版本的详细信息,比如发行日期、已知问题、修复的Bug列表以及使用指南等。开发者应该仔细阅读这些文档,以便更好地理解和使用JDK 1.6.0_45。 总的来说,JDK 1.6.0_45对于...
5. **日期和时间API**:Java 8对日期和时间API进行了全面升级,引入了`java.time`包,替代了之前复杂的`java.util.Date`和`java.util.Calendar`。 6. **新的类型接口**:如`Optional<T>`,它是一个容器对象,可能...
4. **日期和时间API**:Java 8提供了新的java.time包,替代了过时的java.util.Date和java.util.Calendar,使日期和时间操作更为简单直观。 5. **默认方法**:接口中可以定义带实现的方法,使得接口可以扩展而不会...
- **日期和时间API**:Java 8改进了日期和时间的处理,提供了`java.time`包,取代了过时的`java.util.Date`和`java.util.Calendar`。 - **默认方法**:接口中可以定义带有实现的方法,这使得接口在不破坏向后兼容性...
在日期时间API方面,JDK1.8用java.time包取代了旧的java.util.Date和Calendar,提供了更直观、线程安全的API,使得日期和时间的操作更加简单和易用。 最后,JDK1.8还引入了Method References,它允许直接引用已有...
在JDK 1.8.0_20这个具体版本中,除了包含上述核心特性外,还可能包括了一些安全更新、性能优化和bug修复。安装此版本的JDK后,开发者可以获得Java 8的所有功能,并能确保程序在最新的环境下运行。 总的来说,JDK ...