Java 每天在同一时间向不同时区发送电子邮件

rya*_*dlf 6 java timezone gmt

原来这似乎是一个复杂的主题,请告诉我我的方法是否太简单。

基本上,我想要做的是每天早上 7 点向用户列表发送电子邮件提醒(仅当他们有提醒出现时,但这不是重点)。当然,早上 7 点是在不同的时间,具体取决于世界各地的每个人的服务器位置。

计划是在用户注册时通过 javascript 从用户那里收集 GMT 时差:

var today = new Date();  
var offset = -(today.getTimezoneOffset()/60);
Run Code Online (Sandbox Code Playgroud)

很简单,我现在知道偏移时间并将其与其他用户数据一起存储在数据库中。现在服务器端我设置了一个每小时运行一次的 TimerTask。我收集系统小时(比如它的 5 点),看看离我的目标时间有多远(在这种情况下是 2 (7-5)),得到系统偏移小时(在这种情况下是 -5),然后拉数据库中 GMT 偏移时间为 -3 (-5 + 2) 的所有用户,然后发送电子邮件等。此时我假设我知道每个人的时区偏移为 -3 的时间是早上 7 点,我可以继续这个过程。这将在下一小时再次运行并收集时区偏移为 -4 的所有用户。这是真正有效的东西,还是我错过了什么?

Calendar systemTime = Calendar.getInstance();
int targetHour = 7;
int currentHour = systemTime.get(Calendar.HOUR_OF_DAY); //Its 5 am.
int difference = targetHour - currentHour; //2
int zoneOffset = systemTime.get(Calendar.ZONE_OFFSET) / (1000*60*60); //-5
int targetZone = zoneOffset + difference; //-3

List<User> users = userDAO.findByZoneOffset(targetZone);
for(User user : users) {
    //Send email or whatever I want to do with these users.
}
Run Code Online (Sandbox Code Playgroud)

我理解客户端时区可能设置不正确并因此产生关闭结果的可能性,但我愿意冒这个风险,因为提醒在早上 7 点准时发出并不是绝对必要的,只是更可取。

Jon*_*eet 1

该计划是在用户注册时通过 JavaScript 收集到 GMT 偏移时间

这不足以获得一致的时区。它不考虑夏令时。因此,如果用户在遵守夏令时的任何地方,他们要么在大约半年的时间里在早上 6 点收到电子邮件,要么在大约半年的时间里在早上 8 点收到电子邮件。您最好根据 IP 地理位置 + 偏移量猜测他们的时区。

我设置了一个每小时运行一次的 TimerTask。

我建议比这更频繁地跑步。否则,您很可能会发现自己在发送电子邮件之前就醒了- 所以您然后回去睡觉,并在下次 7:59 发送电子邮件...这可能是您当前的 8:59方案,基于客户端 DST 更改。那时您距离预定的发送时间还有近两个小时!

我收集系统时间

也不要这样做。此时有两个时区需要考虑 - 并且您的服务器时区完全无关。使用 UTC,直到转换为客户端的本地时间。这将使生活变得更加简单。如果您仍在使用Calendar,则只需设置其时区即可完成此操作。

看看你的代码,如果你按精确匹配的时间进行检查,看起来你最终也可能会完全错过一群用户。如果您最终在 3:59 运行一次,然后在 4:01 运行一次,您就会错过任何必须在 4 点运行的人。我建议跟踪您上次向每个用户发送邮件的时间 -或者可能是你上次跑步时 - 并用它来确保你总是抓住每个人。

最后,我强烈建议您使用Joda Time。它是一个清晰的日期/时间 API,它将帮助您思考在代码中的正确位置使用正确的概念。