【问题标题】:Set linux time to millisecond precision将linux时间设置为毫秒精度
【发布时间】:2012-06-22 22:32:33
【问题描述】:

我有一个嵌入式 Linux 设备,它通过串行通信协议与另一个“主”设备连接。主设备会定期将其日期传递给从设备,因为稍后从设备会将需要准确时间戳的信息返回给主设备。但是,Linux 的“日期”命令只能将系统日期设置为一秒以内。这对我们的使用来说是不够的。

有人知道如何将 Linux 机器的时间设置得比 1 秒更精确吗?

【问题讨论】:

  • 我相信 1 秒的精度是 Linux 的标准。您不能将其设置为更高的精度,因为其他所有内容都会中断(时间以整数形式存储/发送)。我很确定有一些命令或东西可以获取自午夜以来的毫秒数,您可以将其传递给设备,并在您的代码中从它那里接收毫秒数。如果我对 Linux 足够了解,我会在此处将其作为答案发布,但我很确定如果您想要亚秒级精度,您将不得不传递另一个时间值。

标签: linux date system time-precision


【解决方案1】:

其他答案中给出的settimeofday(2) 方法有一个严重的问题:它完全按照您所说的去做。 :)

直接立即更改系统时间的问题在于,如果调整为负值,它会混淆获取更改前后时间的程序。也就是说,他们可以感知时间倒退。

解决此问题的方法是简单且可移植的adjtime(3),或复杂、强大且特定于Linux 的adjtimex(2)。这两个调用都使用复杂的算法在一段时间内缓慢调整系统时间,仅向前调整,直到实现所需的更改。

对了,你确定你不是reinventingwheel 吗?我建议您阅读 Julien Ridoux 和 Darryl Veitch 的 ACM 队列论文 Principles of Robust Timing over the Internet。您正在研究嵌入式系统,所以我预计图 5 中的铃声会让您不寒而栗。你能说“阻尼振荡器”吗? adjtime()adjtimex() 使用这种有问题的算法,所以在某种意义上我反对我自己的上述建议,但 Mills 算法仍然比步进调整非算法更好。如果您选择实施 RADclock,那就更好了。

【讨论】:

  • 您提出了合理的担忧。我在答案中包含的代码 sn-p 来自嵌入式系统,该系统具有从 GPS 接收器获得的纳秒精度。就我而言,它仅在当前系统时间与 GPS 时间相差一秒以上时才执行该代码,即使在启动时也是如此。这在实践中被证明是非常可靠的。
  • ntpdate 和 ntpd 都使用 adjtimex 来调整时间,这是一个合理的逐步做的方法,而不是一次设置。
【解决方案2】:

settimeofday() 系统调用采用微秒精度。您必须编写一个简短的程序才能使用它,但这很简单。

struct timeval tv;
tv .tv_sec = (some time_t value)
tv .tv_usec = (the number of microseconds after the second)
int rc = settimeofday (&tv, NULL);
if (rc)
        errormessage ("error %d setting system time", errno);

【讨论】:

    【解决方案3】:
    • 您可以使用settimeofday(2) 系统调用;接口支持微秒级分辨率。

      #include <sys/time.h>
      
      int gettimeofday(struct timeval *tv, struct timezone *tz);
      int settimeofday(const struct timeval *tv, const struct timezone *tz);
      
         struct timeval {
             time_t      tv_sec;     /* seconds */
             suseconds_t tv_usec;    /* microseconds */
         };
      
    • 你可以使用clock_settime(2)系统调用;接口提供多个时钟,接口支持纳秒级分辨率。

      #include <time.h>
      
      int clock_getres(clockid_t clk_id, struct timespec *res);
      
      int clock_gettime(clockid_t clk_id, struct timespec *tp);
      
      int clock_settime(clockid_t clk_id, const struct timespec
      *tp);
      
         struct timespec {
             time_t   tv_sec;        /* seconds */
             long     tv_nsec;       /* nanoseconds */
         };
      
      
      CLOCK_REALTIME
            System-wide real-time clock.  Setting this clock
            requires appropriate privileges.
      
      CLOCK_MONOTONIC
            Clock that cannot be set and represents monotonic time
            since some unspecified starting point.
      
      CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific)
            Similar to CLOCK_MONOTONIC, but provides access to a
            raw hardware-based time that is not subject to NTP
            adjustments.
      
      CLOCK_PROCESS_CPUTIME_ID
            High-resolution per-process timer from the CPU.
      
      CLOCK_THREAD_CPUTIME_ID
            Thread-specific CPU-time clock.
      

      这个接口提供了clock_getres(2) 调用的精妙之处,它可以准确地告诉你分辨率是多少 -- 仅仅因为接口接受纳秒并不意味着它实际上可以支持 纳秒级分辨率。 (我有一个模糊的记忆,20 ns 大约是许多系统的极限,但没有参考支持这一点。)

    【讨论】:

    • clock_settime 是立即设置还是逐步设置?
    【解决方案4】:

    如果您通过串行链路运行支持 IP 的网络协议(例如,哦,PPP),您可以在“主”主机上运行 ntpd,然后使用 ntpd 或 ntpdate on 同步时间嵌入式设备。 NTP 会照顾你。

    【讨论】:

    • +1 提供唯一不需要编程的答案。 OP 没有提到语言,只提到了命令行工具。也许这个问题应该在 Superuser.com 上?
    猜你喜欢
    • 2017-08-31
    • 2014-03-20
    • 2011-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-23
    • 2014-10-21
    • 2018-10-10
    相关资源
    最近更新 更多