Go 标准库 time 包简介

最近打算开始对 Go 语言标准库的每个包和每个方法进行讲解和添加一些使用实例。

这个想法也是由来很久了,但一直没有行动起来,今天,就把它捡起来吧。

Go 语言标准库的 time 包提供了 测量显示 时间的功能,外加一个定时器

而且呢,time 包里的所有函数都有一个前提假设:日历计算总是假设一个公历 ( 格里高利历 ),没有闰秒

格里高利历

对的,你没看错,是 「 格里高利历 」,而不是格里高日历。格里高利历是公历的标准名称,教皇格里高利十三世于 1582 年颁布。而公元即 「 公历纪元 」,又称 「 西元 」,而我国也在开国大典前几天,也就是 1949 年 9 月 27 日确定使用公历 ( 不然没法确定开国时间 )

格里高利历的最大特点,就是历年平均长度为 365 日 5 时 49 分 12 秒,比回归年长 26 秒,没隔 3000 年左右仍存在1天的误差

闰秒

「 闰秒 」 就是 1 分钟有 61 秒, 「 跳秒 」 都安排在 6 月 30 日,或是 12 月 31 日的最后一瞬间。

总所周知,1 分钟只有 60 秒,那为什么会多出 1 秒呢 ?

因为地球的自转转速并不是均匀的,有时快有时慢。所以呢,为了配合这种时慢时快的自转。每当地球自转变化引起的时间误差积累到与原子钟相关接近 1 秒时,就要人为地把时钟增加或减少 1 秒,从而使两者重新协调一致。这增加或减少的1秒称为 「 跳秒 」。若是增加的,就是 「 正跳秒 」( 拨慢 1 秒);若是减少的就是 「 负跳秒 」( 拨快 1 秒 )

Go 语言 time 包的两种时钟

其实,Linux 世界里有四种时钟 ( clock )

CLOCK_REALTIME
CLOCK_MONOTONIC
CLOCK_MONOTONIC_RAW
CLOCK_BOOTTIME
  1. CLOCK_REALTIME,就是非常出名的 「 wall time 」,即是实际的时间。

    其实就是我们经常看到的,20xx 年 xx 月 xx 日 xx 时 xx 分 xx.xx 秒,只不过保存的时候使用的是时间戳格式

    wall time,挂钟,很古老很古老的欧洲时代,家家户户都有一个挂钟,用来看时间的,其实,就相当于现在大家在用的手表

    CLOCK_REALTIME 时间是可以设置的,用户可以使用命令 date 或是系统调用去修改。

    如果使用了 NTP, 也会被 NTP 修改。

    当系统休眠 ( suspend ) 时,仍然会运行的 ( 原理就是,系统恢复时,kernel 去作补偿 )

  2. CLOCK_MONTONIC,即单调时间,即从某个时间点开始到现在过去的时间。

    用户不能修改这个时间,但是当系统进入休眠 ( suspend ) 时,CLOCK_MONOTONIC 是不会增加的

    CLOCK_MONTONIC 其实就是一个计时器,当电脑开机的时候重新开始计时,当电脑睡眠的时候暂停计时,当电脑关机的时候停止计时

    只不过这个计时器采用的不是 秒为单位,或者通常计时器上的 xx.xx ,而是采用的 CPU 时钟

  3. CLOCK_MONOTONIC_RAW,和 CLOCK_MONOTONIC 类似,不同之处是 MONOTONIC_RAW 不会受到 NTP 的影响

    CLOCK_MONOTONIC 会受到 NTP 的影响并不是说 NTP 会去修改 CLOCK_MONOTONIC,使其不连续

    而是说当 NTP server 和本地的时钟硬件之间有问题,NTP 会影响到 CLOCK_MONOTONIC 的频率,但是 MONOTONIC_RAW 则不会受其影响

  4. CLOCK_BOOTTIME,与 CLOCK_MONOTONIC类似,但是当休眠 ( suspend ) 时,会依然增加

了解了 Linux 世界的四个时钟后,我们就来说说 Go 语言里的两个时钟

Monotonic Clocks

Go 语言的 time 包主要使用了两个时钟

  1. CLOCK_REALTIME,就是非常出名的 「 wall time 」,即是实际的时间
  2. CLOCK_MONTONIC,即单调时间,即从某个时间点开始到现在过去的时间

操作系统提供 「 wall time 」,其可以根据时钟同步而变化,以及 「 monotonic clock 」,不会根据时钟同步而变化。

两者的一般规则是 「 wall time 」 用于告知时间,而 「 monotonic clock 」 用于测量时间

Go 语言为了简化 API,并没有为两种时钟准备两套 API,而是在 time.Now() 方法返回的 Time 结构中同时包含了 wall clock 读数和 monotonic clock 读数;

而之后对 Time 结构的操作,显示时间相关的操作使用的是 wall time ,测量和计算时间的操作使用的是 monotonic clock ,特别是比较和减法,使用 monotonic clock 读数。

例如,下面的代码,即使在定时操作期间更改 wall time ,此代码也始终计算大约 20 毫秒的时间间隔

start := time.Now()
... operation that takes 20 milliseconds ...
t := time.Now()
elapsed := t.Sub(start)

而另外一些方法,比如 time.Since(start)time.Until(deadline)time.Now().before(deadline) 等,同样不受 wall time 时间重置的影响

结束语

有关 time 包两个时间的更多细节,我们会再下一章节继续阐述,这章节就到这里吧

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.