ScheduledExecutorService runs every night at 12:00 UTC

I want to run the ScheduledExecutorService exactly 12 hours a day, the schedule should start today at 02/22/2017 00:00:00 (UTC TIME), can anyone tell me if 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

      

);

+4


source to share


1 answer


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.

      

More details

Specify zone explicitly

You are assuming the JVMs current timezone is your desired UTC . When calling methods with a date, you omit the optional timezone argument. This omission means that the current time zone of the JVMs is applied implicitly and silently at runtime. This default can change at any time. Any code in any thread of any application within this JVM can change the default value at runtime (!).

Instead of implicitly referring to the current JVM default timezone, always specify the desired / expected zone explicitly . In your case, we want ZoneOffset.UTC

. Instead of assuming / hoping that the current default for the deployment JVM is set to UTC and remains in UTC, specify explicitly with a constant .

You seem to be using the excellent Joda-Time library . This project is now in maintenance mode and the team advises moving to the java.time classes. The same basic concepts as Joda-Time have inspired java.time.

First get the current moment as shown in UTC .

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

      

Extract a date-only value from this. Add one to get the date tomorrow.

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

      

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

We strive to keep the delay time delayed until the first execution of your executor service. Therefore, we need a period of time between the present and the first moment tomorrow.

And when defining the time span, use the Half-Open method when the start is on while the end is exclusive. Thus, our time span starts from the present (current moment) and reaches, but does not include) the first moment tomorrow.

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

Calculate the elapsed time between now and this first moment tomorrow. The class Duration

represents such time intervals that are not tied to the timeline.

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

      



Instead of a mysterious numeric literal such as 86400000

, use a self-signed call.

TimeUnit.DAYS.toMillis( 1 )

      

So your call ScheduledExecutorService

will 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.
)

      

You don't need to use granularity as fine as milliseconds to zoom in for whole days. Performers don't work with great timing for various reasons. So I would probably calculate in minutes. But it doesn't matter.

Very important: . You must run

trap your Runnables method code for any exception. If an exception of any type is executed for the executor, the executor silently stops. No additional task schedules and no alerts. Search for more information including an answer from me.

You do not explain what the object you are referring to is scheduleAtFixedRate

. So this is most of the code that we cannot help with until you post more information. I am concerned that you have the name "Thread". This object must be an implementation ScheduledExecutorService

, not a thread.

Council. Avoid running things exactly at midnight. Many things tend to happen on computers at midnight. For example, a jump in second adjustments, many Unix cleanup utilities, and common activities such as backups that can be scheduled by naive administrators. Waiting for something like five or fifteen minutes can get you out of trouble and cryptic problems.


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the nasty old legacy time classes such as java.util.Date

, Calendar

and . SimpleDateFormat

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

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

You can exchange java.time objects directly with your database. Use a JDBC driver conforming to JDBC 4.2 or newer, No need for strings, no need for classes java.sql.*

.

Where can I get the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is proof of possible future additions to java.time. Here you can find useful classes, such as Interval

, YearWeek

, YearQuarter

and longer .

+2


source







All Articles