事件回顧:
因為我們的產品會有與時間轉換這部分,並且流量主要集中在小程序。
emmm~ 獲取用戶出生的年/月/日/時 我們和后台協商的是換算用戶選擇后的時間為 年/月/日/時/分/秒 所以我們會給用戶默認時1分1秒...
但是,因為小時的關系 部分用戶反饋和瀏覽器產品的顯示不准
當然,接到反饋的產品當然會和我們溝通,是不是代碼出了bug ?
問題復現:
我在小程序時間選擇器 選擇到 1989/5/14 任意小時的時候使用 new Date(年,月-1,日,時,分,秒).getTime() 和 https://tool.lu/timestamp/ 換算回來的日期與用戶竟然會有一個小時的差距...
這我就很納悶了,到底是什么問題...
於是我用node跑了一個腳本
// main.js
let fs = require('fs'); let rightTime = 673023661000; // https://tool.lu/timestamp/ 取你要對比的正確的時間戳; let year = 1991; // 對比的年份 let arr = []; let diffArr = []; let mon = [31,28,31,30,31,30,31,31,30,31,30,31] // 當年的月份對應的多少天 let signNum = 0; for(let i = 0; i < 12; i++){ if(i+1 == 5){ for(let j=0; j<mon[i]; j++){ for(let k=0; k<24; k++){ let currentTime = year + '/' + (i+1) + '/' + (j+1) + '/ ' + k + ':1:1+08:00' let getJsTime = new Date(year, i, j+1, k, 1, 1); let obj = '\r\n' + currentTime + " ---> " + getJsTime+ "<-->" + getJsTime.getTimezoneOffset() +" ---"+ getJsTime.getTime(); diffArr.push(getJsTime.getTime()) arr.push(obj) signNum++ } } } } for(let i=0; i<arr.length; i++){ let currentComNum = rightTime + i * 1000 * 3600; let sign = '' if(diffArr[i] == currentComNum){ sign = 'yes' }else{ sign = 'no'; } arr[i] = arr[i] + '--->' + currentComNum + ' ---> ' + sign; console.log(arr[i] + '--->' + currentComNum + ' ---> ' + sign) } fs.writeFile('對比.txt', arr, (err) => { if (err) throw err; console.log('文件已保存'); });
運行 這個js文件 node main.js
然后我發現 時間偏移 getJsTime.getTimezoneOffset() 這部分值一直是-480 其實讀者看完可以直接跑一次就可以在main.js同級目錄下看到
突然想起來Node.js和瀏覽器的運行環境不一樣,會不會在瀏覽器表現不一致?所以,我只能再粘貼復制代碼到瀏覽器 開發者工具。復制的代碼去掉以下部分:
let fs = require('fs');
fs.writeFile('對比.txt', arr, (err) => { if (err) throw err; console.log('文件已保存'); });
去掉之后,在瀏覽器中的表現瞬間清晰,因為, 時間偏移 getJsTime.getTimezoneOffset() 這個值已經成了 -540 。此時你就會想為什么會這樣子?接下來開始解密階段。
揭秘部分年份出現的1小時偏差
1986年4月,我國采取夏令時,具體作法是:每年從四月中旬第一個星期日的凌晨2時整(北京時間),將時鍾撥快一小時,即將表針由2時撥至3時,夏令時開始;到九月中旬第一個星期日的凌晨2時整(北京夏令時),再將時鍾撥回一小時,即將表針由2時撥至1時,夏令時結束。從1986年到1991年的六個年度,除1986年因是實行夏時制的第一年,從5月4日開始到9月14日結束外,其它年份均按規定的時段施行。在夏令時開始和結束前幾天,新聞媒體均刊登有關部門的通告。1992年起,夏令時暫停實行。
看到這里,你會不會恍然大悟。但是,別高興得太早...
你會說,為什么不能高興? 這原因都找到了,你不就可以根據這個偏移值計算回正常的日期嗎?
emm~ 道理是這樣的 確實,瀏覽器可以這樣子,但是小程序是根源所在,還得在小程序實驗驗證才行!!!
小程序驗證
emm~~ 經過一系列的操作,最后我得到的結果和Node.js跑出來的一樣,偏移值一直是-480!!!
好吧,這個找了一系列的原因竟然找到了,小程序沒有做對夏令時的處理
emm~~ 所以我在微信開發者社區報備這個bug
最后的最后,我還是得在微信修改之前自己手動判斷夏令時區間。。。
附圖:
小程序選擇器 選完后的結果是[86, 4, 3, 2] // 年,月,日,時 其中月/日都是 +1 才能對應到對應的月和日 timeArr = [86, 4, 3, 2] year = 1986 // 這里已經函數處理過 所以直接顯示1986
checkYear(timeArr, year) function checkYear(timeArr, year){ switch (year){ case 1986: check86day(timeArr); break; case 1987: case 1988: case 1989: case 1990: case 1991: checkDay(timeArr, year); break; default: outNormalTime(); break; } } function check86day(timeArr){ let startSign = alraedySummaryTimeObj[0].dayStart; let endSign = alraedySummaryTimeObj[0].dayEnd; switch(timeArr[1]+1){ case 5: case 9: checkHour(timeArr, 5, 9, startSign, endSign) break; case 6: case 7: case 8: addOffsetTime(); break; default: outNormalTime(); break; }; } function checkDay(timeArr, year){ let alreadySummaryTime = [1986, 1987, 1988, 1989, 1990, 1991]; let startSign = alraedySummaryTimeObj[alreadySummaryTime.indexOf(year)].dayStart; let endSign = alraedySummaryTimeObj[alreadySummaryTime.indexOf(year)].dayEnd; switch (timeArr[1] + 1) { case 4: case 9: checkHour(timeArr, 4, 9, startSign, endSign) break; case 5: case 6: case 7: case 8: addOffsetTime(); break; default: outNormalTime(); break; }; } function checkHour(timeArr, mon1, mon2, startSign, endSign){ if (((timeArr[1] + 1 == mon1) && ((timeArr[2] + 1) > startSign)) || ((timeArr[1] + 1 == mon2) && ((timeArr[2] + 1) < endSign))){ addOffsetTime(); } else if (((timeArr[1] + 1 == mon1) && ((timeArr[2] + 1) == startSign)) || ((timeArr[1] + 1 == mon2) && ((timeArr[2] + 1) == endSign))){ checkDetailHour(timeArr, mon1, mon2); }else{ outNormalTime(); } } function checkDetailHour(timeArr, mon1, mon2){ if ((((timeArr[1] + 1 == mon1) && (timeArr[3] > 2))) || ((timeArr[1] + 1 == mon2) && (timeArr[3] < 1))){ addOffsetTime(); } else{ outNormalTime(); } }
// 時間戳進行對應的加減操作 function outNormalTime(){ 時間戳 -= 0 } function addOffsetTime() { 時間戳 -= 3600 * 1000 }
當我寫完這些回頭看,一把辛酸淚~~~
因為我在真機上測試的時候,emm 時區偏移是正常的可以看到-540 也就是說 微信開發者工具是 跑的node.js 所以一直是-480 因為es6有過改動...
而真機測試是瀏覽器環境 只能說踩坑踩得心累
最后的改動回復偏移值的代碼是這樣子的
微信....
let d = new Date(timeStr); if (d.getTimezoneOffset() !== -480){ itsBirth = d.getTime() - (-480 - d.getTimezoneOffset()) * 60 * 1000
}else{
itsBirth = d.getTime()
}
記錄這次的小程序采坑記~~