1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        一個(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ì)?。?/p>

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

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

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

        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ú)毛病?。?/p>

        我甚至懷疑是 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)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产睡熟迷奷一区二区 | 国产黄色免费网站 | 女人被舔全过程 | 婷婷五月丁香五月 | 下乡干部玩农村妇女 | 少妇又紧又色又爽又刺激视频网站 | AV网子 | 亚洲va成人天堂 美女18免费看 | 开心婷婷五月天 | 他舔我下面 |