我面临一个奇怪的问题。 mySQL 中的全局时区设置采用 UTC。 mySQL的单个实例中有多个表(子数据库)(我使用database.NET作为管理器);所以我无法更改全球时区。
以下是我的询问。 我需要的只是显示东部时间的时间。我见过一些带有
@@sessionTimeZone
的解决方案,但它们不起作用。 此外,我还遇到了在美国东部时间晚上 9 点之前收集数据的问题,但在 UTC 中则为第二天凌晨 1 点。
我的主要困惑是数据已经以UTC存储在表中;但是,我希望看到这些
datetime
字段显示在 EST 中。
cartId
是一个数值域
createDate
是日期时间字段
我只是使用 http://fishcodelib.com/database.htm 并连接到 mySQL 数据库。
SELECT DATE(createDate)
,DATE_FORMAT(createDate, '%l%p') as HourOfDay
,count(cartId) as numCarts_ALL
FROM carts
WHERE createDate >= '2014-09-24'
AND createDate < '2014-10-01'
AND HOUR(createDate) >= 10 AND HOUR(createDate) <21
GROUP by DATE(createDate),HOUR(createDate)
;
我将非常感谢任何帮助。 再次感谢
DATETIME
数据类型不受全局或连接本地时区设置的影响。这只适用于 TIMESTAMP
数据类型。这就解释了为什么您尝试使用 @@session.TimeZone 进行修改没有任何效果。不过,NOW()
和 CURDATE()
受到影响。
您说您的
DATETIME
数据存储在UTC中。那太好了。当您以这种方式存储数据时,生活会变得更加轻松。
在使用我即将给您的建议之前,请确保您的 MySQL 服务器已正确加载时区表。 执行此命令并确保您不会得到 NULL 结果。
SELECT CONVERT_TZ(NOW(), 'America/New_York', 'UTC')
如果这不起作用 - 如果您收到
NULL
或错误 - 您需要让服务器人员加载时区表。他们应该这样做。他们知道怎么做。 (如果他们不这样做,您应该寻找新的服务提供商。)我们需要使用名为“America/New_York”的时区,因为您可能希望在每年的适当日期在 EDT 和 EST 之间自动切换。
现在,要从表中检索正确转换的 UTC
DATETIME
值,请执行以下操作:
SELECT CONVERT_TZ(createDate, 'UTC', 'America/New_York') AS createDate
FROM yourTable
这很酷,因为如果您有位于不同时区的用户,您可以将时区设置设为用户首选项。
要将本地时间值存储为 UTC,只需相反操作即可。 例如。
INSERT INTO yourTable (createDate) VALUES (CONVERT_TZ(?, 'America/New_York', 'UTC'))
现在做
SELECT NOW()
并查看 NOW() 是当地时间还是 UTC。 如果是 UTC,那么您应该通过执行
SET TIME_ZONE='America/New_York'
来开始会话。这将使您的时区设置正确,以便
NOW()
和
CURDATE()
做您想做的事。然后,要从表中获取昨天(当地时间)的行,请执行以下操作:
WHERE createDate >= CONVERT_TZ(CURDATE(),'America/New_York','UTC') - INTERVAL 1 DAY
AND createDate < CONVERT_TZ(CURDATE(),'America/New_York','UTC')
这会将当地时间午夜转换为 UTC 并获取项目范围。
要获取今天下午 4 点到明天凌晨 2 点的所有数据,您可以这样做:
今天下午 4 点(当地时间)是
CURDATE() + INTERVAL 16 HOUR
。明天凌晨 2 点是
CURDATE() + INTERVAL 26 HOUR
或者你可以写它CURDATE() + INTERVAL 1 DAY + INTERVAL 2 HOUR
因此获取该范围需要这样:
WHERE createDate >= CONVERT_TZ(CURDATE() + INTERVAL 16 HOUR,'America/New_York','UTC')
AND createDate < CONVERT_TZ(CURDATE() + INTERVAL 26 HOUR,'America/New_York','UTC')
如果您愿意组合普通日期对象和普通时间对象,还可以使用
ADDTIME(CURDATE(),'16:00')
获取今天下午 4 点的
DATETIME
值。同样,你可以像这样得到明天凌晨 2 点: ADDTIME(CURDATE(),'02:00') + INTERVAL 1 DAY
请注意,这种形式的 WHERE 子句允许对
createDate
列上的索引进行范围扫描。这对于性能非常有好处。
SELECT DATE(CONVERT_TZ(createDate, '+00:00', '-04:00')) createdDate,
HOUR(CONVERT_TZ(createDate, '+00:00', '-04:00')) hourOfDay
FROM carts
WHERE
createDate BETWEEN CURRENT_DATE + INTERVAL 16 HOUR AND CURRENT_DATE + INTERVAL 26 HOUR
GROUP BY createdDate, hourOfDay
针对不同日期
SELECT DATE(CONVERT_TZ(createDate, '+00:00', '-04:00')) createdDate,
HOUR(CONVERT_TZ(createDate, '+00:00', '-04:00')) hourOfDay
FROM carts
WHERE
createDate BETWEEN '2014-09-24' AND '2014-10-01'
GROUP BY createdDate, hourOfDay
HAVING hourOfDay <= 2 OR hourOfDay >= 20
您可能会想“为什么不在 WHERE 子句中?”
如果where子句中使用了函数,则不能使用索引(会导致全表扫描)。所以只需过滤掉日期范围内的记录,以及 HAVING 子句中的小时即可
仅供参考
CURRENT_DATE + INTERVAL 16 HOUR
是的缩写
DATE_ADD(CURRENT_DATE, INTERVAL 16 HOUR)
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
然后添加文档底部
默认时区=“UTC+N” (就我而言,住在韩国: 默认时区=“+9:00”)
然后重新启动