坑~夏令时冬令时引发的时间换算问题

时间:2024-01-25 22:57:03

 

起因

最近接触到一些国外的项目,由于国内外有时差这个东西,对于某些基础数据存到数据库的时候需要记录时间,为了方便,这里采用了时间戳(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]. 百度百科-冬令时