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
и многое другое.