首页 > 解决方案 > 如何在不同时区的某个时间执行作业

问题描述

假设我在 BST 即英国夏令时,并且我想按照美国/东部时区在 19.30 执行工作,那么我怎么能实现它。

我试过的示例代码,

Instant now = Instant.now();
LocalDateTime localTimeNow = LocalDateTime.ofInstant(now, ZoneOffset.systemDefault());
//if BST then use "Europe/London" 
//if US/Eastern then use "America/New_York" 
// For EST also use "America/New_York"
// If GB-Eire then use "Europe/London"
ZonedDateTime bsTime = now.atZone(ZoneId.of("Europe/London"));

ZonedDateTime nyAmerica = now.atZone(ZoneId.of("America/New_York"));

// Lets calculate the difference between 2 timezones
// Between London and EST
long timeDiff = ChronoUnit.MILLIS.between(bsTime, nyAmerica);
System.out.println("timeDiff - " + timeDiff);

int minutes = (int) ((timeDiff / 1000) / 60);

System.out.println("Time diff bet London and EST - " + minutes + " minutes");

long diff = Duration.between(bsTime, nyAmerica).getSeconds();
int mins = (int) (diff / 60);
System.out.println("Time diff bet London and EST - " + mins + " minutes");

在这两种情况下它都给我零。

我想要的是我必须使用这个延迟将它传递给执行器服务,如下所示,

executor.schedule(myRunnable, delay, TimeUnit.SECONDS);

因此,即使我在英国,根据美国/东部时间,这项工作应该在 19.30 执行。

此外,EST、BST 等一些缩写也不是有效的 ZoneId。那么,当我有 EST 或 BST 等缩写格式的时区时,我该如何处理这些情况?

标签: javascheduled-tasks

解决方案


更新:下面的原始答案显示了如何计算本地时间以启动必须在不同时区的特定时间运行的作业。

如果您只是想计算要等到那个时间,它可以更容易地完成,而不涉及本地时区。

LocalTime jobStartTime = LocalTime.of(19, 30);
ZoneId jobZone = ZoneId.of("America/New_York");

ZonedDateTime now = ZonedDateTime.now(jobZone);
ZonedDateTime jobDateTime = now.with(jobStartTime);
if (jobDateTime.isBefore(now))
    jobDateTime.plusDays(1);
long delay = ChronoUnit.MILLIS.between(now, jobDateTime);

System.out.println("now         = " + now);
System.out.println("jobDateTime = " + jobDateTime);
System.out.println("delay       = " + delay + "  =  " + Duration.ofMillis(delay));

输出

now         = 2020-07-17T08:18:45.482028800-04:00[America/New_York]
jobDateTime = 2020-07-17T19:30-04:00[America/New_York]
delay       = 40274517  =  PT11H11M14.517S

原始答案

now2020-07-17 07:57:45 Z
在伦敦那是2020-07-17 08:57:45 +01:00
在纽约那是2020-07-17 03:57:45 -04:00

伦敦和纽约的时差是多少?
0秒,因为它们是同一时间

问题中的代码没有计算时间是 19:30。相反,它会尝试计算现在的时区差异,但由于夏令时,晚上 7:30 的时区差异可能会有所不同,因此该方法是错误的。

如果您在伦敦,并且需要知道下一次纽约的时间是 19:30,请执行以下操作:

Instant now = Instant.now();
ZoneId localZone = ZoneId.of("Europe/London");
ZoneId remoteZone = ZoneId.of("America/New_York");
System.out.println("now             = " + now);

ZonedDateTime remoteNow = now.atZone(remoteZone);
LocalDate remoteDate = remoteNow.toLocalDate();
LocalTime remoteTime = LocalTime.of(19, 30);
if (remoteNow.toLocalTime().isAfter(remoteTime))
    remoteDate = remoteDate.plusDays(1);
ZonedDateTime remoteStartTime = ZonedDateTime.of(remoteDate, remoteTime, remoteZone);
System.out.println("remoteNow       = " + remoteNow);
System.out.println("remoteStartTime = " + remoteStartTime);

ZonedDateTime localStartTime = remoteStartTime.withZoneSameInstant(localZone);
System.out.println("localNow        = " + now.atZone(localZone));
System.out.println("localStartTime  = " + localStartTime);

输出

now             = 2020-07-17T07:57:45.206007800Z
remoteNow       = 2020-07-17T03:57:45.206007800-04:00[America/New_York]
remoteStartTime = 2020-07-17T19:30-04:00[America/New_York]
localNow        = 2020-07-17T08:57:45.206007800+01:00[Europe/London]
localStartTime  = 2020-07-18T00:30+01:00[Europe/London]

因此,在运行英国时区的计算机上,美国东部的下一个晚上 7:30 时间是今晚午夜半点。


推荐阅读