千家信息网

你可能不会注意的Timestamp

发表于:2025-01-27 作者:千家信息网编辑
千家信息网最后更新 2025年01月27日,提起java里面的时间戳,相信很多人都用过。不就是java.sql.Timestamp类,两个构造器,13个方法,这也许属于java中最简单的基础类了。俗话说淹死的都是会游泳的,同样在开发中让我们栽跟
千家信息网最后更新 2025年01月27日你可能不会注意的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安全错误 数据库的锁怎样保障安全 广州万户网络技术有限公司骗子 网络安全教育简单的图片 软件开发项目的科学性先进性 开局就给管理权限的服务器 软件开发后怎么与硬件对接 徐州市网络安全攻防大赛第二届 数据库建表例子6 app后端用什么软件开发 黄石市网络安全宣传周答题 软件开发退出壁垒 数据库可以设置时间再执行操作吗 数据库报负一 产品经理的ai数据库 2021网络安全保研面试内容 软件测试占软件开发的多少 无尽之剑无登录服务器失败 互联网大会科技观察 设有学生选修课程的数据库 用电脑做服务器有什么用 商汤科技属于几线互联网公司 网络安全法 6.1 脉冲神经网络技术 软件开发公司前十名甲骨文 电脑登录不了服务器数据库 数据库微课的总结报告 惠普dl380服务器操作手册 软件开发演化模型的特点 数据库和多媒体的未来发展方向 软件开发模型 敏捷 国家网络安全周与360
0