问题描述
PHP 中时区的一些问题已经在我脑海中浮现了一段时间,我想知道是否有比我目前正在做的更好的方法来处理它.
Some issues with timezones in PHP have been in the back of my mind for a while now, and I was wondering if there are better ways to handle it than what I'm currently doing.
所有问题都围绕重新格式化数据库存储日期:
All of the issues revolve around reformating database stored dates:
在处理必须支持多个时区(对于用户)的站点时,为了规范存储时间戳的时区,我总是使用 CURRENT_TIMESTAMP
属性或 将其与服务器时区一起存储>NOW()
函数.
When dealing with a site that has to support multiple timezones (for users), to normalize the timezone offest of stored timestamps I always store it with the server timezone using the CURRENT_TIMESTAMP
attribute or the NOW()
function.
这样我就不必考虑在输入时间戳时为 PHP 设置的时区(因为 PHP 时间函数可以识别时区).对于每个用户,根据他的偏好,我使用以下命令在引导文件中的某处设置时区:
This way I don't have to consider what timezone was set for PHP when the timestamp was entered (since PHP time functions are timezone aware). For each user, according to his preference I set the timezone somewhere in my bootstrap file using:
date_default_timezone_set($timezone);
当我希望使用 php date()
函数格式化日期时,必须进行某种形式的转换,因为 MySQL 当前以 Ymd H:i 格式存储时间戳:s
.不考虑时区,您可以简单地运行:
When I'm looking to format dates with the php date()
function, some form of conversion has to take place since MySQL currently stores timestamp in the format Y-m-d H:i:s
. With no regard to timezone, you could simply run:
$date = date($format,strtotime($dbTimestamp));
问题在于 date()
和 strtotime()
都是时区感知函数,这意味着如果 PHP 时区设置与服务器时区不同,时区偏移量将应用两次(而不是我们想要的一次).
The problem with this is that date()
and strtotime()
are both timezone aware functions, meaning that if the PHP timezone is set differently from the server timezone, the timezone offset will apply twice (instead of once as we would like).
为了解决这个问题,我通常使用不支持时区的 UNIX_TIMESTAMP()
函数检索 MySQL 时间戳,允许我直接在其上应用 date()
-从而只应用一次时区偏移量.
To deal with this, I usually retrieve MySQL timestamps using the UNIX_TIMESTAMP()
function which is not timezone aware, allowing my to apply date()
directly on it - thereby applying the timezone offset only once.
我不太喜欢这种hack",因为我不能再像往常一样检索这些列,或者使用 *
来获取所有列(有时它可以大大简化查询).此外,有时使用 UNIX_TIMESTAMP()
根本不是一种选择(尤其是在使用没有太多抽象查询组合的开源包时).
I don't really like this 'hack' as I can no longer retrieve those columns as I normally would, or use *
to fetch all columns (sometimes it simplifies queries greatly). Also, sometimes it's simply not an option to use UNIX_TIMESTAMP()
(especially when using with open-source packages without much abstraction for query composition).
另一个问题是在存储时间戳时,如果不能使用 CURRENT_TIMESTAMP
或 NOW()
- 存储 PHP 生成的时间戳会将其与时区偏移量一起存储我想避免.
Another issue is when storing the timestamp, when usage of CURRENT_TIMESTAMP
or NOW()
is not an option - storing a PHP generated timestamp will store it with the timezone offset which I would like to avoid.
我可能在这里遗漏了一些非常基本的东西,但到目前为止,我还没有想出一个通用的解决方案来处理这些问题,所以我不得不逐个处理它们.非常欢迎您的想法
I'm probably missing something really basic here, but so far I haven't been able to come up with a generic solution to handle those issues so I'm forced to treat them case-by-case. Your thoughts are very welcome
推荐答案
几个月前,我们花了一些时间思考这个问题.我们最终得到的技术非常简单:
Few months ago we spent some time thinking about this. The technique we ended up with is pretty simple:
- 以 GMT/UTC 存储日期(例如 0 时区偏移).
- 在从数据库检索后应用当前用户时区偏移量(例如,在向用户显示之前或任何时候).
我们使用 Unix 时间戳格式.但这没关系.
We use Unix timestamps format. But that doesn't matter.
这篇关于在 PHP 中处理时区的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!