坑~夏令时冬令时引发的时间换算问题
起因
最近接触到一些国外的项目,由于国内外有时差这个东西,对于某些基础数据存到数据库的时候需要记录时间,为了方便,这里采用了时间戳(int或者timestamp)记录。由于时间戳全球都是一样的,需要的时候根据时区进行转换就能够拿到当地的时间。
嗯~ o(* ̄▽ ̄*)o,这样看起来确实没什么毛病。众所周知,一天有24小时,换算成秒就是:24*60*60=86400秒。
然而,我在某次使用 MySql 的 FROM_UNIXTIME 发现一个问题,两个时间相差86400秒,但是格式化之后却不是相差一天!!!
假设北京时间2019年11月25日 12:00:00,对应的时间戳是:1574654400,照理说这个时间戳加上一天86400秒,理论上就是北京时间2019年11月26日 12:00:00,事实上确实如此,国内的话这么算确实没什么问题,但是如果是国外时区的话,那可能会出问题。
由于国外部分国家有夏令时和冬令时之分(具体下面会细说),直接加上86400秒可能会有问题。
感兴趣的可以拿1572764400(太平洋时间2019-11-03 00:00:00,单位:秒)这个时间戳验证下
拿代码演示下:
PHP:
<?php echo "PST时区的时间\n"; date_default_timezone_set(\'PST8PDT\'); echo date(\'Y-m-d H:i:s\',1572764400); echo "\n"; echo date(\'Y-m-d H:i:s\',1572764400+86400); echo "\n"; //换个时区 echo "换成上海时区看看\n"; date_default_timezone_set(\'Asia/Shanghai\'); echo date(\'Y-m-d H:i:s\',1572764400); echo "\n"; echo date(\'Y-m-d H:i:s\',1572764400+86400); echo "\n";
运行结果:
PST时区的时间 2019-11-03 00:00:00 2019-11-03 23:00:00 换成上海时区看看 2019-11-03 15:00:00 2019-11-04 15:00:00
明明是同一个时间戳,都是加上86400(一天),为什么在上海这个时区是第二天,而在PST(美国太平洋时区)只加了23小时?神不神奇!意不意外!
为了弄清楚这个问题,首先得先了解下什么是夏令时,什么是冬令时
夏令时
夏令时,表示为了节约能源,人为规定时间的意思。也叫夏时制,夏时令(Daylight Saving Time:DST),又称“日光节约时制”和“夏令时间”,在这一制度实行期间所采用的统一时间称为“夏令时间”。
一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。目前全世界有近110个国家每年要实行夏令时。[1]
冬令时
有夏令时就会有冬令时。高纬度和中纬度的许多国家在夏季到来前,把时针拨快一小时,新的时间就是夏令时,到下半季秋季来临前,再把时针拨回一小时,即形成冬令时。 [2]
夏令时和冬令时的影响
拿美国来说,美国各个地区的时间都不同,不像中国一样统一使用北京时间,美国一般以三月份第二个周日凌晨两点当成夏季的开始,十一月份第一个周日的凌晨两点当成冬季的开始。
所以在每年的三月份第二个周日凌晨两点过后,时间就会往前调快一个小时;同理,十一月份第一个周日把这一个小时调回来。
你也可以理解成美国那边,一年里面有一天只有23小时(夏天开始那一天),有一天有25小时(冬天开始那一天),其他时间每天都是24小时。
所以你会发现,夏天的时候,中国的北京时间(东八区)与美国太平洋时区(西八区)的时差是15小时,而到了冬天却变成16小时
解决方案
回到开头那个问题,如果我们想直接算第二天,直接加上86400(一天)可能在其他国家就会有我上面那个夏令时和冬令时时间换算的问题,要如何避免呢?首先能够确定的是,直接加上86400是不可取的,如果加上一天能否行得通
PHP:
<?php echo "PST时区的时间\n"; date_default_timezone_set(\'PST8PDT\'); echo date(\'Y-m-d H:i:s\',1572764400); echo "\n"; echo date(\'Y-m-d H:i:s\',1572764400+86400); echo "\n"; echo "--------------------------\n"; echo date(\'Y-m-d H:i:s\',1572764400); echo "\n"; echo date(\'Y-m-d H:i:s\',strtotime(\'+1 day\',1572764400)); echo "\n";
运行结果:
PST时区的时间
2019-11-03 00:00:00
2019-11-03 23:00:00
--------------------------
2019-11-03 00:00:00
2019-11-04 00:00:00
可以看出,不直接加上86400,直接在日期上加上一天是完全没问题的。
JavaScript:
var date = new Date(1572764400*1000); date.setDate(date.getDate()+1); var timestamp = Math.round(date.getTime()/1000);
注意:JS的时间戳是毫秒!!!
结论
在经济全球化快速发展的今天,在软件开发的过程中,尽量养成习惯,由于夏令时和冬令时不是固定的,开发在时间计算上应该慎用86400进行加减运算,时间计算请直接对日期进行加减,展示时间给用户看的时候尽量结合当地时间,结合夏令时和冬令时计算出准确的当地时间,避免产生不必要的分歧。
参考:
[1]. 百度百科-夏令时
[2]. 百度百科-冬令时