一个坑
我们经常在客户端做一些与时间相关的需求,比如 在6点~12点要展示一个新的广告位。
为了解决上述问题,我们通常把 开始、结束时间格式和服务端做好约定,通过配置下发,如 startTime=2017-10-19 15:00:00
。
客户端用 当前时间与配置时间 做对比,来完成切换。
为了防止客户端任意篡改时间,我们不会直接去读取客户端时间(也就是
System.currentTimeMillis()
转化而来的时间),我们会获取当前服务端时间(这里不做展开)。
而为了解析配置中的时间,我们需要一个常用的 SimpleDateFormat
类来帮助我们解析。用法如下:
上述代码看上去毫无问题,我们将 配置中的时间 解析成了时间戳,并且,我们还注意到了时区问题,使用了Locale.CHINA 东8区
来解析,规避掉了用户手动切时区而导致解析异常(因为 我们的服务器时间是采用了东8区时间)。恩,总而言之,非常棒。
于是乎,我们代码上线了,等到了2017-10-19 15点,静静等待着广告位流量暴增。
可是还没到15点,11点......一波流量进来、12点.... 流量曲线变抖了、13点.....继续爆发...
来来,review一波
整点流量曲线变化明显,很快意识到可能被时区坑了 。
由于获取服务端时间已经上线很久了大量业务方在使用,没出现过时区问题。所以直接被排除。
剩下的,就是这3行代码了。。。。
因此不得不来检查一下 这3行代码。。What fuck ,你告诉我,这么和谐用法,特喵有什么问题。。
Run 一下
肉眼是看不出来什么问题了,跑一下。
Out put:
time:1508396400000
反查之:1508396400000 ->Thu Oct 19 2017 15:00:00 GMT+0800 (CST)
接着切换本地时区,切到东9区:
Out put:
time:1508392800000
反查之:1508392800000 ->Thu Oct 19 2017 14:00:00 GMT+0800 (CST)
真的。。。。。提前了。。。。。 一个小时。。。。Locale.CHINA,这个参数,摆设么?
问题定位了,SimpleDateFormat
的错误用法,导致配置时间解析出错,非东8区的用户,就会存在时间不准问题。
SimpleDateFormat ,我还敢信你么?
在我吐槽了半小时SimpleDateFormat
后,我认真打开了源码,习惯性的读了一下类注释:
可知,有3个用法:
- formatting(date -> text)
- parsing (text -> date)
- normalization
我们用到的是parse
。
可知,parse中的 时区,来自于 TimeZone
。而SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
中的Locale.CHINA
并非设置时区,而是在:
构造方法中的 locale ,被传入DateFormatSymbols.getInstanceRef(locale);
中,作为设置 formatData
的格式,这个参数,会在 formatting(date -> text)
用法中生效。
因此,我们需要 正确的设置解析时区,应该去设置 TimeZone
。
SimpleDateFormat
暴露了setTimeZone(TimeZone zone)
方法可以设置时区。
由此,我们可以理解Locale.CHINA
失效的原因。
正确用法
parsing (text -> date)
将时间字符串,转换成正确的
Date
。
无论修改到任何时区,都将输出东8区时间:
time:1508396400000
formatting(date -> text)
将
Date
转化成指定时区的 时间字符串格式。
这个只会根据国家来改变展示格式.
输出:
//系统语言是中文
time:公元 2017/十一月/05 22:42:14 周日 下午 中国标准时间
//系统语言是英文
time:AD 2017/November/05 22:45:22 Sun PM China Standard Time
指定第二个参数后:
//系统语言是中文
time:公元 2017/十一月/05 22:42:14 周日 下午 中国标准时间
//系统语言是英文
time:公元 2017/十一月/05 22:45:56 周日 下午 中国标准时间
其实都是细节,注意使用,避免入坑。。
..
网友评论