我面临一个奇怪的问题。 mySQL中的全局时区设置为UTC。在mySQL的单个实例中有多个表(子数据库)(我使用database.NET作为管理器);所以我无法改变全球时区。
以下是我的查询。 我需要的只是显示EST中的时间。我已经看到了@@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)
;
我真的很感激任何帮助。 再次感谢
答案 0 :(得分:2)
DATETIME
数据类型不受全局或连接本地时区设置的影响。这仅适用于TIMESTAMP
数据类型。这就解释了为什么你试图用@@ session.TimeZone捣乱不会产生任何影响。不过,NOW()
和CURDATE()
受到影响。
您说您的DATETIME
数据以UTC格式存储。这太棒了。当您以这种方式存储数据时,生活会更轻松
在您使用我即将给您的建议之前,请确保您的MySQL服务器正确加载了时区表。执行此命令并确保您没有得到NULL结果。
SELECT CONVERT_TZ(NOW(), 'America/New_York', 'UTC')
如果这不起作用 - 如果您收到NULL
或错误 - 您需要让服务器人员加载时区表。他们应该这样做。他们知道如何。 (如果他们不这样做,你应该得到一个新的服务提供商。)
我们需要使用名为&#39; America / New_York&#39;的时区。因为大概你想在每年的适当日期在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')
如果您希望将普通日期对象和普通时间对象组合在一起,您今天下午4点也可以使用ADDTIME(CURDATE(),'16:00')
获取DATETIME
值。同样,明天凌晨2点可以这样:
ADDTIME(CURDATE(),'02:00') + INTERVAL 1 DAY
请注意,这种形式的WHERE子句允许createDate
列上的range scan on an index。这对性能非常有利。
答案 1 :(得分:0)
将日期时间从时区转换为另一个时区:
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
您可能会想到&#34;为什么不在WHERE子句中?&#34;
如果在where子句中使用函数,则不能使用索引(这会导致全表扫描)。因此,只需过滤掉日期范围内的记录和HAVING子句中的小时数
FYI
CURRENT_DATE + INTERVAL 16 HOUR
是
的缩写DATE_ADD(CURRENT_DATE, INTERVAL 16 HOUR)