Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ScheduledExecutorService execute every night at 12 AM UTC Time

I want to start ScheduledExecutorService exactly 12 AM daily ,Schedule has to Start at today at 22/02/2017 00:00:00 (UTC TIME),Can any one tell me Whether my code is Correct or not?

DateTime today = new DateTime().withTimeAtStartOfDay(); 
DateTime startOfTommorrow = today.plusDays(1).withTimeAtStartOfDay();

Long midnight = startOfTommorrow.getMillis();
long midnights = (midnight / 1000)  / 60;
final DateFormat nextDateTymFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

System.out.println("***********************************");
System.out.println("Schedule Updater "+nextDateTymFormat.format(new Date()));
System.out.println("today "+today);
System.out.println("startOfTommorrow "+startOfTommorrow);
System.out.println("midnight Long "+midnight);
System.out.println("***********************************");
vitalScheduleThread.scheduleAtFixedRate(new Runnable() {

    @Override
    public void run() {

        System.out.println("Hello vitalSchService !!"+nextDateTymFormat.format(new Date()));

        Thread.currentThread().setName("vitalSchService");

        //sendMail();
        vitalSchedule.process(springContext);
    }
}, midnight , 86400000 , TimeUnit.MILLISECONDS
);
like image 960
kavie Avatar asked Apr 21 '17 07:04

kavie


People also ask

How do you schedule a Java program to run everyday?

Simply pass in the time of day you want to run the task as a Calendar object, and the task as a Runnable . For example: Calendar timeOfDay = Calendar. getInstance(); timeOfDay.

How do I stop scheduled executor service?

To properly shut down an ExecutorService, we have the shutdown() and shutdownNow() APIs. This method returns a list of tasks that are waiting to be processed.

How does scheduled executor service work?

An ExecutorService that can schedule commands to run after a given delay, or to execute periodically. The schedule methods create tasks with various delays and return a task object that can be used to cancel or check execution.

How to schedule task in Java?

One of the methods in the Timer class is the void schedule(Timertask task, Date time) method. This method schedules the specified task for execution at the specified time. If the time is in the past, it schedules the task for immediate execution.


1 Answers

tl;dr

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;  // Capture the current moment.

….scheduleAtFixedRate(
    new Runnable() { … } ,           // Define task to be executed as a `Runnable`.
    Duration.between(                // Determine amount of time for initial delay until first execution of our Runnable.
        now ,                        // Current moment.
        now.toLocalDate().plusDays( 1 ).atStartOfDay( ZoneOffset.UTC )  // Determine the first moment of tomorrow in our target time zone (UTC). Used as the exclusive end of our Half-Open span of time.
    ) ,
    TimeUnit.DAYS.toMillis( 1 ) ,    // Amount of time between subsequent executions of our Runnable. Use self-documenting code rather than a “magic number” such as `86400000`. 
    TimeUnit.MILLISECONDS            // Specify the granularity of time used in previous pair of arguments.
)                                    // Returns a `ScheduledFuture` which you may want to cache.

Details

Specify zone explicitly

You are assuming the JVM’s current time zone is your desired UTC. You omit the optional time zone argument when calling the date-time methods. That omission means the JVM’s current default time zone is applied implicitly and silently at runtime. That default may change at any moment. Any code in any thread of any app within that JVM can change the default during runtime(!).

Instead of relying implicitly on the JVM’s current default time zone, always specify your desired/expected zone explicitly. In your case, we want ZoneOffset.UTC. Instead of assuming/hoping the deployment JVM’s current default is set to UTC, and stays at UTC, specify explicitly using the constant.

You seem to be using the excellent Joda-Time library. That project is now in maintenance mode, with the team advising migration to the java.time classes. Same basic concepts, as Joda-Time inspired java.time.

First get the current moment as seen in UTC.

OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );

Extract a date-only value from that. Add one to get tomorrow’s date.

LocalDate today = now.toLocalDate();
LocalDate tomorrow = today.plusDays( 1 );

The term “midnight” can be ambiguous and confusing. Instead, focus on the concept of “first moment of the day”.

We are aiming for the amount of time to delay until your first execution of your executor service. So we need the span of time between now and the first moment of tomorrow.

And when determining a span of time, use the Half-Open method when the beginning is inclusive while the ending is exclusive. So our span of time starts with now (the current moment) and runs up to, but does not include) the first moment of tomorrow.

Let java.time determine the first moment of the day tomorrow. In UTC the day always starts at 00:00. But not so in some time zones on some dates, where the day might start at a time like 01:00. So, as a habit, always let java.time determine first moment of the day. OffsetDateTime tomorrowStart = OffsetDateTime.of( tomorrow , LocalTime.MIN , ZoneOffset.UTC );

Calculate the elapsed time between now and that first moment of tomorrow. The Duration class represents such spans of time unattached to the timeline.

Duration d = Duration.between( now ,  tomorrowStart );
long millisUntilTomorrowStart = d.toMillis();

Instead of a mysterious number literal such as 86400000, use a self-documenting call.

TimeUnit.DAYS.toMillis( 1 )

So your ScheduledExecutorService call would look like this:

….scheduleAtFixedRate(
    new Runnable() { … } ,          // Task to be executed repeatedly, defined as a Runnable.
    millisUntilTomorrowStart ,      // Initial delay, before first execution. Use this to get close to first moment of tomorrow in UTC per our code above.
    TimeUnit.DAYS.toMillis( 1 ) ,   // Amount of time in each interval, between subsequent executions of our Runnable.
    TimeUnit.MILLISECONDS           // Unit of time intended by the numbers in previous two arguments.
)

For incrementing in whole days, you needn't use such a fine granularity as milliseconds. The executors do not run with perfect timing for various reasons. So I probably would have calculated in minutes. But not important.

Very important: You need to enclose the code of your Runnable’s run method in a trap for any exception. If an Exception of any type were to reach the executor, the executor silently halts. No further scheduling of tasks, and no warning. Search Stack Overflow for more info including an Answer by me.

You do not explain what is the object on which you call scheduleAtFixedRate. So that is a major part of the code that we cannot help with until you post more info. I'm concerned you have it named “Thread”. That object must be an implementation of ScheduledExecutorService, not a thread.

Tip: Avoid running things at exactly midnight. Many things tend to happen on computers at midnight. For example, leap second adjustments, many Unix cleanup utilities, and routine activities such as backups that may have been scheduled by naïve administrators. Waiting something like five or fifteen minutes may avoid hassles and mysterious problems.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

  • Java SE 8, Java SE 9, and later
    • Built-in.
    • Part of the standard Java API with a bundled implementation.
    • Java 9 adds some minor features and fixes.
  • Java SE 6 and Java SE 7
    • Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
  • Android
    • Later versions of Android bundle implementations of the java.time classes.
    • For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

like image 97
Basil Bourque Avatar answered Oct 16 '22 10:10

Basil Bourque