由于在运行的某SLG游戏在国内苹果商店多次拿到推荐,我们打算把它做到海外,部署按照全球唯一服的架构来部署,运维同事将集群中的各个模块选择部署在美国芝加哥的机房。上线一段时间后客服反馈平时凌晨3点重置玩家每日数据的时间变成了4点,往后推迟了1小时,当时怀疑是不是出BUG了,查了代码发现这里有猫腻:
public static final long GMT_8 = TimeZone.getDefault().getRawOffset();
并且查了这里的时区是America/Los_Angeles,按照经验,这里走的是夏令时,夏令时时区会比平常的时间走的快,所以虽然是3点,实际上对应的夏令时时间是4点,这下找到问题的关键就有办法来解决。
什么是夏令时,冬令时:
很简单,我们平常用的格林威治标准时间(又译:格林尼治标准时间,Greenwich Mean Time),到了三月,就在格林威治标准时的基础上拨快一个小时,新的时间就是夏令时。到了十月,又在夏令时的基础上拨慢一个小时,就形成冬令时了,说的再简单点,冬令时就是格林威治标准时。
美国时间一般被认为是美国本土的时间。美国本土横跨西五区至西十区,共六个时区,每个时区对应一个标准时间。从东向西分别为东部时间(EST)(西五区时间)、中部时间(CST)(西六区时间)、山地时间(MST)(西七区时间)、太平洋时间(西部时间)(PST)(西八区时间)、阿拉斯加时间(AKST)(西九区时间)和夏威夷时间(HST)(西十区时间),按照“东早西晚”的规律,各递减一小时。美国从每年3月的第二个星期日至11月的第一个星期日采用夏令时,夏令时比正常时间早一小时。
编辑
夏令时(3月11日至11月7日)
东部时间12小时(黄色),中部时间13小时(绿色),山地时间14小时(蓝色),太平洋时间15小时(红色)
冬令时(11月8日至次年3月11日)
东部时间13小时(黄色),中部时间14小时(绿色),山地时间15小时(蓝色),太平洋时间16小时(红色);
如何规避:
1.根据代码来判断当前是冬令时夏令时来做逻辑区分(因为服务器的代码是java,这里我就只提供java方法):
public static boolean isDaylightTime(LocalDateTime a) { LocalDateTime startDate = a.withMonth(3).toLocalDate().atTime(2, 0); LocalDateTime startlightDay = startDate.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.SUNDAY)); //更新为11月 LocalDateTime endDate = a.withMonth(11).toLocalDate().atTime(1, 59,59); LocalDateTime endlightDay = endDate.with(TemporalAdjusters.dayOfWeekInMonth(1, DayOfWeek.SUNDAY)); if (a.isBefore(startlightDay) || a.isAfter(endlightDay)) { return false; } return true; }
2.调整时区:
怎么避免,我这里做如下调整:
编辑
修改为America/Phoenix地区时间(不走夏令时):
timedatectl set-timezone America/Phoenix
然后调整数据库的相关时区
<sqlAddr>jdbc:mysql://127.0.0.1:3306/databasename?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=America/Phoenix&allowPublicKeyRetrieval=true</sqlAddr>
mysql默认时区:
mysql> show variables like '%time_zone%';
+------------------+--------+
| Variable_name | Value |
+------------------+--------+
| system_time_zone | CST |
| time_zone | SYSTEM |
+------------------+--------+
my.cnf配制文件修改:
可以通过修改my.cnf
在 [mysqld] 之下加default-time-zone=timezone来修改时区。
如:default-time-zone = '+8:00'
通过命令:
set time_zone = timezone
比如北京时间(GMT+0800)set time_zone = '+8:00';
美国pst时间(GMT-08:00)set time_zone = '-8:00';
mysql> set time_zone = '+8:00'; Query OK, 0 rows affected (0.17 sec) mysql> select now(); +---------------------+| now() |+---------------------+| 2016-06-23 16:32:53 |+---------------------+1 row in set (0.00 sec)
mysql> set time_zone = '-8:00'; Query OK, 0 rows affected (0.00 sec) mysql> select now(); +---------------------+| now() |+---------------------+| 2016-06-23 00:33:21 |+---------------------+1 row in set (0.00 sec)
mysql 数据库中的时区信息默认为空:
mysql> show tables like "%time%";+---------------------------+| Tables_in_mysql (%time%) |+---------------------------+| time_zone || time_zone_leap_second || time_zone_name || time_zone_transition || time_zone_transition_type |+---------------------------+5 rows in set (0.00 sec)
实际上我更倾向于调整时区,这个省事,而且避免游戏逻辑里的一些处理,最近游戏客服小姐姐气色也好多了,毕竟这个BUG解决了后她就不用被玩家因此diss了。