44

我正在尝试建立一个数据库来存储用户指定的每日警报时间。例如,用户希望在每天早上 7:00 到早上 7:30 之间满足某些条件时收到警报。在尝试实现这一点时,我需要适应夏令时。这是我尝试的解决方案:

  1. 将用户本地时区(长格式,例如“美国/东部”)信息存储在一个表中(例如 userInfo),并将警报时间存储在另一个表中(例如 userAlarms)。
  2. 查询 userAlarms 表时,将 UTC 时间转换为用户本地时间,由存储在 userInfo 表中的 tz 列通过CONVERT_TZ(UTC_TIME(), 'UTC', userInfo.tz).

问题 1. 据我了解,指定时区名称(如美国/东部)考虑夏令时。例如,CONVERT_TZ('00:00:00', 'UTC', 'US/EASTERN')在 1 月 1 日调用应该产生“19:00:00”,但在 7 月 1 日调用应该产生“20:00:00”。我对么?

问题 2. 如果 Q1 正确,我是否需要不断更新 MySQL 的时区表以保持时区 UTC 偏移量是最新的?

问题 3. MySQL 文档中给出的示例在我的服务器上运行时会SELECT CONVERT_TZ('2004-01-01 12:00:00','GMT','MET')产生“ ”。NULL这可能是由于没有设置时区表造成的吗?

我怎样才能检查这个?

4

3 回答 3

35

如果这产生 null 则 TZ 表尚未设置:

SELECT CONVERT_TZ(now(),'US/Eastern','US/Central');

如果您没有设置时区表,您可以更新用户表中的小时偏移量,然后执行以下操作:

select utc_timezone() - interval user_timezone_offset_in_hours hour
from userinfo a
where user_id = 999;

但是,您仍然需要一种方法来更新用户的时区。

如果您正在为 Web 应用程序编写此代码,则可以通过 javascript 获取时区,这里有一篇文章描述了如何(尚未尝试过,但看起来它会工作)。

关于上面的“间隔”的一些解释......

MySQL 中比较巧妙的构造之一是INTERVAL 关键字的使用,最好通过示例来说明(数值可以是表达式或字段值)

select now() today, now() - interval 1 day yesterday;
+---------------------+---------------------+
| today               | yesterday           |
+---------------------+---------------------+
| 2011-05-26 13:20:55 | 2011-05-25 13:20:55 |
+---------------------+---------------------+

您可以随意添加和减去它们,这就是为什么我从不 打扰日期/时间加/减/转换功能

select now() a, now() - interval 1 day + interval 4 hour + interval 8 minute b;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2011-05-26 13:24:16 | 2011-05-25 17:32:16 |
+---------------------+---------------------+

您可以使用负数(应该适用于负时区偏移),它们是相同的:

select now() - interval 1 month a, now() + interval -1 month b;
+---------------------+---------------------+
| a                   | b                   |
+---------------------+---------------------+
| 2011-04-26 13:38:05 | 2011-04-26 13:38:05 |
+---------------------+---------------------+
于 2011-05-26T21:23:31.017 回答
29

我发现此线程很有帮助,并决定共享文档页面以导入此信息。我在 CentOS 和 RHEL 中完全按照下面的说明进行了操作,并且运行良好。我现在可以使用带有“GMT”和“US/Eastern”等参数的 CONVERT_TZ 函数。

从 MySQL 文档中,这是导入 MySQL 时区表信息的方法:

http://dev.mysql.com/tech-resources/articles/4.1/time.html


对于在基于 Unix 的系统上运行 MySQL 4.1.3 或更高版本的所有用户(请记住,这在 Windows 系统上还不起作用):

填充时区表。

为此,请运行mysql_tzinfo_to_sql随 MySQL 发行版提供的程序。mysql_tzinfo_to_sql读取操作系统时区文件并从中生成 SQL 语句。SQL 语句然后由 mysql 处理,以加载时区表。

mysql_tzinfo_to_sql成功运行,需要知道服务器机器的操作系统时区文件存放在哪里;检查名称类似于/usr/share/zoneinfo. 将命令行中的目录名称传递给mysql_tzinfo_to_sql,并将输出发送到 mysql 程序。这是一个例子。

shell> mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql

注意:上述命令假定“mysql_tzinfo_to_sql”和“mysql”在您的路径中。如果不是,您需要在运行命令时提供两者的完整路径,或者切换到 mysql bin 文件夹并使用如下命令:

shell> ./mysql_tzinfo_to_sql /usr/share/zoneinfo | ./mysql -u root mysql
于 2011-03-15T22:33:28.357 回答
21

Q1:是的,CONVERT_TZ 会为您考虑夏令时。此信息以及每个时区的 DST 开始/结束时间存储在 time_zone_* 表中。

Q2:是的,正如 mysql 文档中所述,时区信息会根据每个地区的政治而变化。每次发生更改时,您都必须更新 time_zone_* 表。有时做 IT 很糟糕,这就是其中之一。

Q3:这些是 5 个时区表,查询它们以查看它们是否有任何内容:

select * from mysql.time_zone_transition_type;
select * from mysql.time_zone_transition;
select * from mysql.time_zone_name;
select * from mysql.time_zone_leap_second;
select * from mysql.time_zone;
于 2010-09-13T17:53:50.347 回答