【问题标题】:Parse ISO_LOCAL_TIME despite inaccuracy of system clock尽管系统时钟不准确,但仍解析 ISO_LOCAL_TIME
【发布时间】:2016-02-25 14:06:44
【问题描述】:

我在解析本地分区时间字符串时遇到问题(例如"12:00:00")。一些远程服务提供带有本地时间字符串的数据。服务的本地时区不时更改。有时服务的时钟不准确(最多几秒钟)。我的时钟也可能没有很好地校准。但我们很清楚,服务器上的数据总是最新的。 这是解释代码

private static ZoneOffset parseOffset(Clock now, String serviceLocal) {
    LocalTime lt = LocalTime.parse(serviceLocal);
    for (long s = HOURS.toSeconds(12); s > -HOURS.toSeconds(12); s -= MINUTES.toSeconds(30)) {
        final ZoneOffset offset = ZoneOffset.ofTotalSeconds((int) s);
        final LocalDate ld = LocalDate.now(now);
        final ZonedDateTime zdt = ZonedDateTime.of(ld, lt, offset);
        final long seconds = zdt.getLong(ChronoField.INSTANT_SECONDS);
        if (seconds > now.instant().minusSeconds(MINUTES.toSeconds(30)).getEpochSecond()
                && seconds <= now.instant().getEpochSecond()) {
            return offset;
        }
    }
    throw new DateTimeException(String.format("Can't determine time zone of \"%s\". Current UTC time is \"%s\".",
            serviceLocal, now.instant()));
}

/**
 * This test passes. Detected offset is "GMT+6:00".
 */
@Test
public void shouldParseOffset_1() {
    // given
    String serviceLocal = "23:59:59";
    Clock systemTime = Clock.fixed(Instant.parse("2016-02-25T18:00:00Z"), ZoneOffset.UTC);
    // when
    ZoneOffset offset = parseOffset(systemTime, serviceLocal);
    // then
    assertThat(offset, equalTo(ZoneOffset.of("+06:00")));
}

/**
 * This test fails. As I said before data is always latest. It is easy to
 * guess that some of systems (dedicated service or local) clock is not well
 * calibrated. So zone offset should be still equal to "GMT+6:00".
 */
@Test
public void shouldParseOffset_2() {
    // given
    String serviceLocal = "00:00:01";
    Clock systemTime = Clock.fixed(Instant.parse("2016-02-25T18:00:00Z"), ZoneOffset.UTC);
    // when
    ZoneOffset offset = parseOffset(systemTime, serviceLocal);
    // then
    assertThat(offset, equalTo(ZoneOffset.of("+06:00")));
} 

让总误差不超过 10 秒。 100%的情况下如何确定服务器数据的准确时间?

【问题讨论】:

  • 所以你有一个来自服务器的本地时间 - 你知道它是准确的 +/- 10 秒,你准确地知道当前时间并基于你想找到服务器 ZoneOffset?
  • @assylias 完全正确。我的parseOffset 方法的主要问题在于极端情况。例如。服务器的LocalDate 可能与当前时间不同。

标签: java datetime timezone java-8 java-time


【解决方案1】:

一种方法是首先调整服务器时间以反映“准确”时间(即向上或向下调整几秒以匹配正确的分钟秒数)。

然后您可以计算您的服务器和本地时间之间的时间差。

它可能看起来像:

public static ZoneOffset parseOffset(Clock now, String serviceLocal) {
  LocalTime serverTime = LocalTime.parse(serviceLocal);
  LocalTime localTime = LocalTime.now(now);

  LocalTime adjustedServerTime = getAccurateServerTime(serverTime, localTime, 10);

  int seconds = getSecondsOffset(localTime, adjustedServerTime);
  return ZoneOffset.ofTotalSeconds(seconds);
}

/**
 *
 * @param actual the time on the server (may be inaccurate by 10 seconds)
 * @param accurate the accurate local time , may be a in a different time zone
 * @param maxSecondsInaccuracy the maximum inaccuracy of the time on the server in seconds
 * @return the server time, adjusted for seconds inaccuracy
 */
private static LocalTime getAccurateServerTime(LocalTime actual, LocalTime accurate, int maxSecondsInaccuracy) {
  int actualSeconds = actual.getSecond();
  int accurateSeconds = accurate.getSecond();
  if (Math.abs(actualSeconds - accurateSeconds) < maxSecondsInaccuracy) {
    return actual.withSecond(accurateSeconds);
  } else { //not in the same minute
    if (actualSeconds < accurateSeconds) {
      return actual.minusMinutes(1).withSecond(accurateSeconds);
    } else {
      return actual.plusMinutes(1).withSecond(accurateSeconds);
    }
  }
}

/**
 * @return the offset between the two times, in seconds, between -12 and +12
 */
private static int getSecondsOffset(LocalTime target, LocalTime serverTime) {
  Duration d = Duration.between(target, serverTime);
  long minutes = d.toMinutes();

  //limit offset to -12/+12
  if (minutes < -12 * 60) minutes = minutes + 24 * 60;
  if (minutes > 12 * 60) minutes = minutes - 24 * 60;
  return (int) (minutes * 60);
}

【讨论】:

    猜你喜欢
    • 2019-03-08
    • 2017-03-25
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-26
    • 2015-08-08
    相关资源
    最近更新 更多