当前位置:网站首页>我被这个浏览了 746000 次的问题惊住了
我被这个浏览了 746000 次的问题惊住了
2022-07-29 01:47:00 【JavaMonsterr】
给大家分享一个我最近发现的有点意思,但是卵用不大的小知识点。
先给你搞个程序看一下:
public class MainTest {
public static void main(String[] args) throws Exception {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = simpleDateFormat.parse("1900-01-01 08:00:00");
System.out.println(simpleDateFormat.format(date));
}
}
你说上面的程序逻辑就是一个简单的时间格式化,你说输出结果是什么?
只是需要瞟一眼就知道,肯定是输出这个结果呀:
1900-01-01 08:00:00
但是,你把上面的程序拿出来,直接跑起来,你会发现输出结果竟然是这样的:
1900-01-01 08:05:43
当时就懵逼了。
我知道时差 8 小时,是因为有时区问题。
我知道时间差 1 小时,是因为有夏令时的原因。
但是这里差了 5 分 43 秒,有零有整,就让我有点摸不着头脑了。

上面这个案例就是一个读者分享给我的,他们在数据库里面默认时间是 1900-01-01,再加上时区问题,刚好变成了 1900-01-01 08:00:00,于是在通过程序做数据迁移的时候就踩到了这个莫名其妙的时间问题。

同时他还给我附送了一个关于这个 bug 的链接:
https://bugs.openjdk.java.net/browse/JDK-8266262

我乍一看,这个 bug 还挺新的呢,属于今年提出来的。
仔细又看了一眼发现是和之前的 bug 重复了:

但是这里提到了原因:
他说可以看一下这个链接 https://www.timeanddate.com/time/zone/china/shanghai?year=1900
这里面,在 1900 年的时候,发生了一个变化:
The timezone offset was UTC +8:05:43 hours all of the period.
虽然我没太看明白具体是什么意思,但是我看到了“5 分 43 秒”:

我理解就是由于时区的变化,导致时间发生了重置。
接着我顺藤摸瓜,在 stackoverflow 上找到了这个:
https://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result
当时我就震惊了。
这个 10 年前被提出的问题居然已经被浏览过 746k 次了,非常热门的问题了,我居然没注意到过:

这个问题具体是这样的:

你就大概瞟一眼,我给你翻译翻译。
提问者说,他发现 1927-12-31 23:54:07 到 1927-12-31 23:54:08 之间差了 353 秒,按理来说应该是 1 秒才对啊?
但是把时间改成下面这样,又正常了:
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
我把程序粘出来你也可以跑一下,看看结果非常的神奇啊:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str3 = "1927-12-31 23:54:07";
String str4 = "1927-12-31 23:54:08";
Date sDt3 = sf.parse(str3);
Date sDt4 = sf.parse(str4);
long ld3 = sDt3.getTime() /1000;
long ld4 = sDt4.getTime() /1000;
System.out.println(ld4-ld3);
}
但是当我跑了一遍之后,我发现:我去,说好的 353 秒呢?
跑出来怎么是 1 秒呢,毫无毛病啊:

我甚至怀疑是 jdk 版本的问题,于是我换了 jdk 9,11,15 都跑了一下,都是 1 秒。
这就很奇怪了啊。
感觉这个问题提的就有问题啊。

但是当我读了下面最高赞的答案之后,我才仿佛窥见了一点端倪。
这个回答比较长,我先全部截图下来给你看看:

比较长的原因是作者修改了几次回答。
为什么会修改回答呢?
且往后看吧,一切的答案都藏在这里面。
我选关键的给你说。
首先看第一段:

他说(1927年) 12 月 31 日的时候,上海的时区发生了变化。
而关于 1927 年上海的详细情况,他附上了一个超链接,这个超链接就是前面出现的网站,点进去之后是这样的:

但是这个里面显示:
No further time changes in 1927 in Shanghai
翻译过来就是:1927 年上海的时间没有进一步变化。
这特么就和他下面说的那一坨内容对不上了啊?
他下面说,在 1927 年底的午夜时分,时钟往回走了 5 分 52 秒。因此,"1927-12-31 23:54:08"实际上发生了两次,而 Java 取的是第二次的的时刻,因此存在差异。
看到这里其实我都懵逼了,这玩意前后不符啊,于是我又接着开始搜索。
直到我发现了这个:
https://coolshell.cn/articles/5075.html/comment-page-2#comments
这也是十年前的文章。
这里面作者把当时网站截了个图:

当年的截图显示:
在1927年12月31日23:59:59时,往后面的一秒应该是1928年1月1日 0:0:0,但是这个时间被往后调整了5分52秒,而成了,1927年12月31日的,23:54:08,于是,完成了352秒的穿越。
这说明了什么?
说明数据发生了篡改,有人篡改了网页上的信息!

到底是怎么回事呢?
我们回到 stackoverflow 接着往下看:

这是他第一次修改回答,因为 History changes...
历史发了变化了...
他这里说,如果用 TZDB 的 2013a 版本的数据,原来的问题将不再表现出完全相同的行为。
在 2013a 中,结果将是 358 秒,过渡时间为 23:54:03,而不是 23:54:08。
他提到了一个 TZDB,这是个啥东西呢?
我也不知道,但是我搜索了一下。

他应该说的是这个的东西。
https://www.iana.org/time-zones
看名字你也知道了,它是一个时区数据库,里面应该是维护的时区相关的数据。
也就是说,在这个时区数据库里面,用 2013a 版本的数据,前面的代码就是另外一种输出了。
也就是说数据确实发生了变化。
而关键的回答在于下一次编辑:

History has changed again...
历史再次发生了变化。
在这个时区数据库里面,2014f 版本中,变化的时间已经移到了1900-12-31,现在只是一个 343 秒的变化。
343 秒?
不就是我们前面的 5 分 43 秒吗?

好了,现在时差能对上了,343 秒,但是时间还是没对上啊。
我们的测试时间 1900-01-01 08:00:00,他这里写的时间是 1900-12-31。
差了整整一年呢?
好,我们看他最后一次编辑的内容:

我个人理解他要表达的意思是这样的。
Java 为了在时区上统一标准,所以来了个一刀切的政策。
统一的标准就是让 UTC 时区下 1900 年之前的任何瞬间都是标准时间。
至于产生的时差嘛...
就在最开始的时候补上去吧。
所以,1900-01-01 00:00:00 加上 8 小时时差,是 1900-01-01 08:00:00,在这个基础上预先加上 27 年后来自 1927-12-31 那个午夜由于时间回拨带来的 343 秒。
1900-01-01 08:05:43,我个人认为就是这样来的。
而前面 stackoverflow 里面对应的那个程序,我们现在执行是输出 1,但是在 10 年前,输出结果确实是 353 。
就像我把程序改成这样:

最终的输出结果不是 1,而是 -342。
时间,发生了“倒流”。
好了,又是一个没啥卵用的知识点。
最后,再补充两个冷知识。
第一个是我在 jdk bug 列表里面追溯了一下,能找到最早提出相关问题的时间是 2005 年:
https://bugs.openjdk.java.net/browse/JDK-6281408

在这个里面,官方是这样回复的:

这个问题不会被修复,以避免任何兼容性问题。
意思就是:问题我知道了,但是这玩意不太好弄,bug 先变成 feature 吧,就先这样吧。
别问,问就是有历史原因在里面。
第二个冷知识是,前面提到的,时区在 1927 年发生了变化。
你知道为什么吗?
我在某网站上找到了这样的描述:
https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9C%8B%E6%99%82%E5%8D%80

1928 年,就是民国 17 年。
那一年,中共军史上最早的红军,中国工农红军第四军成立。
那一年,毛主席在井冈山建立农村革命根据地。
那一年,星星之火,已成燎原之势。
边栏推荐
- 自定义mvc原理和框架实现
- Awvs cannot start problem
- Comprehensive use method of C treeview control
- Day 15 (VLAN related knowledge)
- 【上传图片可剪裁-1】
- Jmeter之BeanShell生成MD5加密数据写入数据库
- RGBD点云降采样
- 开启TLS加密的Proftpd安全FTP服务器安装指南
- 【上传图片2-可裁剪】
- Quanzhi t3/a40i industrial core board, 4-core [email protected] The localization rate reaches 100%
猜你喜欢

响应式织梦模板化妆美妆类网站
![[electronic components] constant voltage, amplify the current of the load (triode knowledge summary)](/img/07/d5861404a76a0fb7d6d5f930a4a66a.png)
[electronic components] constant voltage, amplify the current of the load (triode knowledge summary)

Responsive dream weaving template home decoration website

How to guarantee password security? How does the secure browser manage passwords?

RGBD点云降采样

Try to understand the essence of low code platform design from another angle

Cookies and sessions

Comprehensive use method of C treeview control

物联网开发--MQTT消息服务器EMQX

JetPack--Navigation实现页面跳转
随机推荐
发布融资需求1.29亿元,大科城项目路演持续浇灌科创“好苗子”
2022.7.28-----leetcode.1331
第3章业务功能开发(线索备注的删除和修改)
向量相似度评估方法
即时通讯场景下安全合规的实践和经验
聊聊接口性能优化的11个小技巧
C language improvement (I)
Navigation--实现Fragment之间数据传递和数据共享
Resnet50 + k-fold cross validation + data enhancement + drawing (accuracy, recall, F value)
【质量】代码质量评价标准
[simple implementation and extension of one · data | array heap]
QT qstackedwidget multi interface switching
2022.7.27-----leetcode.592
Leetcode 242. valid anagram
费曼学习法(符号表)
Complete collection of common error handling in MySQL installation
Understand the clock tree in STM32 in simple terms
Responsive Zhimeng template decoration design website
防止重复点击
TI C6000 TMS320C6678 DSP+ Zynq-7045的PS + PL异构多核案例开发手册(2)