views:

39

answers:

1

My Java application needs to send an email out to all users once per day. I'd like to deliver it at approximately 2AM based on each user's local time. So a user in New York would get the message at 2AM America/New_York time. A user in Los Angeles would get the message at 2AM America/Los_Angeles time. My mailing process would run once each hour of the day.

I plan to use HTML5 geo-location features or IP Address geo-locating to automatically determine each user's time zone during sign up. Of course, the user can modify the timezone manually if these values are incorrect. I intend to store the selected timezone in the User object as a Timezone ID string, such as "America/New_York". This will persist to the database as a string, but this could be changed if necessary.

Things to consider:

  • I need to account for daylight savings time, so the user always receives the email around 2AM. This means I can't just store GMT-8 or similar UTC offsets in the user object. Part of the year Los Angeles is in GMT-7, and other parts it is in GMT-8.
  • Another SO question has answers that suggest storing offset information, but I don't see how that would work as the times in different places can change throughout the year. I'm not going to update all my user objects timezones whenever a timezone change event somewhere in the world happens.
  • I am using JodaTime in my application, so I can take advantage of it if it will help.
  • I'm using Hibernate for database queries and would like to find a solution that could be handled in a hibernate query, without needing to process hundreds of thousands of user records in Java.

I'm using Spring Scheduling cron features (via Quartz) to run a method at 2 minutes past the hour every hour of the day. Right now most of my users are in America/Los_Angeles, so I'm manually forcing all mail to be sent at 2:02AM Pacific time. The following method runs every hour at :02 past the hour, but it manually checks the time and only proceeds if the current time in Los Angeles is in the 2:00 hour. This means users in other places will get the email at a different time than 2AM.

@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
}

So, what I need is to perform a database query that will give me all users that have a local time in the 2:00AM hour, based on the time zone in their User object. Any thoughts on how to accomplish this?

A: 

Pretty simple:

1.Fire a cron job each hour
2.calculate user's current time based on the current GMT time and user's timeoffset.
3.If it is 2 am for particular User send an email to her/him and make that user flagged for not to consider in next job execution.

To calculate user's current time from user's OFFSET and GMT time here is an illustration:

// Get the current time in Hong Kong
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone("Hongkong"));

int hour12 = cal.get(Calendar.HOUR);         // 0..11
int minutes = cal.get(Calendar.MINUTE);      // 0..59
int seconds = cal.get(Calendar.SECOND);      // 0..59
boolean am = cal.get(Calendar.AM_PM) == Calendar.AM;

// Get the current hour-of-day at GMT
cal.setTimeZone(TimeZone.getTimeZone("GMT"));
int hour24 = cal.get(Calendar.HOUR_OF_DAY);  // 0..23

// Get the current local hour-of-day
cal.setTimeZone(TimeZone.getDefault());
hour24 = cal.get(Calendar.HOUR_OF_DAY);      // 0..23
org.life.java
@org.life.java: The issue isn't figuring it out in Java, it is working out the best way to store the timezone in the database so that a single hibernate query can load all users who's current time is 2AM. Maybe there isn't any HQL to solve this, in which case I'll revert to Java, but I'm hoping someone has some ideas.
Tauren
Well you can always query for the same.
org.life.java