标题: PHP获取时间戳慢了8个小时
时间: 2022-09-07发布,2022-09-07修改
data.timezone=PRC
data_default_timezone_set('PRC');
『回复列表(30|隐藏机器人聊天)』
UNIX时间戳是指从绝对时间点(UTC时间1970年1月1日午夜)起经过的秒数,不考虑闰秒。
它是时区无关的。
时区的作用体现在把unix时间戳转换为时间字符串的时候。
date_default_timezone_set('UTC');
var_dump(time());
var_dump(date('Y-m-d H:i:s', 0));
var_dump(date('Y-m-d H:i:s', time()));
var_dump(date('Y-m-d H:i:s'));
date_default_timezone_set('PRC');
var_dump(time());
var_dump(date('Y-m-d H:i:s', 0));
var_dump(date('Y-m-d H:i:s', time()));
var_dump(date('Y-m-d H:i:s'));
你从函数名称也能看出来,既然是date_default_timezone_set,它影响的肯定是date()
函数,不会是time()
函数。
为什么UNIX时间戳必须与时区无关呢?因为时区记录的不止是简单的时间偏移,还包括:
所以本地时间不是连续的,它在国家立法调整时区,以及每年夏令时开始和结束的那一刻断开。
这样一来,让时间戳与时区有关就只会带来坏处,不会带来好处,比如:
此外,无论当地是否有夏令时和时区调整,时间戳和时区相关都会带来以下问题:
在用户调整时区后,一些刚刚修改的文件可能会被认为在未来修改(比如从UTC+8调整到UTC+7,本地时间戳数值变小了3600)。这会让依赖修改时间判断是否需要重新编译的程序(比如make
)无法正确重新编译,因为目标文件的修改时间在未来,总是大于源代码的修改时间。
时间戳将不可在不同系统间交换,因为不同系统的时区设置可能不同,交换时必须附带时区。
上述坏处只需要让时间戳与时区无关就能全部解决。目前,时间戳只代表协调世界时的字面值(不考虑润秒),所以:
关于夏令时的影响,举个例子:协调世界时1990年6月1日的午夜,并不是北京时间8点,而是北京时间——9点。
date_default_timezone_set('PRC');
$t = gmmktime(0, 0, 0, 6, 1, 1990);
var_dump($t);
var_dump(gmdate('Y-m-d H:i:s', $t));
var_dump(date('Y-m-d H:i:s', $t));
就算在中国,如果时间戳和时区相关,你也会在历史问题上引入难以解决的复杂性,更不用说那些正在实施夏令时的国家了。
以下是我认为良好的设计
date = xxx
->
time >= xxx and time <= xxx
)。select unix_timestamp()
),因为时间戳是时区无关的,即使数据库和网站程序的时区不同,结果也一致。你可能会问,set time_zone = '+8:00';
这样不行吗,这不就设为北京时间了吗?
从1990年6月1日午夜问题就能看出来,这样不行,你会在历史问题上犯错误。
中国曾在1986年到1991年期间实施夏令时,所以UTC+8并非总是北京时间。
注意我说time() + 3600 * 8
是“unix时间戳偏移8小时后的秒数”,它已经不再是unix时间戳。
只有未偏移的秒数(当前时刻与UTC时间1970年1月1日午夜的秒数之差)才叫unix时间戳。
unix时间戳是一个绝对概念,同一时刻世界上有且只有一个unix时间戳,无论你在哪个时区。或者换种说法,unix时间戳是协调世界时的整数表示法,而协调世界时显然是与时区无关的。同一时刻世界上只有一个协调世界时,所以只有一个unix时间戳。
至于时区,应该在显示时进行处理,也就是在把unix时间戳从整数转换为时间字符串时进行处理。不应该对协调世界时(unix时间戳整数)本身添加偏移。
这就是为什么,date_default_timezone_set
只对date
函数有效,对time
函数无效。
time()
始终返回协调世界时,不应该对其添加时区偏移。只有当你把它转换为时间字符串(date($format, $time)
)时,才会自动添加时区偏移。
如果你对time()
的返回值添加了时区偏移,那么当你使用date($format, $time)
把它转换为时间字符串的时候,结果就会是错误的,因为date
总是会自动为时间添加时区偏移,如果你已经偏移过一次,那最终结果就偏移了两次。