首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何处理夏时制时钟回滚引起的时间模糊

如何处理夏时制时钟回滚引起的时间模糊
EN

Stack Overflow用户
提问于 2019-06-14 18:53:28
回答 2查看 584关注 0票数 2

我想看看是否有更好的解决方案:

我收到了来自系统A的时间戳,格式为“”,没有时区,但他们可以将其修正为UTC。

然后,我需要将SSH放到system中,以获得“最后的同步时间”,它可能是过去的,而且它不返回任何时区,甚至不返回年份(来自备份产品),下面是一个示例:

时间同步:太阳11月3日01:13

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

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

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

“美国东部时间2019年6月14日星期五21:07:07”

因此,程序可以应用年份,以及这个输出的时区来完成“最后一次同步时间”的时间戳。该程序确实处理了“最后一次snync时间”和“日期”输出跨越一年边界的情况。

它工作得很好,除非夏时制结束,时钟回滚(凌晨2点回到凌晨1点),有一个小时的窗口--时间将模糊不清:

例如,我从系统A (从UTC已经转换到本地)得到一个凌晨1:20分的时间图,然后当我从系统B得到凌晨1:30时,我无法判断B是否晚于A,可能是时钟改变之前的1:30。系统B的当前时区没有说明“最后同步时间”位于哪个时区。

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

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

任何建议都是非常感谢的。如果这是要走的路,那么是否有一个好的Java库来计算白天的节能型切换日期呢?多谢百万!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-06-16 18:51:31

我看不出你能完全确定。“太阳11月3日”可能在2002年、2013年或2019年,甚至可以追溯到更早的历史。一种方法是,假设上一次同步时间不超过,比方说,在当前system系统时间之前几年(也不是在该时间之后),并报告一个错误,如果您能够检测到它不在这几年内。

夏令时间(夏令时)结束时的诀窍是,如果有任何不明确之处,总是假设时间提前。这样,当您检测到同步时间晚于来自A的时间戳时,无论如何解释不明确的同步时间,这都是正确的。这也意味着,您将等待直到最后一次同步时间在凌晨2点之后,正如您所建议的。我不认为这在比较上是令人望而却步的,但是如果你需要确定,你需要做你自己的测量和判断。

代码语言:javascript
运行
复制
    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));

作为代码片段,它的输出是:

最后同步时间:2019-11-03T01:13-04:美国/纽约时间戳从系统A: 2019-11-03T06:05:55Z还好吗?错误

您可以看到,它选择将最后一次同步时间01:13解释为日光时,偏移量为-04:00,这将导致检查失败。时间也可能是在标准时间,偏移-05:00,在这种情况下,世界协调委员会的等价物应该是06:13,并且检查会成功。但是,正如前面所讨论的,为了安全起见,我们更愿意等待直到同步时间在02:00之后,并再次变得清晰。

while循环一直在假设不同的年份来解析字符串,直到它到达一天匹配的年份为止。

票数 2
EN

Stack Overflow用户

发布于 2019-06-15 01:27:56

马特·约翰逊的评论中提到了这一点,我认为这是最好的解决方案:

现代的Java代码应该使用java.time包,这是自Java8以来内置的。ZoneRules.getValidOffsets将告诉您在特定时区中申请给定LocalDateTime的偏移量。如果返回多个偏移量,则处于一个不明确的时期。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56603752

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档