64

How can I configure the time zone for a Spring based @Scheduled cron job?

Background:

I have a job that executes once a day, say 2 PM, using Spring's @Scheduled annotation:

@Scheduled(cron = "0 0 14 * * *")
public void execute() {
    // do scheduled job
}

The problem is that 2 PM differs between different servers, because Spring uses on TimeZone.getDefault() internally. Moreover, the JavaDoc of TimeZone.getDefault() states that:

Gets the default TimeZone for this host. The source of the default TimeZone may vary with implementation.

In other words, the time zone is not determined. It may depend on JVM implementation, server time zone configuration, server location, and / or other unknown factors. Consequently, the cron job triggers on different times on different servers, unless there is a way to explicitly set which time zone that should be used?

I am using Spring 3.2.2.


Update

As of Spring 4, Spring Jira issue SPR-10456 has been resolved. Consequently, the @Scheduled annotation has a new zone attribute for exactly this purpose.

matsev
  • 32,104
  • 16
  • 121
  • 156
  • possible duplicate of [Initialize default Locale and Timezone with Spring configuration](http://stackoverflow.com/questions/4416955/initialize-default-locale-and-timezone-with-spring-configuration) – NimChimpsky Apr 10 '13 at 15:38
  • 2
    @NimChimpsky The question is related, but in my opinion not the same. The link that you provided describes how to set the default time zone on a system level, whereas I am only interested in specifying the time zone for the cron job. – matsev Apr 10 '13 at 21:36
  • Oh well, looks like the solution is already mentioned in the question, but I didn't find it in the answers when I was looking for one. – Vlasec Dec 10 '15 at 09:25

5 Answers5

50

It turned out that I could not use the @Scheduled annotation, but I implemented a work-around. In the JavaDoc of the SchedulingConfigurer it is stated that:

[SchedulingConfigurer is] Typically used for setting a specific TaskScheduler bean to be used when executing scheduled tasks or for registering scheduled tasks in a programmatic fashion as opposed to the declarative approach of using the @Scheduled annotation.

Next, I changed the cron job to implement the Runnable interface and then updated my configuration file to implement the SchedulingConfigurer, see below:

@Configuration
@EnableScheduling
@ComponentScan("package.that.contains.the.runnable.job.bean")
public class JobConfiguration implements SchedulingConfigurer {

    private static final String cronExpression = "0 0 14 * * *";
    private static final String timeZone = "CET";

    @Autowired
    private Runnable cronJob;

    @Bean
    CronTrigger cronTrigger() {
        return new CronTrigger(cronExpression, TimeZone.getTimeZone(timeZone));
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addCronTask(new CronTask(job, cronTrigger()));
    }
}

Please read the JavaDoc of the @EnableScheduling for more information.


Update

As of Spring 4, Spring Jira issue SPR-10456 has been resolved. Consequently, the @Scheduled annotation has a new zone attribute for exactly this purpose, e.g.

@Scheduled(cron = "0 0 14 * * *", zone = "CET")
public void execute() {
    // do scheduled job
}
matsev
  • 32,104
  • 16
  • 121
  • 156
  • 13
    A usage example of the timezone in the `@scheduled` annotation would be `@Scheduled(cron = "0 0/60 * * * ?",zone = "Asia/Colombo")` – Ishan Thilina Somasiri Aug 24 '14 at 15:09
  • @matsev I have followed your solution as I am also dealing with timezones along with cronTrigger, and my code is not working properly. Can you please check my code and guide me if I have went wrong anywhere? Here is the link: http://stackoverflow.com/questions/31370293/crontrigger-is-not-triggering-at-specified-time-but-instead-sends-multiple-push – Chandz Jul 27 '15 at 06:09
  • @IshanThilinaSomasiri Can you please help me by checking this link, http://stackoverflow.com/questions/31370293/crontrigger-is-not-triggering-at-specified-time-but-instead-sends-multiple-push – Chandz Jul 27 '15 at 06:11
  • @IshanThilinaSomasiri My doubt is, When cronTrigger() is built in WebConfig.java which contains both _timezone_ & _cron expression_, how can we pass the same _timezone_ & _cron expression_ for @Scheduled(cron = "0 0/60 * * * ?", zone = "Asia/Colombo") in the different class where the method is present which has logic to run based of cron job.? – Chandz Jul 27 '15 at 06:28
  • You can find yours from this list: http://joda-time.sourceforge.net/timezones.html – Bahadir Tasdemir Jun 01 '16 at 12:38
  • I need to run for multiple time zones and I need to do it in a single scheduled job, is that possible? – Sumedh Sep 02 '22 at 07:44
  • 1
    @Sumedh I don't think so. One alternative is to create a single `doWork()` method. Next, add one `@Scheduled` method for each time zone that calls the `doWork()` method. Optionally, the `doWork()` can may also have one or more parameters for further customisation. For some problems another option may be to create a cron expression that triggers on scheduled intervals (e.g. every six hours), but then you don't have control over specific time zones. – matsev Sep 03 '22 at 08:29
25

There is element zone in annotation @Scheduled, starting from version 4.0.

You can insert a timezone as a string that can be accepted by java.util.TimeZone.

Vlasec
  • 5,500
  • 3
  • 27
  • 30
9

Your code should be like this:

@Scheduled(cron = "0 0 14 * * *", zone = "GMT-5")
    public void execute() {
     // do scheduled job
}

"Zone" is gonna be the desired country's timezone.

Here is a nice tutorial about scheduled tasks with Spring:

https://www.baeldung.com/cron-expressions

dmarquina
  • 3,728
  • 1
  • 28
  • 28
2

You can also use time zone with @Scheduled tag in spring-boot like this :

@Scheduled(cron = "0 0 14 * * *" , zone = "GMT+5:00")
public void execute() {
    // do the scheduled job
}
Nasser Ali Karimi
  • 4,462
  • 6
  • 34
  • 77
0

I doubt you want different jobs or parts of application to use different time zones. Assuming you want to have it all consistent and DRY, either configure OS on all servers to have consistent time zone, or set user.timezone Java system property for all of the application servers. Centrally manage configuration (OS, application server), and for that puppet and chef can be very useful.

Stevo Slavić
  • 2,298
  • 2
  • 24
  • 32
  • 1
    Generally, I agree, and our servers are all configured to use the same time zone. Our servers need to interact with a third party server on a regular basis, hence the cron job. The problem is that the external server has a scheduled maintenance window during which we cannot interact with it, and that maintenance window is based on a different time zone than our servers. Of course, we could have configured all our servers to use the same time zone as the third party server, but we rather keep the coupling to external sources as limited as possible. – matsev Apr 14 '13 at 13:52