<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一個(gè)讓我驚掉下巴的時(shí)間格式化問(wèn)題!

          共 5230字,需瀏覽 11分鐘

           ·

          2022-01-01 16:36

          前沿技術(shù)早知道,彎道超車(chē)有希望
          積累超車(chē)資本,從關(guān)注DD開(kāi)始

          昨天,DD看到一篇挺有意思的文章,相關(guān)知識(shí)很冷門(mén),甚至可能你看完了覺(jué)得沒(méi)啥卵用。但作者探究真相的過(guò)程非常直接大家學(xué)習(xí),下面一起來(lái)看看吧!


          先給你搞個(gè)程序看一下:

          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));
              }
          }

          你說(shuō)上面的程序邏輯就是一個(gè)簡(jiǎn)單的時(shí)間格式化,你說(shuō)輸出結(jié)果是什么?

          只是需要瞟一眼就知道,肯定是輸出這個(gè)結(jié)果呀:

          1900-01-01 08:00:00

          但是,你把上面的程序拿出來(lái),直接跑起來(lái),你會(huì)發(fā)現(xiàn)輸出結(jié)果竟然是這樣的:

          1900-01-01 08:05:43

          當(dāng)時(shí)就懵逼了。

          我知道時(shí)差 8 小時(shí),是因?yàn)橛袝r(shí)區(qū)問(wèn)題。

          我知道時(shí)間差 1 小時(shí),是因?yàn)橛邢牧顣r(shí)的原因。

          但是這里差了 5 分 43 秒,有零有整,就讓我有點(diǎn)摸不著頭腦了。

          上面這個(gè)案例就是一個(gè)讀者分享給我的,他們?cè)跀?shù)據(jù)庫(kù)里面默認(rèn)時(shí)間是 1900-01-01,再加上時(shí)區(qū)問(wèn)題,剛好變成了 1900-01-01 08:00:00,于是在通過(guò)程序做數(shù)據(jù)遷移的時(shí)候就踩到了這個(gè)莫名其妙的時(shí)間問(wèn)題。

          同時(shí)他還給我附送了一個(gè)關(guān)于這個(gè) bug 的鏈接:

          https://bugs.openjdk.java.net/browse/JDK-8266262

          我乍一看,這個(gè) bug 還挺新的呢,屬于今年提出來(lái)的。

          仔細(xì)又看了一眼發(fā)現(xiàn)是和之前的 bug 重復(fù)了:

          但是這里提到了原因:

          他說(shuō)可以看一下這個(gè)鏈接https://www.timeanddate.com/time/zone/china/shanghai?year=1900

          這里面,在 1900 年的時(shí)候,發(fā)生了一個(gè)變化:

          The timezone offset was UTC +8:05:43 hours all of the period.

          雖然我沒(méi)太看明白具體是什么意思,但是我看到了“5 分 43 秒”:

          我理解就是由于時(shí)區(qū)的變化,導(dǎo)致時(shí)間發(fā)生了重置。

          接著我順藤摸瓜,在 stackoverflow 上找到了這個(gè):

          https://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result

          當(dāng)時(shí)我就震驚了。

          這個(gè) 10 年前被提出的問(wèn)題居然已經(jīng)被瀏覽過(guò) 746k 次了,非常熱門(mén)的問(wèn)題了,我居然沒(méi)注意到過(guò):

          這個(gè)問(wèn)題具體是這樣的:

          你就大概瞟一眼,我給你翻譯翻譯。

          提問(wèn)者說(shuō),他發(fā)現(xiàn) 1927-12-31 23:54:07 到 1927-12-31 23:54:08 之間差了 353 秒,按理來(lái)說(shuō)應(yīng)該是 1 秒才對(duì)啊?

          但是把時(shí)間改成下面這樣,又正常了:

          String str3 = "1927-12-31 23:54:07";  
          String str4 = "1927-12-31 23:54:08";

          我把程序粘出來(lái)你也可以跑一下,看看結(jié)果非常的神奇啊:

          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);
          }

          但是當(dāng)我跑了一遍之后,我發(fā)現(xiàn):我去,說(shuō)好的 353 秒呢?

          跑出來(lái)怎么是 1 秒呢,毫無(wú)毛病啊:

          我甚至懷疑是 jdk 版本的問(wèn)題,于是我換了 jdk 9、11、15 都跑了一下,都是 1 秒!

          這就很奇怪了啊。

          感覺(jué)這個(gè)問(wèn)題提的就有問(wèn)題啊。

          但是當(dāng)我讀了下面最高贊的答案之后,我才仿佛窺見(jiàn)了一點(diǎn)端倪。

          這個(gè)回答比較長(zhǎng),我先全部截圖下來(lái)給你看看:

          比較長(zhǎng)的原因是作者修改了幾次回答。

          為什么會(huì)修改回答呢?

          且往后看吧,一切的答案都藏在這里面。

          我選關(guān)鍵的給你說(shuō)。

          首先看第一段:

          他說(shuō)(1927年) 12 月 31 日的時(shí)候,上海的時(shí)區(qū)發(fā)生了變化。

          而關(guān)于 1927 年上海的詳細(xì)情況,他附上了一個(gè)超鏈接,這個(gè)超鏈接就是前面出現(xiàn)的網(wǎng)站,點(diǎn)進(jìn)去之后是這樣的:

          但是這個(gè)里面顯示:

          No further time changes in 1927 in Shanghai

          翻譯過(guò)來(lái)就是:1927 年上海的時(shí)間沒(méi)有進(jìn)一步變化。

          這特么就和他下面說(shuō)的那一坨內(nèi)容對(duì)不上了啊?

          他下面說(shuō),在 1927 年底的午夜時(shí)分,時(shí)鐘往回走了 5 分 52 秒。因此,"1927-12-31 23:54:08"實(shí)際上發(fā)生了兩次,而 Java 取的是第二次的的時(shí)刻,因此存在差異。

          看到這里其實(shí)我都懵逼了,這玩意前后不符啊,于是我又接著開(kāi)始搜索。

          直到我發(fā)現(xiàn)了這個(gè):

          https://coolshell.cn/articles/5075.html/comment-page-2#comments

          這也是十年前的文章。

          這里面作者把當(dāng)時(shí)網(wǎng)站截了個(gè)圖:

          當(dāng)年的截圖顯示:

          在1927年12月31日23:59:59時(shí),往后面的一秒應(yīng)該是1928年1月1日 0:0:0,但是這個(gè)時(shí)間被往后調(diào)整了5分52秒,而成了,1927年12月31日的,23:54:08,于是,完成了352秒的穿越。

          這說(shuō)明了什么?

          說(shuō)明數(shù)據(jù)發(fā)生了篡改,有人篡改了網(wǎng)頁(yè)上的信息!

          到底是怎么回事呢?

          我們回到 stackoverflow 接著往下看:

          這是他第一次修改回答,因?yàn)?History changes...

          歷史發(fā)了變化了...

          他這里說(shuō),如果用 TZDB 的 2013a 版本的數(shù)據(jù),原來(lái)的問(wèn)題將不再表現(xiàn)出完全相同的行為。

          在 2013a 中,結(jié)果將是 358 秒,過(guò)渡時(shí)間為 23:54:03,而不是 23:54:08。

          他提到了一個(gè) TZDB,這是個(gè)啥東西呢?

          我也不知道,但是我搜索了一下。

          他應(yīng)該說(shuō)的是這個(gè)的東西。

          https://www.iana.org/time-zones

          看名字你也知道了,它是一個(gè)時(shí)區(qū)數(shù)據(jù)庫(kù),里面應(yīng)該是維護(hù)的時(shí)區(qū)相關(guān)的數(shù)據(jù)。

          也就是說(shuō),在這個(gè)時(shí)區(qū)數(shù)據(jù)庫(kù)里面,用 2013a 版本的數(shù)據(jù),前面的代碼就是另外一種輸出了。

          也就是說(shuō)數(shù)據(jù)確實(shí)發(fā)生了變化。

          而關(guān)鍵的回答在于下一次編輯:

          History has changed again...

          歷史再次發(fā)生了變化。

          在這個(gè)時(shí)區(qū)數(shù)據(jù)庫(kù)里面,2014f 版本中,變化的時(shí)間已經(jīng)移到了1900-12-31,現(xiàn)在只是一個(gè) 343 秒的變化。

          343 秒?

          不就是我們前面的 5 分 43 秒嗎?

          好了,現(xiàn)在時(shí)差能對(duì)上了,343 秒,但是時(shí)間還是沒(méi)對(duì)上啊。

          我們的測(cè)試時(shí)間 1900-01-01 08:00:00,他這里寫(xiě)的時(shí)間是 1900-12-31。

          差了整整一年呢?

          好,我們看他最后一次編輯的內(nèi)容:

          我個(gè)人理解他要表達(dá)的意思是這樣的。

          Java 為了在時(shí)區(qū)上統(tǒng)一標(biāo)準(zhǔn),所以來(lái)了個(gè)一刀切的政策。

          統(tǒng)一的標(biāo)準(zhǔn)就是讓 UTC 時(shí)區(qū)下 1900 年之前的任何瞬間都是標(biāo)準(zhǔn)時(shí)間。

          至于產(chǎn)生的時(shí)差嘛...

          就在最開(kāi)始的時(shí)候補(bǔ)上去吧。

          所以,1900-01-01 00:00:00 加上 8 小時(shí)時(shí)差,是 1900-01-01 08:00:00,在這個(gè)基礎(chǔ)上預(yù)先加上 27 年后來(lái)自 1927-12-31 那個(gè)午夜由于時(shí)間回?fù)軒?lái)的 343 秒。

          1900-01-01 08:05:43,我個(gè)人認(rèn)為就是這樣來(lái)的。

          而前面 stackoverflow 里面對(duì)應(yīng)的那個(gè)程序,我們現(xiàn)在執(zhí)行是輸出 1,但是在 10 年前,輸出結(jié)果確實(shí)是 353 。

          就像我把程序改成這樣:

          最終的輸出結(jié)果不是 1,而是 -342。

          時(shí)間,發(fā)生了“倒流”。

          好了,又是一個(gè)沒(méi)啥卵用的知識(shí)點(diǎn)。

          最后,再補(bǔ)充兩個(gè)冷知識(shí)。

          第一個(gè)是我在 jdk bug 列表里面追溯了一下,能找到最早提出相關(guān)問(wèn)題的時(shí)間是 2005 年:

          https://bugs.openjdk.java.net/browse/JDK-6281408

          在這個(gè)里面,官方是這樣回復(fù)的:

          這個(gè)問(wèn)題不會(huì)被修復(fù),以避免任何兼容性問(wèn)題。

          意思就是:?jiǎn)栴}我知道了,但是這玩意不太好弄,bug 先變成 feature 吧,就先這樣吧。

          別問(wèn),問(wèn)就是有歷史原因在里面。

          第二個(gè)冷知識(shí)是,前面提到的,時(shí)區(qū)在 1927 年發(fā)生了變化。

          你知道為什么嗎?

          我在某網(wǎng)站上找到了這樣的描述:

          https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%9C%8B%E6%99%82%E5%8D%80

          1928 年,就是民國(guó) 17 年。

          那一年,中共軍史上最早的紅軍,中國(guó)工農(nóng)紅軍第四軍成立。

          那一年,毛主席在井岡山建立農(nóng)村革命根據(jù)地。

          那一年,星星之火,已成燎原之勢(shì)。

          荒腔走板

          這期的荒腔走板,我就只放一張圖:


          至于這個(gè)政策最終會(huì)落實(shí)成什么樣呢?

          到時(shí)候大家有機(jī)會(huì)來(lái)成都軟件園逛逛吧,看看燈火通明的高樓大廈,那是年輕人在燃燒的樣子。

          算了,再放一張圖吧。

          最后說(shuō)一句

          好了,看到了這里了,轉(zhuǎn)發(fā)、在看、點(diǎn)贊隨便安排一個(gè)吧,要是你都安排上我也不介意。寫(xiě)文章很累的,需要一點(diǎn)正反饋。給各位讀者朋友們磕一個(gè)了!


          與優(yōu)秀的人在一起,自己也會(huì)優(yōu)秀起來(lái)

          高質(zhì)量技術(shù)交流群,您還沒(méi)加入嗎?

          趕緊點(diǎn)擊加入我們,享受一起成長(zhǎng)的快樂(lè)!


          往期推薦

          “VPN翻墻被大規(guī)模行政處罰” 是真的嗎?

          技術(shù)前沿:Redis推出性能碾壓ES和Mongo的大殺器

          墻裂推薦!卡神力作《代碼隨想錄》,上架首日賣(mài)爆!

          又雙叒有兄弟因?yàn)?YYYY-MM-dd 被叫去加班了...

          Java 18 都要來(lái)了,你不會(huì)還在用Java 8吧?


          前沿技術(shù)早知道,彎道超車(chē)有希望
          積累超車(chē)資本,從關(guān)注DD開(kāi)始

          點(diǎn)擊閱讀原文,送你免費(fèi)Spring Boot教程!

          瀏覽 46
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲天堂在线视频观看 | 国产偷人免费视频 | 三级黄色生活毛片 | 成人女a在线免费 | 波多野吉衣AⅤ无码一区小说 |