又是時間格式化問題,詭異的是隻有10月份BUG才出現
theme: cyanosis highlight: a11y-dark
- 小知識,大挑戰!本文正在參與“程式設計師必備小知識”創作活動。
- 本文已參與「掘力星計劃」,贏取創作大禮包,挑戰創作激勵金。
背景
十一假期後第一天工作,當大家還沉浸在國慶長假的快樂的時候,我被業務部門急促的電話拉回到現實,生產環境上有頁面資料都是空的,而節前還都是好好的。
這就奇了怪了,過了一個國慶,這個bug就閃現出來了?
時間格式化的鍋
排查原因
從表象上看是後臺沒有返回資料,實際是前臺的時間傳遞有問題。
下面這個請求,日期欄位date應該是20211011,但是怎麼會變成2042呢?
難道過了一個國慶,年份2021就變成了2042嗎?
又是時間格式化問題
下面省略一萬秒,前端開發排查後發現了下面的程式碼:
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
回憶第一次和時間格式化邂逅
回憶總是讓人憂傷。
第一次和時間格式化bug的邂逅是2020年元旦。
當很多同事在家喜迎新年的時候,突然業務報問題,說頁面上的時間錯了。
時間給了我們一個驚喜,這應該是元旦最難忘的禮物。
還是經過了排查問題--定位問題的過程,最後前端開發媛發現了下面的祕密:
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:這不是同一個程式設計師埋的彩蛋。
啟示
- JavaScript是一個弱型別語言,它不會強制開發者提前指定資料的型別,因此在任何時候,開發人員的疏忽都會導致程式碼處理走入意想不到的分支,就像上面的程式碼總是在整數和字串之間轉換。而像Java這樣的強型別語言則增加了一些約束,不會隨意改變資料型別。除此之外,還要準確使用小括號。
- 對於新手程式設計師,不要隨便相信網上的程式碼,多瞭解每個方法和語法的原理,能用成熟的工具類絕不自己寫,要聰明地偷懶。
人不能兩次踏入同一條河流
,但是兩個程式設計師可能產生同一種Bug,所以現在讀文章的你是否真的學廢了時間格式化呢?
我是Pandas,專注Java/JS等程式設計實用技術分享,公眾號
Java實用技術手冊
和B站均有視訊解說,歡迎來玩。如果你覺得這篇文章有用,別忘了點贊+關注,一起進步!
- spring注入靜態變數有幾種方法?春節假期虹貓藍兔三千問
- stream的實用方法和注意事項
- 【Java實用技術】字串的拆分用什麼方法好?有一半程式設計師都掉過split坑
- 【Java實用技術】字串的擷取用什麼方法好?
- 【Java實用技術】java中關於整數的幾個冷知識,總有一個你不知道
- 又是時間格式化問題,詭異的是隻有10月份BUG才出現
- 我決定寫一本Java實用技術,特點實用!實用!還是實用!
- 5 款新型 Linux 命令列工具,實用!
- 5 款新型 Linux 命令列工具,實用!
- Nginx 的 5 大應用場景,太實用了!
- 自定義雙向繫結框架-只需一個註解,簡單實用
- RabbitMQ 延遲佇列,太實用了!
- Spring 中的重試機制,簡單、實用!
- 推薦一款 ES 叢集視覺化工具:Cerebro,簡單、實用!