我有一个查询返回按小时分组的结果,就像这样。
SELECT COUNT(*) FROM (`shipped_products`) WHERE HOUR(timestamp) = 8
问题是,我在localhost上获得的结果与在实时服务器上的结果不同。两者的数据完全相同(UTC)。我相信我的localhost数据库是纽约,而实时数据库是UTC,因此,HOUR()在这两种环境中的工作方式不同。我无权更改实时服务器时区,并且希望避免更改本地数据库时区。在查询中是否有一种方法可以确保HOUR()函数返回相同的结果而不管数据库时区?
答案 0 :(得分:3)
SELECT COUNT(*) FROM (`shipped_products`)
WHERE HOUR(CONVERT_TZ(timestamp, 'UTC', 'America/New York')) = 8
手册警告:
注意
要使用
'MET'
或'Europe/Moscow'
等命名时区,必须正确设置时区表。 See Section 10.6, “MySQL Server Time Zone Support”,有关说明。
您也可以使用小时值,但会丢失任何时区知识,例如历史时区更改,DST等。
SELECT COUNT(*) FROM (`shipped_products`)
WHERE HOUR(CONVERT_TZ(timestamp, '+00:00', '-05:00')) = 8
答案 1 :(得分:2)
您可以将会话时区(或全球时区)设置为UTC as described in the docs。
set time_zone = '+00:00';
然后HOUR
和其他函数将解释UTC中的timestamp
类型。另请参阅timestamp
和datetime
in this part of the docs之间的差异。
然而,另一个问题是WHERE HOUR(timestamp) = 8
会使您的查询non-sargable,因此它必须扫描整个表格,并且无法利用任何索引你可能有。表中的记录越多,得到的速度就越慢。 (特别是如果你有数千或数百万条记录)。
更好的方法是将其重写为范围查询。获取您想要过滤的开始和停止时间,并使用半开间隔。
WHERE timestamp >= @start AND timestamp < @end
当然,在计算起始值和结束值时,您会将值锁定到特定日期。如果你确实想要每天每天的8:00 UTC小时,那么你应该在表上创建一个包含该信息的单独整数列,这样你就可以在一个可搜索的查询中使用它。
WHERE your_utc_hour_column = 8
这可能是某些数据库中的计算列,但我不认为MySQL支持这些列,因此您必须手动创建并填充它。
答案 2 :(得分:0)
虽然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;
}
只要两个数据库都保持其当前时区设置,就不会中断。