又是時間格式化問題,詭異的是隻有10月份BUG才出現

語言: CN / TW / HK

theme: cyanosis highlight: a11y-dark


背景

十一假期後第一天工作,當大家還沉浸在國慶長假的快樂的時候,我被業務部門急促的電話拉回到現實,生產環境上有頁面資料都是空的,而節前還都是好好的。

這就奇了怪了,過了一個國慶,這個bug就閃現出來了?

img

時間格式化的鍋

排查原因

從表象上看是後臺沒有返回資料,實際是前臺的時間傳遞有問題。

下面這個請求,日期欄位date應該是20211011,但是怎麼會變成2042呢?

難道過了一個國慶,年份2021就變成了2042嗎?

image-20211012202112694

又是時間格式化問題

下面省略一萬秒,前端開發排查後發現了下面的程式碼:

js  // 這裡省略一萬行程式碼  let str = ""  let endDateTime = new Date()  str += endDateTime.getFullYear()  + (endDateTime.getMonth() + 1 < 10 ? '0' + (endDateTime.getMonth() + 1) : endDateTime.getMonth() + 1)  + (endDateTime.getDate() < 10 ? '0' + endDateTime.getDate() : endDateTime.getDate())    let opt = {date: str,            productNo: productNo};    // 這裡省略一萬頭牛

前端大神們看了上面的程式碼,能一眼看出哪裡出問題了嗎?

  • 如果你能很看看出問題,說明你的基本功非常紮實。
  • 如果不能一看看出,甚至還要除錯一下,說明你基礎要加強,你也可能出現類似錯誤。

這個程式碼似曾相似,後面會說和時間格式化的第一次邂逅。

解析

endDateTime.getMonth()程式碼返回的是月份索引(10月份對應9),9+1=10 < 10 是三元表示式條件

js  三元表示式:  (endDateTime.getMonth() + 1 < 10 ? '0' + (endDateTime.getMonth() + 1) : endDateTime.getMonth() + 1)    在10月份程式碼變成了:endDateTime.getMonth() + 1  所以:  str = 2021 + 9 + 1 + 11 = 2042

為什麼10月份之前沒有問題呢?

js  因為9月份的時候三元表示式變成了:'0' + (endDateTime.getMonth() + 1)  JS會把結果轉成字串 '09'

不得不佩服開發同學成功地在9月份避開了BUG,導致大家和測試同學都無法在之前測出問題,而10月份問題暴露。

問題解決

開發給的最快解決方案是增加一個操作把年份變成字串,這樣就不存在數字累計導致年月日錯誤。

js  // 解決BUG  str += endDateTime.getFullYear() + '' // 這裡增加空字串  + (endDateTime.getMonth() + 1 < 10 ? '0' + (endDateTime.getMonth() + 1) : endDateTime.getMonth() + 1)  + (endDateTime.getDate() < 10 ? '0' + endDateTime.getDate() : endDateTime.getDate())

當然我們不建議上面的操作,我建議要麼寫一個健壯的公共的時間格式化工具類,要麼引用外部成熟的時間工具類,比如moment.js

js  // import http://cdn.staticfile.org/moment.js/2.24.0/moment.js  this.date = moment().format('YYYYMMDD');  // 輸出:20211011

回憶第一次和時間格式化邂逅

回憶總是讓人憂傷。

img

第一次和時間格式化bug的邂逅是2020年元旦。

當很多同事在家喜迎新年的時候,突然業務報問題,說頁面上的時間錯了。

image-20211012223859800

時間給了我們一個驚喜,這應該是元旦最難忘的禮物。

還是經過了排查問題--定位問題的過程,最後前端開發媛發現了下面的祕密:

js  // 先省略一萬字碼神附體  let mydate = new Date()  let date = mydate.getFullYear() + '-' +    (mydate.getMonth() + 1 >= 10 ? mydate.getMonth() + 1 : '0' + mydate.getMonth() + 1)    this.setData({     mydate: date  })

對於這次bug的解析,歡迎小夥伴們在評論區給出自己的見解。

「 掘金官方將在掘力星計劃活動結束後,在評論區抽送100份掘金周邊獎品,抽獎詳情見活動文章

歷史總是驚人的相似,沒想到這次又碰到了這個時間格式化bug。

PS:這不是同一個程式設計師埋的彩蛋。

啟示

  1. JavaScript是一個弱型別語言,它不會強制開發者提前指定資料的型別,因此在任何時候,開發人員的疏忽都會導致程式碼處理走入意想不到的分支,就像上面的程式碼總是在整數和字串之間轉換。而像Java這樣的強型別語言則增加了一些約束,不會隨意改變資料型別。除此之外,還要準確使用小括號
  2. 對於新手程式設計師,不要隨便相信網上的程式碼,多瞭解每個方法和語法的原理,能用成熟的工具類絕不自己寫,要聰明地偷懶。
  3. 人不能兩次踏入同一條河流,但是兩個程式設計師可能產生同一種Bug,所以現在讀文章的你是否真的學廢了時間格式化呢?

我是Pandas,專注Java/JS等程式設計實用技術分享,公眾號Java實用技術手冊和B站均有視訊解說,歡迎來玩。

如果你覺得這篇文章有用,別忘了點贊+關注,一起進步!