将人类时间与计算机时间结合为综合时间

时间:2014-05-31 17:02:48

标签: java datetime time

我正在尝试将Java 8中的高数据速率UDP流接口模拟器/测试器写入具有非常精确的时间处理器卡的实时机器。每条消息都有一个时间字段,该字段的分辨率为微秒。该接口依赖于高分辨率时间处理器进行数据包排序。界面依赖于我没有的高精度时间卡,需要模拟等式。我想我可以使用这样的东西逃脱:

TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());

它确实可以工作但是在长时间运行后我发现UDP会咬我,因为我发送了几百个无序的数据包并且具有相同的时间戳,而接口的另一端无法告诉我收到的数据包无序。接口在某种程度上容忍了这一点,但这对于具有高精度时钟的真实系统来说并不是真正的问题。

为了缓解这种情况,我在currentTimeMillis()中添加了一个合成微秒感,如下所示:

class TimeFactory {
  private long prev;
  private long incr;

  public long now() {
    final long now = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis());
    long synthNow = now;
    if(now == prev) {
      if(incr < 999) {
        incr += 1;
      }

      synthNow += incr;
    } else {
      incr = 0;
    }

    prev = now;
    return synthNow;
  }
}

有没有人像这样处理合成时间?有没有其他方法来收紧这个代码甚至更好的方法来处理这个(使用nanoTime以某种方式)?如果我发送了超过999个数据包,那么增加到毫秒范围是安全的(即:增量+ 1000或更多)?看起来我在currentTimeMillis()调用之间的差异大约是10-15ms,但我确定这是非常依赖于系统的。

3 个答案:

答案 0 :(得分:2)

如果有人对此感兴趣,我最终会解决缺乏高分辨率系统时钟的问题。它会给我一个合成的微秒计数器,它会递增,直到System.currentTimeMillis()返回一个更新的值,或者你调用了999次。在实践中,我只看到最多约500个增量。看起来我不会担心溢出到毫秒范围内。

我仍然愿意接受其他更实际的结果选择。

public class SyntheticMicrosClock extends Clock {
    private final ZoneId zone;
    private long prev;
    private long incr;

    SyntheticMicrosClock (ZoneId zone) {
        this.zone = zone;
    }
    @Override
    public ZoneId getZone() {
        return zone;
    }
    @Override
    public Clock withZone(ZoneId zone) {
        if (zone.equals(this.zone)) {  // intentional NPE
            return this;
        }
        return new SyntheticMicrosClock(zone);
    }
    public long micros() {
      final long now = TimeUnit.MILLISECONDS.toMicros(millis());
      long synthNow = now;
      if(now == prev) {
        if(incr < 999) {
          incr += 1;
        }

        synthNow += incr;
      } else {
        incr = 0;
      }

      prev = now;
      return synthNow;
    }
    @Override
    public long millis() {
        return System.currentTimeMillis();
    }
    @Override
    public Instant instant() {
        return Instant.ofEpochSecond(0, micros());
    }
}

要使用它,我将合成时钟注入我需要的地方。例如:

Clock synthClock = Inject or new SynthClock(ZoneOffset.UTC);
Instant.now(synthClock);

答案 1 :(得分:1)

您需要时间戳还是只需要基于时间的高分辨率增加数字?如果是这样,您可以使用System.nanoTime

早期的JVM&OS&#39;这个电话有问题。但似乎已经解决了(见第一个答案here)。

当然,它有可能在你身上徘徊。不知道你的协议有什么样的灵活性,但应该有办法解决这个问题。

答案 2 :(得分:1)

基于@Bill所建议的,你有200年以上的nanoTime分辨率,所以为什么不在init上存储nanoTime,在init上存储cu​​rrentTimeMillis,然后将nanoTime和initNanoTime的差异添加到initCurrentTimeMillis以获得增强的,高精度的时间戳?一旦你在100ms左右的时间内检测到这个增强时钟和真实时钟之间的时钟偏差,你就可以重新启动。