音悦Tai疑似倒闭:如何获得当前的TAI时间(tai time now)

如何使用 Java 或 C ++ 在 Linux 中以毫秒为单位获取当前的 TAI 时间?

我需要这个的原因是能够在很长一段时间内(大约几年)准确地获取时间戳,并且仍然能够比较它们,而不必担心闰秒。可以在闰秒内进行多次测量,并且所有测量都需要明确,单调增加和线性增加。这将是一个专用的 Linux 服务器。这是一个科学项目,需要大约 0.5 秒的精度。

我目前不希望投资 GPS 计时员,并希望使用 NTP 来 pool.ntp.org,以保持系统时钟正常。

我已经研究了以下解决方案:

Java 8 或 ThreeTen 项目获得 TAIInstant 的唯一方法是使用 Instant,然后将其转换,根据规范,“根据 UTC-SLS,从 Instant 进行转换不会在闰秒附近完全准确。”这本身并不是什么大不了的事情(实际上,使用 UTC-SLS 似乎仍然可以接受 Insteme 包装器)。但是,在

使用 JSR-310 API 实现 Java 时间尺度不需要提供任何亚秒级精确的时钟,或者单调或平滑地进行。因此,实现不需要实际执行 UTC-SLS 转换或以其他方式知道闰秒。

使用右 /?timezone这似乎总是可行的,但是我不确定实现是否足够智能以在闰秒内继续工作,或者 System.currentTimeMillis()甚至会给 TAI 时间。换句话说,底层实现是否仍然使用 UTC,从而在闰秒期间给出一个不明确的时间,然后将其转换为 TAI,或者使用右 / timeusing Systemillzone

使用 CLOCK_TAI我尝试在 Linux 内核中使用 CLOCK_TAI,但发现它与我的测试中的 CLOCK_REALTIME 完全相同:代码:

#include <iostream>
#include <time.h>
long sec(int clock)
{
    struct timespec gettime_now;
    clock_gettime(clock, &gettime_now);
    return gettime_now.tv_sec;
}
int main()
{
    std::cout << sec(0) << std::endl;       // CLOCK_REALTIME
    std::cout << sec(1) << std::endl;       // CLOCK_MONOTONIC
    std::cout << sec(11) << std::endl;      // CLOCK_TAI
    return 0;
}

输出很简单:

1427744797
6896
1427744797

使用 CLOCK_MONOTONIC这样做的问题是,即使计算机重新启动,时间戳也需要保持有效和可比。

4

CLOCK_REALTIMECLOCK_TAI返回相同的值,因为内核参数tai_offset为零。

通过使用adjtimex(timex tmx)检查并读取该值。我认为ntpd会设置它,如果它足够新 (>4.2.6) 并且有一个闰秒文件。它也可能能够从上游服务器获取它,但我无法验证。调用adjtimex()可以在以 root 身份运行时手动设置tai_offset页面。

3

除了正确的接受答案,我还提到免费的Java 库 Time4Jmin version v4.1)作为可能的解决方案,因为

我写它来填补 Java 世界的空白(java.time不能做所有),

到目前为止给出的其他答案只谈论 C ++(但你也要求 Java),

它根据 @ user3427419 描述的相同原理工作。

它使用基于System.nanoTime()的单调时钟,但甚至允许通过接口TickProvider自定义实现。为了校准的目的,您可以使用net.time4j.SystemClock.MONOTONIC,也可以使用名为SntpConnector的 SNTP-clock,它只需要一些简单的配置即可连接到您想要的任何 NTP-time-server。由于内置的 timesec-n-second

时钟的重新校准(在 NTP-重新连接的情况下)是可能的,这意味着时钟可以适应中间时间调整(尽管我强烈建议不要在测量期间或在闰秒期间进行)。尽管在某些情况下,SNTP 时钟的这种重新连接通常会导致时间后退,Time4J 尝试应用平滑算法(如果在时钟配置中激活)以确保单调行为。详细文档可用 Example:

// Step 0: configure your clock
String ntpServer = "ptbtime1.ptb.de";
SntpConnector clock = new SntpConnector(ntpServer);
// Step 1: Timestamp start of the program and associate it with a counter
clock.connect(); 
// Step 2: Use the counter for sequential measurements at fixed intervals
Moment m = clock.currentTime();
System.out.println(m); // possible output = 2015-06-30T23:59:60,123456789Z
// Step 3: Timestamp new counter value(s) as necessary to keep your data adequately synced
clock.connect();

我怀疑任何基于 C ++ 的解决方案是否更简单。更多的代码演示也可以在DZone上学习。

更新(注释中问题的答案):

一个稍微简化的解决方案如何自动下载给定的 IETF 资源为新的闰秒,并将其转换为 Time4J 特定的格式可能看起来像这样:

URL url = new URL("https://www.ietf.org/timezones/data/leap-seconds.list");
BufferedReader br =
    new BufferedReader(
        new InputStreamReader(url.openStream(), "US-ASCII"));
String line;
PlainDate expires = null;
Moment ntpEpoch = PlainTimestamp.of(1900, 1, 1, 0, 0).atUTC();
List<PlainDate> events = new ArrayList<PlainDate>();
try {
    while ((line = br.readLine()) != null) {
        if (line.startsWith("#@")) {
            long expraw = Long.pLong(line.substring(2).trim());
            expires = ntpEpoch.plus(
              expraw, TimeUnit.SECONDS)
            .toZonalTimestamp(ZonalOffset.UTC).toDate();
            continue;
        } else if (line.startsWith("#")) {
            continue; // comment line
        }
        // this works for some foreseeable future
        long epoch = Long.pLong(line.substring(0, 10)); 
        // this is no leap second 
        // but just the official introduction of modern UTC scale
        if (epoch == 2272060800L) {
            continue;
        }
        // -1 because we don't want to associate 
        // the leap second with the following day
        PlainDate event = 
          ntpEpoch.plus(epoch - 1, TimeUnit.SECONDS)
                  .toZonalTimestamp(ZonalOffset.UTC).toDate();
        events.add(event); // we don't assume any negative leap seconds here for simplicity
    }
} finally {
    br.close();
}
// now let's write the result into time4j-format
// use a location relative to class path of main program (see below)
String path = "C:/work/leapseconds.txt"; 
Writer writer = new FileWriter(new File(path));
String sep = System.getProperty("line.separator");
try {
    for (PlainDate event : events) {
        writer.write(event + ", +" + sep);
    }
    writer.write("@expires=" + expires + sep);
} finally {
    writer.close();
}
System.out.println(
  "Leap second file was successfully written from IETF-resource.");
// And finally, we can start the main program in a separate process
// with the system property "net.time4j.scale.leapseconds.path"
// set to our leapsecond file path (must be relative to class path)
Some notes:

如果设置此property,那么将从指定的文件中读取闰秒,任何最终可用的 tzdata-module 将停止以产生任何并发闰秒信息。

3

我需要这样做的原因是能够在很长一段时间内(大约几年)准确地获取时间戳,并且仍然能够比较它们,而不必担心闰秒。可以在闰秒内进行多次测量,并且所有测量都需要明确,单调增加和线性增加。

那么你的设计是次优的。你不能使用时间,然后以某种方式干涉闰秒。这实际上经常出现,人们陷入了使用挂钟进行时间戳测量的相同陷阱。

程序的时间戳启动并将其与计数器关联

使用计数器以固定间隔进行顺序测量

必要的时间戳新计数器值,以保持数据充分同步

如果你避免了 1 秒的时间戳,可以发生跳跃秒(午夜!),你是免费的,因为这些可以稍后调整。

现在如果你坚持使用没有计数器的 TAI,你所需要的只是一个需要计算闰秒的表。然后只需使用单调时间。还有一些库可以为你做到这一点,但是它们可能已经过时了,所以你必须自己维护它们,

http://skarnet.org/software/skalibs/libstddjb/tai.html
0

您必须实现基于 C ++ std::steady_clock 或类似的 TAI 时钟。要同步您的 TAI 时钟,您可以依靠 GPS 或 NTP。

NTP 的选项 TAI:您的 TAI 实现需要有关闰秒的知识。NTP 协议或referenced resources可能是当前和未来闰秒的最可靠来源。

来自 GPS 的选项 TAI:GPS 时钟与 TAI 有固定的偏移量,您不必弄乱闰秒

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(825)
Remain:显示内联块在 matterial步进器头中不保持对齐
上一篇
阴阳师ios可以转安卓:安卓频率振动(pixel 6 vibration intensity)
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(19条)