我的Java应用程序需要每天向所有用户发送一封电子邮件。我想在大约凌晨2点根据每个用户的当地时间提供。因此,纽约的用户将在2AM America / New_York时间收到消息。洛杉矶的用户将在2AM America / Los_Angeles时间收到消息。我的邮件流程每天都会运行一次。
我打算使用HTML5地理位置功能或IP地址定位来在注册过程中自动确定每个用户的时区。当然,如果这些值不正确,用户可以手动修改时区。我打算将选定的时区存储在User对象中作为时区ID字符串,例如“America / New_York”。这将作为字符串持久保存到数据库,但如果需要,可以更改。
需要考虑的事项:
我正在使用Spring Scheduling cron功能(通过Quartz)在当天每小时2分钟运行一个方法。现在我的大多数用户都在America / Los_Angeles,所以我手动强制所有邮件都在太平洋时间凌晨2:02发送。以下方法每小时运行一次:02小时,但它会手动检查时间,并且仅在洛杉矶当前时间为2:00小时时才会进行。这意味着其他地方的用户将在凌晨2点以外的时间收到电子邮件。
@Scheduled(cron="0 2 * * * *")
public void sendDailyReportEmail() {
DateTime now = new DateTime(DateTimeZone.forID("America/Los_Angeles"));
if (now.getHourOfDay() != 2) {
log.info("Not 2AM pacific, so skipping email reports");
return;
}
// send email reports
}
因此,我需要的是执行一个数据库查询,该查询将根据用户对象中的时区为我提供在凌晨2:00时有本地时间的所有用户。有关如何实现这一点的任何想法?
答案 0 :(得分:2)
我已经给出了更多的想法,并有一个可能的解决方案。我还没有实现它,但我认为它应该工作。基本上,它涉及执行以下查询(注意:这是MySQL特定的):
select * from members where hour(convert_tz(now(),'UTC',timezone)) = 3;
此查询通过执行以下操作选择当前本地时间在凌晨3点到凌晨3点59分之间的所有成员:
now()
获取当前服务器时间,这是UTC时间,因为数据库服务器配置为UTC时间。 convert_tz()
函数将该时间转换为成员表的timezone
列中指定的成员的时区。请注意,Member类包含“America / Los_Angeles”格式的时区字段。hour()
函数的小时数,以查看它是否为3
,持续3 AM。我有点担心每小时对系统中的每个成员进行时区转换和计算。我将不得不测试一些东西,看看它对数据库造成了什么样的负载,但它可能会淹没数百万甚至10万的用户。
应该显着减轻负载的替代方案,但不是那么优雅,请执行以下操作(注意此代码未经测试!):
@Scheduled(cron="0 2 * * * *")
public void sendDailyReportEmail() {
Query query = session.createQuery(
"select distinct m.timezone from Member m");
List<String> timezones = query.list();
for (String timezone : timezones) {
DateTime now = new DateTime(DateTimeZone.forID(timezone));
if (now.getHourOfDay() == 3) {
Query query2 = session.createQuery(
"from Member where timezone = :zone");
query2.setParameter("zone", timezone);
List<Member> members = query2.list();
// send email reports
}
}
}
此代码执行此操作:
这会在每小时开始时增加一些额外开销,但不需要按用户时区处理。有可能系统实际只会使用几十个独特的时区。我不太可能在所有500多个时区中拥有会员。
最后一件事。我没有在凌晨2点发送电子邮件,而是将其移至凌晨3点。这是因为当夏令时在春天变化时,时间从凌晨2点变为凌晨3点。因此,没有上午2:02这样的事情,这意味着当天不会发送电子邮件。此外,在秋季,系统可以发送每个用户2封电子邮件,因为一个小时重复。我需要找出非美国时区是否会在不同时间改变时间,因为凌晨3点可能是其他地方的问题。