ScheduledExecutorService 每晚在 UTC 时间凌晨 12 点执行

kav*_*vie 5 java datetime runnable scheduledexecutorservice

我想在每天凌晨 12 点准时启动 ScheduledExecutorService ,Schedule 必须在今天 22/02/2017 00:00:00(UTC 时间)开始,谁能告诉我我的代码是否正确?

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
);
Run Code Online (Sandbox Code Playgroud)

Bas*_*que 6

太长了;博士

\n\n
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC ) ;  // Capture the current moment.\n\n\xe2\x80\xa6.scheduleAtFixedRate(\n    new Runnable() { \xe2\x80\xa6 } ,           // Define task to be executed as a `Runnable`.\n    Duration.between(                // Determine amount of time for initial delay until first execution of our Runnable.\n        now ,                        // Current moment.\n        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.\n    ) ,\n    TimeUnit.DAYS.toMillis( 1 ) ,    // Amount of time between subsequent executions of our Runnable. Use self-documenting code rather than a \xe2\x80\x9cmagic number\xe2\x80\x9d such as `86400000`. \n    TimeUnit.MILLISECONDS            // Specify the granularity of time used in previous pair of arguments.\n)                                    // Returns a `ScheduledFuture` which you may want to cache.\n
Run Code Online (Sandbox Code Playgroud)\n\n

细节

\n\n

明确指定区域

\n\n

您假设 JVM\xe2\x80\x99s 当前时区是您所需的UTC。调用日期时间方法时,可以省略可选的时区参数。该省略意味着 JVM\xe2\x80\x99s 当前默认时区在运行时隐式且静默地应用。该默认值可能随时更改。该 JVM 内任何应用程序的任何线程中的任何代码都可以在运行时更改默认值(!)。

\n\n

不要隐式依赖 JVM\xe2\x80\x99s 当前默认时区,而应始终显式指定您所需/预期的时区。就您而言,我们想要ZoneOffset.UTC. 不要假设/希望部署 JVM\xe2\x80\x99s 当前默认值设置为 UTC,并保持在 UTC,而是使用常量 显式指定

\n\n

您似乎正在使用优秀的Joda-Time库。该项目现在处于维护模式,团队建议迁移到 java.time 类。基本概念相同,就像Joda-Time启发了java.time一样。

\n\n

首先获取UTC中看到的当前时刻。

\n\n
OffsetDateTime now = OffsetDateTime.now( ZoneOffset.UTC );\n
Run Code Online (Sandbox Code Playgroud)\n\n

从中提取仅日期值。加一即可得到明天\xe2\x80\x99s 的日期。

\n\n
LocalDate today = now.toLocalDate();\nLocalDate tomorrow = today.plusDays( 1 );\n
Run Code Online (Sandbox Code Playgroud)\n\n

术语 \xe2\x80\x9cmidnight\xe2\x80\x9d 可能含糊不清且令人困惑。相反,请关注\xe2\x80\x9c一天中的第一个时刻\xe2\x80\x9d的概念。

\n\n

我们的目标是在您首次执行执行人服务之前延迟一段时间。所以我们需要从现在到明天第一时刻之间的时间跨度。

\n\n

在确定时间跨度时,当开始包含在内而结束为排除时,请使用半开方法。因此,我们的时间跨度从现在(当前时刻)开始,一直到(但不包括)明天的第一时刻。

\n\n

让 java.time 确定明天一天的第一个时刻。在 UTC 中,一天始终从 00:00 开始。但在某些时区的某些日期,情况并非如此,一天可能从 01:00 等时间开始。因此,作为一种习惯,始终让 java.time 确定一天中的第一个时刻。\n OffsetDateTime TomorrowStart = OffsetDateTime.of( 明天 , LocalTime.MIN , ZoneOffset.UTC );

\n\n

计算从现在到明天的第一时刻之间经过的时间。该类Duration表示与时间线无关的时间跨度。

\n\n
Duration d = Duration.between( now ,  tomorrowStart );\nlong millisUntilTomorrowStart = d.toMillis();\n
Run Code Online (Sandbox Code Playgroud)\n\n

不要使用诸如 之类的神秘数字文字86400000,而是使用自记录调用。

\n\n
TimeUnit.DAYS.toMillis( 1 )\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以你的ScheduledExecutorService电话看起来像这样:

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

对于整天的增量,您不需要使用像毫秒这样的精细粒度。由于各种原因,执行者并没有在完​​美的时机运行。所以我可能会在几分钟内计算出来。但并不重要。

\n\n

非常重要:您需要将 Runnable\xe2\x80\x99s 方法的代码包含run在陷阱中以防止任何异常。如果任何类型的异常到达执行器,则执行器会默默地停止。没有进一步的任务安排,也没有警告。搜索 Stack Overflow 以获取更多信息,包括我的答案。

\n\n

您没有解释您调用的对象是什么scheduleAtFixedRate。因此,这是代码的主要部分,在您发布更多信息之前我们无法提供帮助。我担心您将其命名为 \xe2\x80\x9cThread\xe2\x80\x9d。该对象必须是 的实现ScheduledExecutorService,而不是线程。

\n\n

提示:避免在午夜运行。很多事情往往会在午夜时分在电脑上发生。例如,闰秒调整、许多 Unix 清理实用程序以及可能由 na\xc3\xafve 管理员安排的备份等日常活动。等待五到十五分钟可能会避免麻烦和神秘的问题。

\n\n
\n\n

关于java.time

\n\n

java.time框架内置于 Java 8 及更高版本中这些类取代了麻烦的旧遗留日期时间类,例如java.util.Date, Calendar, & SimpleDateFormat

\n\n

Joda -Time项目现在处于维护模式,建议迁移到java.time类。

\n\n

要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规格为JSR 310

\n\n

您可以直接与数据库交换java.time对象。使用与JDBC 4.2或更高版本兼容的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*

\n\n

从哪里获取 java.time 类?

\n\n\n\n

ThreeTen -Extra项目通过附加类扩展了 java.time。该项目是 java.time 未来可能添加的内容的试验场。您可能会在这里找到一些有用的类,例如Interval、、、等等。YearWeekYearQuarter

\n