一個(gè)坑
我們經(jīng)常在客戶端做一些與時(shí)間相關(guān)的需求,比如 在6點(diǎn)~12點(diǎn)要展示一個(gè)新的廣告位且蓬。
為了解決上述問(wèn)題怪与,我們通常把 開始、結(jié)束時(shí)間格式和服務(wù)端做好約定缅疟,通過(guò)配置下發(fā),如 startTime=2017-10-19 15:00:00
遍愿。
客戶端用 當(dāng)前時(shí)間與配置時(shí)間 做對(duì)比存淫,來(lái)完成切換。
為了防止客戶端任意篡改時(shí)間沼填,我們不會(huì)直接去讀取客戶端時(shí)間(也就是
System.currentTimeMillis()
轉(zhuǎn)化而來(lái)的時(shí)間)桅咆,我們會(huì)獲取當(dāng)前服務(wù)端時(shí)間(這里不做展開)。
而為了解析配置中的時(shí)間坞笙,我們需要一個(gè)常用的 SimpleDateFormat
類來(lái)幫助我們解析岩饼。用法如下:
上述代碼看上去毫無(wú)問(wèn)題荚虚,我們將 配置中的時(shí)間 解析成了時(shí)間戳,并且籍茧,我們還注意到了時(shí)區(qū)問(wèn)題版述,使用了Locale.CHINA 東8區(qū)
來(lái)解析,規(guī)避掉了用戶手動(dòng)切時(shí)區(qū)而導(dǎo)致解析異常(因?yàn)?我們的服務(wù)器時(shí)間是采用了東8區(qū)時(shí)間)寞冯。恩渴析,總而言之,非常棒吮龄。
于是乎俭茧,我們代碼上線了,等到了2017-10-19 15點(diǎn)漓帚,靜靜等待著廣告位流量暴增母债。
可是還沒(méi)到15點(diǎn),11點(diǎn)......一波流量進(jìn)來(lái)尝抖、12點(diǎn).... 流量曲線變抖了毡们、13點(diǎn).....繼續(xù)爆發(fā)...
來(lái)來(lái),review一波
整點(diǎn)流量曲線變化明顯牵署,很快意識(shí)到可能被時(shí)區(qū)坑了 漏隐。
由于獲取服務(wù)端時(shí)間已經(jīng)上線很久了大量業(yè)務(wù)方在使用,沒(méi)出現(xiàn)過(guò)時(shí)區(qū)問(wèn)題奴迅。所以直接被排除青责。
剩下的,就是這3行代碼了取具。脖隶。。暇检。
因此不得不來(lái)檢查一下 這3行代碼产阱。。What fuck 块仆,你告訴我构蹬,這么和諧用法,特喵有什么問(wèn)題悔据。庄敛。
Run 一下
肉眼是看不出來(lái)什么問(wèn)題了,跑一下科汗。
Out put:
time:1508396400000
反查之:1508396400000 ->Thu Oct 19 2017 15:00:00 GMT+0800 (CST)
接著切換本地時(shí)區(qū)藻烤,切到東9區(qū):
Out put:
time:1508392800000
反查之:1508392800000 ->Thu Oct 19 2017 14:00:00 GMT+0800 (CST)
真的。。怖亭。涎显。。提前了兴猩。期吓。。峭跳。膘婶。 一個(gè)小時(shí)。蛀醉。悬襟。。Locale.CHINA拯刁,這個(gè)參數(shù)脊岳,擺設(shè)么?
問(wèn)題定位了垛玻,SimpleDateFormat
的錯(cuò)誤用法割捅,導(dǎo)致配置時(shí)間解析出錯(cuò),非東8區(qū)的用戶帚桩,就會(huì)存在時(shí)間不準(zhǔn)問(wèn)題亿驾。
SimpleDateFormat ,我還敢信你么账嚎?
在我吐槽了半小時(shí)SimpleDateFormat
后莫瞬,我認(rèn)真打開了源碼,習(xí)慣性的讀了一下類注釋:
可知郭蕉,有3個(gè)用法:
- formatting(date -> text)
- parsing (text -> date)
- normalization
我們用到的是parse
疼邀。
可知,parse中的 時(shí)區(qū)召锈,來(lái)自于 TimeZone
旁振。而SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
中的Locale.CHINA
并非設(shè)置時(shí)區(qū),而是在:
構(gòu)造方法中的 locale ,被傳入DateFormatSymbols.getInstanceRef(locale);
中涨岁,作為設(shè)置 formatData
的格式拐袜,這個(gè)參數(shù),會(huì)在 formatting(date -> text)
用法中生效梢薪。
因此阻肿,我們需要 正確的設(shè)置解析時(shí)區(qū),應(yīng)該去設(shè)置 TimeZone
沮尿。
SimpleDateFormat
暴露了setTimeZone(TimeZone zone)
方法可以設(shè)置時(shí)區(qū)。
由此,我們可以理解Locale.CHINA
失效的原因畜疾。
正確用法
parsing (text -> date)
將時(shí)間字符串赴邻,轉(zhuǎn)換成正確的
Date
。
無(wú)論修改到任何時(shí)區(qū)啡捶,都將輸出東8區(qū)時(shí)間:
time:1508396400000
formatting(date -> text)
將
Date
轉(zhuǎn)化成指定時(shí)區(qū)的 時(shí)間字符串格式姥敛。
這個(gè)只會(huì)根據(jù)國(guó)家來(lái)改變展示格式.
輸出:
//系統(tǒng)語(yǔ)言是中文
time:公元 2017/十一月/05 22:42:14 周日 下午 中國(guó)標(biāo)準(zhǔn)時(shí)間
//系統(tǒng)語(yǔ)言是英文
time:AD 2017/November/05 22:45:22 Sun PM China Standard Time
指定第二個(gè)參數(shù)后:
//系統(tǒng)語(yǔ)言是中文
time:公元 2017/十一月/05 22:42:14 周日 下午 中國(guó)標(biāo)準(zhǔn)時(shí)間
//系統(tǒng)語(yǔ)言是英文
time:公元 2017/十一月/05 22:45:56 周日 下午 中國(guó)標(biāo)準(zhǔn)時(shí)間
其實(shí)都是細(xì)節(jié),注意使用瞎暑,避免入坑彤敛。浩考。
..