千家信息网

你可能不会注意的Timestamp

发表于:2024-11-23 作者:千家信息网编辑
千家信息网最后更新 2024年11月23日,提起java里面的时间戳,相信很多人都用过。不就是java.sql.Timestamp类,两个构造器,13个方法,这也许属于java中最简单的基础类了。俗话说淹死的都是会游泳的,同样在开发中让我们栽跟
千家信息网最后更新 2024年11月23日你可能不会注意的Timestamp

提起java里面的时间戳,相信很多人都用过。
不就是java.sql.Timestamp类,两个构造器,13个方法,这也许属于java中最简单的基础类了。

俗话说淹死的都是会游泳的,同样在开发中让我们栽跟头的往往都是耳熟能详的一些类库。

引子

首先让我们看看以下几行代码的输出结果吧


Timestamp t1 = new Timestamp(0);System.out.println(t1);Timestamp t2 = Timestamp.valueOf("2037-12-31 23:59:59");System.out.println(t2.getTime());System.out.println(t2.getTime() == new Long(Integer.MAX_VALUE) * 1000);Timestamp t3 = new Timestamp(new Long(Integer.MAX_VALUE) * 1000);System.out.println(t3);Timestamp t21 = Timestamp.valueOf("9999-12-31 23:59:59");System.out.println(t21.getTime());Timestamp t22 = new Timestamp(t21.getTime());System.out.println(t22);Date d1 = new Date(0);System.out.println(d1.equals(t1));System.out.println(t1.equals(d1));

如果你能很明确的说出每一个输出结果是什么以及为什么,那么你已经不需要继续往下看了。
如果你对一个或者更多的结果感到迷茫,就让我们来一起踩踩坑吧。

时间范围

要搞清楚Timestamp类的范围方法有很多,可以看文档、看源代码,写个代码测试一下或者搜索引擎看看别人怎么说。
当我们实践了上面的一种或者多种方法后我们再回过头来看看我们引子里的第一段和第二段代码的输出结果。


Timestamp t1 = new Timestamp(0);System.out.println(t1);//1970-01-01 08:00:00.0

有没有看着很熟悉?跟格林尼治标准时(计算机用的比较多的说法是UTC)就差8个小时,那也很好理解我们是东八区嘛。
换句话说Timestamp类的开始时间可以认为是格林尼治标准时,在不同时区使用会加上时区的偏移量。


Timestamp t2 = Timestamp.valueOf("2037-12-31 23:59:59");System.out.println(t2.getTime());//2145887999000System.out.println(t2.getTime() == new Long(Integer.MAX_VALUE) * 1000);//falseTimestamp t3 = new Timestamp(new Long(Integer.MAX_VALUE) * 1000);System.out.println(t3);//2038-01-19 11:14:07.0Timestamp t21 = Timestamp.valueOf("9999-12-31 23:59:59");System.out.println(t21.getTime());//253402271999000Timestamp t22 = new Timestamp(t21.getTime());System.out.println(t22);//9999-12-31 23:59:59.0

上面几段代码其实都是根据网上关于Timestamp的最大值做出的验证

第一种 2037-12-31 23:59:59(t2)

可以发现获取出来的毫秒数和Integer.MAX_VALUE差不多就是1000倍的差距,
那不妨推断一下这种说法的依据是在32位系统中存储毫秒数,无溢出情况下的最大月末或者年末。
接下来通过Integer.MAX_VALUE构造出来的时间(t3)是2038-01-19 11:14:07.0 也验证了我们的推断。

第二种 9999-12-31 23:59:59

这个时间是我们在目前时间格式下的最大时间了,通过t21,t22的验证发现通过,Timestamp类是可以存储这种时间的。
再回过头去看源代码,发现用于存储毫秒数的是Long而不是Integer,64位的Long完全可以到9999年嘛。

通过上面的验证我们可以确认Timestamp类的最大时间可以是9999-12-31 23:59:59

Tips:
实际使用的时候我们的数据需要存储到数据库。
以mysql为例,如果你想当然的将java的Timestamp直接就对应到数据库的Timestamp,你会发现两个数据类型范围并不一样。
摘抄一段mysql官方文档的说明:

The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. The supported range is '1000-01-01' to '9999-12-31'. The DATE type is used for values with a date part but no time part. MySQL retrieves and displays DATE values in 'YYYY-MM-DD' format. The supported range is '1000-01-01' to '9999-12-31'.
The DATETIME type is used for values that contain both date and time parts. MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD HH:MM:SS' format. The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.
The TIMESTAMP data type is used for values that contain both date and time parts. TIMESTAMP has a range of '1970-01-01 00:00:01' UTC to '2038-01-19 03:14:07' UTC.


在真实使用的时候将业务,java类库,数据库数据类型进行对照,尽可能的找出符合要求的组合。

Equals并不相等

用到了时间,当然不能不比较了,看看下面这段代码的输出吧


Date d1 = new Date(0);System.out.println(d1.equals(t1));//trueSystem.out.println(t1.equals(d1));//false

很有意思的结果,我们先来看看他是怎么做到的吧,看源码>>
Date.equals:


public boolean equals(Object obj) {   return obj instanceof Date && getTime() == ((Date) obj).getTime();}

由于Timestamp是继承自Date,并且在强转后高精度部分丢失导致getTime完全一致,所以第一个比较返回了true

Timestamp.equals:


public boolean equals(java.lang.Object ts) {        if (ts instanceof Timestamp) {                return this.equals((Timestamp)ts);                 } else {                        return false;      }                        }

判断Date并不是Timestamp类型,直接返回false;

代码没毛病,可是回到现实世界不就是说a = b 而b != a吗,作为一个严谨的程序员是不是总感觉哪里不舒服呢?

相信作者也是这样,先是在类上出现了这段说明

The inheritance relationship between Timestamp and java.util.Date really denotes implementation inheritance, and not type inheritance.

然后方法上还要补上

Note: This method is not symmetric with respect to the equals(Object) method in the base class.

大意就是:我写这个继承关系只是实现继承并不是类型继承(为了少写点代码,其实没毛关系),equals方法和父类的equals方法不对等(你们用错了我不负责啊)

总结

最后总结以下几点
1, java.sql.Timestamp可以接受的时间范围是1970-01-01 00:00:00 - 9999-12-31 23:59:59,具体使用的时候需要考虑时区带来的偏移量
2, 和数据库结合使用需要结合实际需求、数据库数据类型的具体范围选择合适的范围,不能仅仅通过名字来选择数据类型
3, Timestamp类的equals方法和父类的equals方法并不是对等的,只有两个比较的对象都是Timestamp的时候才能返回一致的结果
4, 我们在实际设计开发的时候尽量避免这种不舒服的设计,结合继承,封装,多态等多种手段确保我们设计的鲁棒。


时间 数据 方法 代码 类型 结果 范围 数据库 时候 最大 就是 存储 输出 验证 两个 实际 时区 设计 舒服 一致 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 优化网络安全技术防范服务要大力 网络技术支付服务报告 信宜佳峰网络技术服务部 什么是软件开发生命周期 网络安全手抄报小学生 一等奖 中国中西药数据库检索方式 计算机三级考试网络技术网课 数据库重载和重写的不同 中国电信通信网络安全监督局 hdg8服务器耗电量 奶块普拉达服务器在哪下载 摩尔庄园不同服务器啥意思 360网络安全密码是多少 苹果手机服务器验证码不知道 自己创建vpn服务器地址 平谷区专业网络技术服务口碑推荐 电费是用什么软件开发票的 服务器安装设置密码 工程网络安全会议内容 网络安全法考试活动 学网络技术专业技术怎么样 ajax需要数据库吗 网络技术的发展概况 创魔160服务器哪个赚钱 数据库基础教学总结报告 4.29首都网络安全日答题 上位机如何访问数据库 网络安全设备报废说明 数据库操作英文dml 校园网网络技术需求
0