Java Quartz-Scheduler across TimeZone

后端 未结 3 1617
孤街浪徒
孤街浪徒 2020-12-09 20:32

My server runs on Europe/Rome timezone -and this one is the default tz on the server-, I need to schedule jobs according the user\'s timezone, so, if a user, living on Paci

相关标签:
3条回答
  • 2020-12-09 20:40

    You can use ZonedDateTime from java8/java8+, In that way you will not need to explicitly convert the given time into server specific time:

    protected static Trigger createCronTrigger(String triggerName, ZonedDateTime startTime, String cronExpression, int misFireInstruction, ZoneId timeZone) {
        Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity(triggerName)
            .startAt(Date.from(startTime.toInstant())).withSchedule(CronScheduleBuilder.cronSchedule(cronExpression).inTimeZone(TimeZone.getTimeZone(timeZone)).withMisfireHandlingInstructionDoNothing())
            .build();
        return trigger;
    }
    

    you can read more about ZonedDateTime from Here

    0 讨论(0)
  • 2020-12-09 20:42

    Date doesn't carry any TZ data, and Daylight Savings Time is actually its own TZ (EST is Easter Standard Time, EDT is Eastern Daylight Savings Time). The only thing that may pe an issue is that some places, like Phoenix Arizona, do not recognize DST. Any time you need TZ data preserved, Calendar is the way to go.

    0 讨论(0)
  • 2020-12-09 21:04

    I think I found the solution, tested and it works until proved otherwise ;)

    Recup My server runs on a specific timezone (i.e. Europe/Rome)

    If a user on Pacific/Honolulu TZ want to schedule a job that starts on Sun, 27 Jan 2013 at 3:00PM end ends on Thu, 31 Jan 2013 at 9:00PM that fire every day every five minutes starting from 2:00PM to 10:55PM (0 0/5 14-22 * * ?) the correct way is the following:

    • set the user timezone in inTimeZone method on the CronScheduleBuilder
    • adapt to the server time the startAt and endAt dates by converting from Pacific/Honolulu to Europe/Rome

    Sample Code:

    // Begin User Input
    String userDefinedTZ = "Pacific/Honolulu"; // +11
    
    int userStartYear = 2013;
    int userStartMonth = Calendar.JANUARY;
    int UserStartDayOfMonth = 27;
    int userStartHour = 15;
    int userStartMinute = 0;
    int userStartSecond = 0;
    
    int userEndYear = 2013;
    int userEndMonth = Calendar.JANUARY;
    int UserEndDayOfMonth = 31;
    int userEndHour = 21;
    int userEndMinute = 0;
    int userEndSecond = 0;
    // End User Input
    
    
    Calendar userStartDefinedTime = Calendar.getInstance();
    // set start schedule by user input
    userStartDefinedTime.set(userStartYear, userStartMonth, UserStartDayOfMonth, userStartHour, userStartMinute, userStartSecond);
    
    Calendar userEndDefinedTime = Calendar.getInstance();
    // set end schedule by user input
    userEndDefinedTime.set(userEndYear, userEndMonth, UserEndDayOfMonth, userEndHour, userEndMinute, userEndSecond);
    
    
    CronTrigger trigger = newTrigger()
      .withIdentity("name", "group")
      .withSchedule(
        // define timezone for the CronScheduleBuilder
        cronSchedule("0 0/5 14-22 * * ?").inTimeZone(TimeZone.getTimeZone("Pacific/Honolulu"))
      )
      // adapt user start date to server timezone
      .startAt( convertDateToServerTimeZone(userStartDefinedTime.getTime(), userDefinedTZ) )
      // adapt user end date to server timezone
      .endAt( convertDateToServerTimeZone(userEndDefinedTime.getTime(), userDefinedTZ) )
      .build();
    

    Utility to convert dates based on tz:

    public Calendar convertDateToServerTimeZone(Date dateTime, String timeZone) {
        Calendar userDefinedTime = Calendar.getInstance();
        userDefinedTime.setTime(dateTime);
        if(!TimeZone.getDefault().getID().equalsIgnoreCase(timeZone)) {
        System.out.println        ("original defined time: " + userDefinedTime.getTime().toString() + " on tz:" + timeZone);
        Calendar quartzStartDate = new GregorianCalendar(TimeZone.getTimeZone(timeZone));
        quartzStartDate.set(Calendar.YEAR, userDefinedTime.get(Calendar.YEAR));
        quartzStartDate.set(Calendar.MONTH, userDefinedTime.get(Calendar.MONTH));
        quartzStartDate.set(Calendar.DAY_OF_MONTH, userDefinedTime.get(Calendar.DAY_OF_MONTH));
        quartzStartDate.set(Calendar.HOUR_OF_DAY, userDefinedTime.get(Calendar.HOUR_OF_DAY));
        quartzStartDate.set(Calendar.MINUTE, userDefinedTime.get(Calendar.MINUTE));
        quartzStartDate.set(Calendar.SECOND, userDefinedTime.get(Calendar.SECOND));
        quartzStartDate.set(Calendar.MILLISECOND, userDefinedTime.get(Calendar.MILLISECOND));
        System.out.println("adapted time for " + TimeZone.getDefault().getID() + ": " + quartzStartDate.getTime().toString());
        return quartzStartDate;
        } else {
        return userDefinedTime;
        }
    }
    

    == BEGIN OF UPDATE 2012-01-24 ==

    Quartz Based Utility to convert dates based on tz using DateBuilder:

    public Calendar convertDateToServerTimeZone(Date dateTime, String timeZone) {
        Calendar userDefinedTime = Calendar.getInstance();
        userDefinedTime.setTime(dateTime);
        if(!TimeZone.getDefault().getID().equalsIgnoreCase(timeZone)) {
          System.out.println("original defined time: " + userDefinedTime.getTime().toString() + " on tz:" + timeZone);
    
          Date translatedTime = DateBuilder.translateTime(userDefinedTime.getTime(), TimeZone.getDefault(), TimeZone.getTimeZone(timeZone));
    
          Calendar quartzStartDate = new GregorianCalendar();
          quartzStartDate.setTime(translatedTime);
          System.out.println("adapted time for " + TimeZone.getDefault().getID() + ": " + quartzStartDate.getTime().toString());
          return quartzStartDate;
        } else {
          return userDefinedTime;
        }
    }
    

    == END OF UPDATE 2012-01-24 ==

    So on my Europe/Rome Quartz server this job are scheduled for starting from Mon Jan 28 02:00:00 CET 2013 to Fri Feb 01 08:00:00 CET 2013 and fire every five minute every day from 01:00AM to 08:55PM

    When building your Dates for start and end times also specify the timezone (on the java.util.Calendar, or date format string, or org.quartz.DateBuilder) before instantiating the Date. Then quartz stores the date as milliseconds since January 1, 1970 in UTC in that particular timezone - and hence when the server's timezone changes, the trigger is not affected.

    0 讨论(0)
提交回复
热议问题