【问题标题】:MySQL CONVERT_TZ()MySQL CONVERT_TZ()
【发布时间】:2011-02-01 04:06:06
【问题描述】:

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

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

问题 1. 据我了解,指定时区名称(如美国/东部)应该考虑夏令时。例如,在 1 月 1 日调用 CONVERT_TZ('00:00:00', 'UTC', 'US/EASTERN') 应该产生“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”。这可能是由于没有设置时区表造成的吗?

我该如何检查?

【问题讨论】:

标签: mysql timezone convert-tz


【解决方案1】:

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;

【讨论】:

  • 它给了我“错误 1046 (3d000): No Database selected”
  • 您需要将输出通过管道传送到字面上的mysql -uroot mysql - mysql 是二进制可执行文件,第二个 mysql 是数据库名称。
  • 或先执行use mysql; 以在所有命令上使用此数据库。或直接:SELECT * FROM mysql.time_zone;
【解决方案2】:

我发现此线程很有帮助,并决定共享文档页面以导入此信息。我在 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 发行版提供的 mysql_tzinfo_to_sql 程序。 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

【讨论】:

  • 我还需要重新启动 MySQL 守护程序才能生效(在 Debian 上)。
【解决方案3】:

如果这产生 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 获取时区,这里有一个 article 描述了如何(尚未尝试过,但看起来它会工作)。

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

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 |
+---------------------+---------------------+

【讨论】:

  • 非常感谢!很有用~
  • 不错的答案!间隔 + convert_tz 摇滚!
  • 什么是user_timezone_offset_in_hours
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-29
  • 1970-01-01
  • 2017-07-06
  • 1970-01-01
  • 2015-12-28
相关资源
最近更新 更多