事实证明这似乎是一个复杂的主题,如果我的方法太简单,请告诉我。
基本上我正在尝试做的是每天早上7点向用户列表发送电子邮件提醒(只有当他们有提醒信息时,但除此之外)。当然,早上7点是基于全世界每个人的服务器位置的不同时间。
计划是在用户注册时通过javascript收集到GMT抵消小时:
var today = new Date();
var offset = -(today.getTimezoneOffset()/60);
很简单,我现在知道偏移小时并将其与其他用户数据一起存储在数据库中。现在服务器端我有一个TimerTask设置,每小时运行一次。我收集系统小时(比如早上5点),看看离目标时间有多远(在这种情况下是2(7-5)),得到系统偏移小时(在这种情况下是-5),然后拉所有来自数据库的GMT偏移小时为-3(-5 + 2)的用户,然后发送电子邮件等。此时我假设我知道它的上午7点为每个人,时区偏移为-3,我可以继续这个过程。这将在下一个小时再次运行,并收集时区偏移为-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.
}
我理解可能客户时区可能设置不正确,因此产生了结果,但我愿意承担这种风险,因为它不是绝对必要的提醒在早上7点出门,更可取。< / p>
答案 0 :(得分:1)
计划是在用户注册时通过javascript收取GMT抵消小时数
这不足以一致地获得时区。它没有考虑夏令时。因此,如果用户在任何可以观察夏令时的地方,他们将在早上6点收到电子邮件大约半年,或者他们将在早上8点收到大约半年的电子邮件。你可能最好根据IP地理位置+偏移来猜测他们的时区。
我有一个TimerTask设置,每小时运行一次。
我建议比这更频繁地跑步。否则,您可能会发现,在发送电子邮件之前,您最终会唤醒 - 然后您又回去睡觉,并在下次7:59发送电子邮件...这可能是根据客户DST的变化,使用您当前的方案是8:59。那时你的预计发送时间差不多两个小时了!
我收集系统时间
也不要这样做。此时有两个时区需要考虑 - 并且您的服务器时区完全不相关。使用UTC直到转换为客户端的本地时间。它会让生活变得更加简单。如果您仍在使用Calendar
,则只需设置时区即可完成此操作。
查看您的代码,如果您按照完全匹配的小时检查,看起来您最终可能会完全错过一堆用户。如果您最终在(比方说)3:59运行一次,然后在4:01运行一次,那么您将错过任何必须在4运行的人。我建议您记录上次向每个用户发送邮件的时间 - 或者可能在你上次跑步时 - 并使用它来确保总是抓住每个人。
最后,我强烈建议您使用Joda Time。这是一个很多更干净的日期/时间API,它可以帮助您思考在代码中正确使用的正确概念。