6

几个小时以来,我一直在寻找在 PHP/MySQL Web 应用程序中使用时区的最佳方法,但很难找到明确的答案。根据我到目前为止所学到的知识,最好将每个人的东西以 UTC 格式存储在数据库中(如果我错了,请纠正我)。

当用户注册时,我会询问他们那里的时区,然后将其存储到那里的用户。这将采用这种格式作为下拉菜单:

<option value="Europe/London">(GMT) Greenwich Mean Time : London</option>

我正在构建的应用程序将允许用户在未来与人(会议)进行安排,就像日历一样。显然,在一年的时间里,不同的时区有不同的夏令时,知道我将如何满足这一点吗?

假设来自英国的用户在 2013 年 1 月 24 日下午 3:00 召开会议,并邀请住在加利福尼亚的人参加这次会议,我如何获得它以便美国人在他/她的时区看到该会议,而英国用户看到它在他/她的时区?(请注意,两个用户都已注册并设置了他们的时区)。

有没有人有一个明确的解释,也许有一些例子?或者可以指出我在哪里可以找到它?

谢谢

4

2 回答 2

11

我在一年前为一家私人飞机运营商编写的 PHP/MySQL 应用程序中广泛处理了这种情况。在这两个平台上处理时区有不同的策略,但我将解释我是如何做到的。我将 MySQL 服务器设置为 UTC,并在用户在用户配置文件注册过程中指定的时区运行每个 PHP 脚本。

MySQL 和 PHP(PHP 5.2 及更高版本)都具有本机日期时间数据类型。MySQL 的 datetime 是一种原始数据类型,而 PHP 5.2 及更高版本提供了内置的DateTime 类。MySQL datetime 数据类型不包含时区的元数据,但 PHP DateTime 对象始终包含时区。如果 PHP 日期时间构造函数未在第二个参数中指定可选时区,则 PHP 日期时间构造函数使用 php 环境变量。

MySQL 和 PHP 都在配置文件中设置了默认时区。MySQL 使用配置文件中为每个 db 连接设置的日期时间,除非用户在使用命令启动连接后指定不同的时区SET time_zone = [timezone];。PHP 还使用服务器配置文件中设置的时区为每个脚本设置一个时区环境变量,并且可以date_default_timezone_set()在脚本启动后使用 PHP 函数覆盖该环境变量。

PHP DateTime 类有一个名为timezone的属性,它是一个PHP DateTimeZone 对象。DateTimeZone 对象是使用字符串指定的确切时区。时区列表很全面,在世界各地有数百个单独的时区。 PHP 时区将自动考虑夏令时。

当用户在 Web 应用程序中生成日期时间时,在用户配置文件的时区中构造一个 PHP 日期时间对象。然后使用该setTimezone方法将 DateTime 对象修改为 UTC 时区。现在您有了 UTC 格式的用户日期时间,您可以将值存储在数据库中。使用 DateTimeformat方法将数据表示为 MySQL 接受的格式的字符串。

所以用户生成一个日期时间,你在用户指定的时区创建一个 PHP 日期时间对象:

// set using an include file for user profile
$user_timezone = new DateTimeZone('America/New_York'); 

// 1st arg in format accepted by PHP strtotime
$date_object1 = new DateTime('8/9/2012 5:19 PM', $user_timezone); 
$date_object1->setTimezone(new DateTimeZone('UTC'));
$formated_string = $date_object1->format('Y-m-d H:i:s');
$query_string = "INSERT INTO `t_table1` (`datetime1`) VALUES('$formated_string')";

当您从数据库中检索值时,以 UTC 构造,然后转换为用户的时区。

$query_string = "SELECT `datetime1` FROM `t_table1`";
$date_object1 = new DateTime($datetime_string_from_mysql, new DateTimeZone('UTC'));
$date_object1->setTimezone($user_timezone);
$string_for_display_in_application = $date_object1->format('m/d/Y g:i a');

使用此方法,您的日期时间值始终以 UTC 格式存储在数据库中,并且用户始终会体验到他/她的个人资料时区中的值。如果需要,PHP 将针对每个时区更正夏令时。

一个问题:这个解释不包括 MySQL 时间戳数据类型。我建议使用 MySQL datetime 日期类型来存储日期时间值,而不是时间戳数据类型。此处的手册中介绍了时间戳数据类型。

编辑:您可以使用listIdentifiers 生成一个包含每个 PHP 时区字符串的数组,这是 DateTimeZone 类的静态方法。

于 2012-08-09T13:22:09.493 回答
4

在 MySQL 中,您需要做的是:

  1. 将每个用户选择的时区存储在某个地方,您可以在代表该用户进行数据库查询时检索它。您可以将其存储为字符串。
  2. 在您代表特定用户工作之前(例如,存储或检索约会时间和日期)SET time_zone = (stored time zone setting)

这将导致时区适当地转换为每个人的本地时间。

编辑:

这有效,因为

  1. MySQL 尝试使用 UTC(通用时间,以前称为格林威治标准时间)将 DATETIME 和 TIMESTAMP 数据项存储在表中。
  2. 只有知道应用程序提供的每个数据项的正确本地时区,它才能正确执行此操作。
  3. 在不关心不同时区的应用程序中,它以 MySQL 服务器范围的方式执行此操作。请参阅https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html。大多数运行多国和多时区应用程序的人将他们的服务器时区设置为 UTC,而不是本地时间,因为这样容易整理事情。
  4. 除非您还知道日期和时区,否则尝试将时间从 UTC 转换为本地时间几乎没有意义,因为本地时间在一年中的不同时间打开和关闭。尝试为以色列、亚利桑那州和纽约的所有三个地区都做到这一点,我敢说!以色列在逾越节和犹太新年在白天和标准时间之间切换;亚利桑那州没有转换,而纽约则随美国联邦立法机构的心血来潮而转换。
  5. 有一个会话范围的 time_zone 设置 ( SET time_zone = something)。如果您不设置它,它将使用上面第 3 项中的时区表示。如果您设置它,服务器将使用它作为时区来将其内部表示转换为它在查询中发送回的表示。
  6. 您可以通过发出SELECT Name from mysql.time_zone_name. 这可以填充下拉菜单,您的用户可以从中选择她的时区。如果此查询未返回任何项目,请查看https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html的底部。

因此,这意味着您可以将会话 time_zone 设置设置为特定用户的时区,然后返回该用户时区的所有时间。此外,您或将要从该用户的时区转换为 MySQL 的内部表示的任何DATETIMETIMESTAMP项目,因为它们被放置在您的表中。INSERTUPDATE

注意:在具有持久 MySQL 连接的 Web 应用程序中,新用户请求的工作将继承连接的 time_zone 设置。不要忘记为新用户重置它。

如果您正在运行返回多个用户的本地时间数据的查询,并且这些用户恰好位于不同的时区,则您无法利用此 MySQL per-session 功能集。您可以通过为不同的用户运行不同的查询并更改他们之间的 time_zone 设置来解决此问题。

或者,您可以使用 MySQL 功能

CONVERT_TZ(datetime,'UTC','user_time_zone')

或类似的每个项目。

或者,Java 和 DotNET 拥有自己的高质量时区操作系统。因此,您可以选择使用 UTC 的 time_zone 设置运行 MySQL 服务器,并在应用程序中进行所有时区转换。

于 2012-08-08T21:35:13.107 回答