gpt4 book ai didi

java - 如何处理夏令时时钟回滚导致的时间模糊

转载 作者:行者123 更新时间:2023-11-30 05:36:01 30 4
gpt4 key购买 nike

我有这样的场景,我想看看是否有更好的解决方案:

我从系统 A 收到一个时间戳,格式为“yyyy-MM-dd-HH-mm” -ss”,没有时区,但他们可以将其修复为 UTC。

然后我需要通过 SSH 进入系统 B 以获取“上次同步时间”,该时间可能是过去的时间,并且它不会返回任何时区,甚至不会返回年份(来自备份)产品),下面是一个示例:

“同步时间:11 月 3 日星期日 01:13”

系统 B 是运行的备份设备一些专有软件,并且有一个内部调度程序,每 15 分钟唤醒一次,检查是否有任何数据需要从源同步。如果上一个同步仍在运行,它将让当前同步完成,而不采取进一步操作。此“上次同步时间”将在每次同步后更新,因此在最坏的情况下,它不应落后于当前系统时间超过几个小时。

我需要比较这两个时间戳以确保 B 上的“上次同步时间”晚于 A。如果不是,我需要等待并重试查询,直到 B 晚于 A 才能继续执行下一步。

我有一个位于Linux机器上的java程序,当来自A的请求时,它会查询B的“上次同步时间”,然后立即向B发出“日期”命令获取当前系统时间,返回当前系统时间,格式为“EEE MMM dd kk:mm:ss z yyyy”,例如

“Fri Jun 14 21:07:07 EDT 2019 ",

因此程序可以应用此输出的年份和时区来完成“上次同步时间”的时间戳。该程序确实处理“上次同步时间”和“日期”输出分布在一年边界上的情况。

它工作正常,除了夏季夏令时结束时,时钟回滚(凌晨 2 点回到凌晨 1 点),有一小时的窗口时间会不明确:

例如,我从系统 A 获取凌晨 1:20 的时间戳(已从 UTC 转换为本地时间),然后当我从系统 B 获取凌晨 1:30 的时间戳时,我无法判断 B 是否晚于 A。时钟更改前 1:30。系统B的当前时区,并不能明确“上次同步时间”位于哪个时区。

我们要求用户将所有系统切换为UTC时间,所以我们不需要担心关于时钟调整。但这对环境的影响太大了。

另一种选择是我专门处理这一小时,并等到“上次同步时间”时间戳超过凌晨 2 点。为此,我需要在每次进行时间戳比较时检查代码是否是特定小时,我认为这不是最佳选择。但我想不出更好的办法。

非常感谢任何建议。如果这是要走的路,是否有一个好的 Java 库来计算夏令时切换日期?谢谢一百万!

最佳答案

我认为您无法完全确定。 “11 月 3 日星期日”可能是 2002 年、2013 年或 2019 年,甚至更早的历史。一种方法是,如果您可以假设上次同步时间不比您获得的当前系统 B 系统时间早几年(并且也不晚于该时间),并且如果您发现不在这几年之内,请报告错误。

夏令时(夏令时)结束时的技巧是,如果有任何歧义,始终假定较早的时间。这样,当您检测到同步时间晚于 A 的时间戳时,无论如何解释不明确的同步时间,这都是正确的。它还意味着您将按照您的建议等到最后一次同步时间在凌晨 2 点之后。就比较而言,我不认为这会贵得令人望而却步,但如果您需要确定,您需要做出自己的测量和判断。

    final DateTimeFormatter timestampFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd-HH-mm-ss");
final ZoneId systemBTimeZone = ZoneId.of("America/New_York");
final String syncFormatPattern = "'Sync''ed-as-of time:' EEE MMM d HH:mm";
final DateTimeFormatter currentSystemBTiemFormatter = new DateTimeFormatterBuilder()
.appendPattern("EEE MMM dd HH:mm:ss ")
.appendZoneText(TextStyle.SHORT, Collections.singleton(systemBTimeZone))
.appendPattern(" yyyy")
.toFormatter(Locale.US);
final Period maxSyncAge = Period.ofYears(2);

String systemATimestampString = "2019-11-03-06-05-55";
String lastSyncMsg = "Sync'ed-as-of time: Sun Nov 3 01:13";
String currentSystemBTime = "Sun Nov 03 01:13:07 EDT 2019";
OffsetDateTime systemATimestamp = LocalDateTime.parse(systemATimestampString, timestampFormatter)
.atOffset(ZoneOffset.UTC);
ZonedDateTime maxLastSyncTime
= ZonedDateTime.parse(currentSystemBTime, currentSystemBTiemFormatter);
ZonedDateTime minLatSyncTime = maxLastSyncTime.minus(maxSyncAge);
int candidateYear = maxLastSyncTime.getYear();
ZonedDateTime syncTime;
while (true) {
DateTimeFormatter syncFormatter = new DateTimeFormatterBuilder()
.appendPattern(syncFormatPattern)
.parseDefaulting(ChronoField.YEAR, candidateYear)
.toFormatter(Locale.US);
try {
syncTime = LocalDateTime.parse(lastSyncMsg, syncFormatter)
.atZone(systemBTimeZone)
.withEarlierOffsetAtOverlap();
if (syncTime.isBefore(minLatSyncTime) || syncTime.isAfter(maxLastSyncTime)) {
throw new IllegalStateException("Last sync time is out of range");
}
break;
} catch (DateTimeParseException dtpe) {
// Ignore; try next earlier year
}
candidateYear--;
}
System.out.println("Last sync time: " + syncTime);
System.out.println("Timestamp from system A: " + systemATimestamp);
System.out.println("Is OK? " + syncTime.toOffsetDateTime().isAfter(systemATimestamp));

正如代码片段所示,它的输出是:

Last sync time: 2019-11-03T01:13-04:00[America/New_York]
Timestamp from system A: 2019-11-03T06:05:55Z
Is OK? false

可以看到它选择将上次同步时间01:13解释为夏令时,偏移量为-04:00,这导致检查失败。该时间也可能是标准时间,偏移量为 -05:00,在这种情况下,等效的 UTC 时间为 06:13,并且检查会成功。但正如所讨论的,为了安全起见,我们更愿意等到同步时间在 02:00 之后并再次变得明确。

while 循环不断解析假设不同年份的字符串,直到遇到与星期几匹配的年份。

关于java - 如何处理夏令时时钟回滚导致的时间模糊,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56603752/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com