php / mysql正确查询时区敏感行的方法

时间:2012-09-11 00:11:46

标签: php mysql timezone timezone-offset

我将行数用户存储在数据库中。我允许用户输入他们的时区,该时区也存储在数据库中。

我的应用会在他们指定的时间每天向他们发送电子邮件。我将电子邮件传递作为一行存储在另一个db表中。这将通过cron作业发生。

我希望我的查询能够提取用户记录,其中该用户的最新电子邮件至少为1400分钟(24小时前),并根据其时区超过了指定的时间。

我有以下查询,但我不知道如何考虑mysql的时区和用户的时区。有什么建议?

SELECT u.id, u.email, u.timezone_offset, u.email_time, TIMESTAMPDIFF( 
MINUTE , CONCAT( DATE( MAX( e.created ) ) ,  ' ', u.email_time ) , NOW( ) ) AS min_since_last_email
FROM Users u
INNER JOIN Emails e ON e.user_id = u.id
WHERE min_since_last_email > 1400
GROUP BY u.id

时区偏移量是GMT的偏移量。对于我来说,它就像“-5”。

2 个答案:

答案 0 :(得分:0)

稍微改变逻辑:在PHP中进行计算,以UTC格式存储数据库中的所有内容。然后它是一个简单的提取。您可以使用时区功能轻松地在PHP中执行此操作,并且可以根据用户进行自定义 - SQL语句是一个全局语句,每个用户都可以自定义(就像您遇到的那样)。

所以“发送时间电子邮件”可能是UTC时间凌晨4点(并且在数据库中),但是你向用户显示“晚上9点”。

您可能遇到的一个问题是夏令时 - 当时区翻转进/出夏令时时,您需要重新计算所有时间。但是你现在的方法不允许这样做......

答案 1 :(得分:0)

您上次发送电子邮件的日期是您的日期,因此请存储该日期。

随着您发送越来越多的电子邮件,计算每位用户的最高费用将变得越来越昂贵。非规范化并将该日期时间的副本也放在用户记录中。

然后,计算该日期的年龄和用户时区的偏移量。

select *, date_add(now(), interval timezone_offset hour) as email_expected_on
from users
where last_email_date <= date_add(now(), interval timezone_offset hour);

请注意,不将公式应用于users.last_email_date也很重要,否则您将无法在该列上使用索引。