mysql HOUR() 考虑时区

mysql HOUR() accounting for timezones

我有一个查询 returns 结果按小时分组,就像这样。

SELECT COUNT(*) FROM (`shipped_products`) WHERE HOUR(timestamp) = 8

问题是,我在本地主机上得到的结果与在实时服务器上得到的结果不同。两者(UTC)的数据完全相同。我相信我的本地主机数据库是纽约,而实时数据库是 UTC,因此,HOUR() 在这两种环境中的工作方式不同。我没有更改实时服务器时区的权限,并且想避免更改本地数据库时区。无论数据库时区如何,查询内部是否有一种方法可以确保 HOUR() 函数返回相同的结果?

试试 CONVERT_TZ() function:

SELECT COUNT(*) FROM (`shipped_products`)
WHERE HOUR(CONVERT_TZ(timestamp, 'UTC', 'America/New York')) = 8

手册警告:

Note

To use named time zones such as 'MET' or 'Europe/Moscow', the time zone tables must be properly set up. See Section 10.6, “MySQL Server Time Zone Support”, for instructions.

您也可以改用小时值,但会丢失任何时区信息,例如历史时区更改、DST 等

SELECT COUNT(*) FROM (`shipped_products`)
WHERE HOUR(CONVERT_TZ(timestamp, '+00:00', '-05:00')) = 8

虽然 Matt Johnson 有正确的答案,而 miken32 在大多数情况下都有正确的答案,但如果您发现自己无法更改数据库权限、无法上传时区表、无法执行 SET 语句,并且需要一些成功的东西' 在夏令时更改期间中断,以下将起作用。

$corrected_hour = $hour;
if ($_SERVER['HTTP_HOST'] != 'localhost') 
{
    $dateTimeZoneNY = new DateTimeZone('America/New_York');
    $dateTimeZoneUTC = new DateTimeZone('UTC');
    $dateTimeUTC = new DateTime('now', $dateTimeZoneUTC);
    $timeOffset = $dateTimeZoneNY->getOffset($dateTimeUTC);
    $corrected_hour = $hour + abs($timeOffset) / 60 / 60;
}

只要两个数据库保持当前时区设置,这就不会中断。

您可以将会话时区(或全球时区)设置为 UTC,as described in the docs

set time_zone = '+00:00';

然后 HOUR 和其他函数将解释 UTC 中的 timestamp 类型。另见 timestampdatetime in this part of the docs.

之间的区别

但是,另一个问题是 WHERE HOUR(timestamp) = 8 将进行您的查询 non-sargable,因此它将不得不扫描整个 table,并且无法接受利用您可能拥有的任何索引。 table 中的记录越多,速度就越慢。 (特别是如果您有数千或数百万条记录)。

更好的方法是将其重写为范围查询。获取要筛选的开始和停止时间,并使用半开间隔。

WHERE timestamp >= @start AND timestamp < @end

当然,您在计算起止值时会将值锁定到特定日期。相反,如果您确实想要 天的 8:00 UTC 小时,那么您应该使用该信息在 table 上创建一个单独的整数列,这样您就可以在搜索查询中使用它。

WHERE your_utc_hour_column = 8

这可能是某些数据库中的计算列,但我认为 MySQL 不支持这些列,因此您必须手动创建和填充它。