ScheduledExecutorService выполняется каждую ночь в 12:00 UTC времени

Я хочу запускать ScheduledExecutorService ровно в 12:00 ежедневно, Расписание должно начинаться сегодня, 22.02.2017, 00:00:00 (UTC TIME). Может кто-нибудь сказать мне, правильный ли мой код или нет?

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

);

1 ответ

Решение

ТЛ; др

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.

подробности

Укажите зону явно

Вы предполагаете, что текущий часовой пояс JVM - это ваш желаемый UTC. Вы опускаете необязательный аргумент часового пояса при вызове методов даты и времени. Это упущение означает, что текущий часовой пояс JVM по умолчанию применяется неявно и незаметно во время выполнения. Это значение по умолчанию может измениться в любой момент. Любой код в любом потоке любого приложения в этой JVM может изменить значение по умолчанию во время выполнения (!).

Вместо того, чтобы неявно полагаться на текущий часовой пояс JVM по умолчанию, всегда явно указывайте желаемую / ожидаемую зону. В вашем случае мы хотим ZoneOffset.UTC, Вместо того, чтобы предполагать / надеяться, что текущее значение по умолчанию для развертывания JVM установлено в UTC и остается в UTC, укажите явно, используя константу.

Вы, кажется, используете отличную библиотеку Joda-Time. Этот проект сейчас находится в режиме сопровождения, и команда советует перейти на классы java.time. Те же базовые концепции, что и Joda-Time, вдохновили java.time.

Сначала получите текущий момент, как показано в UTC.

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

Из этого извлекается значение только для даты. Добавьте один, чтобы получить завтрашнюю дату.

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

Термин "полночь" может быть неоднозначным и запутанным. Вместо этого сосредоточьтесь на понятии "первый момент дня".

Мы стремимся к тому, чтобы отсрочить время до вашего первого исполнения услуг вашего исполнителя. Поэтому нам нужен промежуток времени между настоящим моментом и первым моментом завтрашнего дня.

А при определении промежутка времени используйте метод Half-Open, когда начало включительно, а окончание - исключительно. Таким образом, наш промежуток времени начинается с настоящего момента (текущего момента) и продолжается, но не включает) первого момента завтрашнего дня.

Пусть java.time определит первый момент дня завтра. В UTC день всегда начинается в 00:00. Но не так в некоторых часовых поясах в некоторые даты, когда день может начаться в такое время, как 01:00. Так что, как всегда, пусть java.time определяет первый момент дня. OffsetDateTime morningStart = OffsetDateTime.of(завтра, LocalTime.MIN, ZoneOffset.UTC);

Рассчитайте прошедшее время между настоящим моментом и первым моментом завтрашнего дня. Duration класс представляет такие промежутки времени, не привязанные к временной шкале.

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

Вместо загадочного числа, такого как 86400000, используйте самодокументируемый вызов.

TimeUnit.DAYS.toMillis( 1 )

Так что ваши ScheduledExecutorService вызов будет выглядеть так:

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

Для приращения в целые дни вам не нужно использовать такую ​​тонкую гранулярность, как миллисекунды. Исполнители не работают с идеальным временем по разным причинам. Так что я бы наверное посчитал за минуты. Но не важно.

Очень важно: вам нужно приложить код вашего Runnable's run метод в ловушке для любого исключения. Если исключение любого типа достигнет исполнителя, исполнитель молча останавливается. Никакого дальнейшего планирования задач и предупреждения. Поиск переполнения стека для получения дополнительной информации, включая ответ от меня.

Вы не объясните, что это за объект, на который вы звоните scheduleAtFixedRate, Так что это основная часть кода, с которой мы не можем помочь, пока вы не отправите больше информации. Я обеспокоен тем, что у вас это называется "Нить". Этот объект должен быть реализацией ScheduledExecutorService не нить.

Совет: избегайте запуска вещей ровно в полночь. Многие вещи, как правило, происходят на компьютерах в полночь. Например, дополнительные настройки, многие утилиты очистки Unix и рутинные действия, такие как резервное копирование, которые могли быть запланированы наивными администраторами. Ожидание около пяти или пятнадцати минут может избежать неприятностей и таинственных проблем.


О java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date, Calendar & SimpleDateFormat,

Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.

Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, соответствующий JDBC 4.2 или более поздней версии. Нет необходимости в строках, нет необходимости в java.sql.* классы.

Где взять классы java.time?

  • Java SE 8, Java SE 9 и более поздние
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android
    • Более поздние версии Android связывают реализации классов java.time.
    • Для более ранних версий Android (<26) проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше). Смотрите Как использовать ThreeTenABP….

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval, YearWeek, YearQuarter и многое другое.

Другие вопросы по тегам