mySQL需要在EST中显示时区,但不能更改全局时间设置

时间:2014-10-01 15:18:29

标签: mysql datetime timezone timezone-offset

我面临一个奇怪的问题。 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)
;

我真的很感激任何帮助。 再次感谢

2 个答案:

答案 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)