温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

你可能不会注意的Timestamp

发布时间:2020-07-04 06:52:26 来源:网络 阅读:5175 作者:chellman 栏目:软件技术

提起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());//2145887999000
System.out.println(t2.getTime() == new Long(Integer.MAX_VALUE) * 1000);//false
Timestamp t3 = new Timestamp(new Long(Integer.MAX_VALUE) * 1000);
System.out.println(t3);//2038-01-19 11:14:07.0
Timestamp t21 = Timestamp.valueOf("9999-12-31 23:59:59");
System.out.println(t21.getTime());//253402271999000
Timestamp 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));//true
System.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, 我们在实际设计开发的时候尽量避免这种不舒服的设计,结合继承,封装,多态等多种手段确保我们设计的鲁棒。


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI