Go 标准库 time 包之 Time 结构 ( 下 )
5 点 30 就起床开工了...
上一章节,我们从宏观的角度介绍了下 Time
结构,如果你英文很厉害,其实就会发现我只是把官方文档翻译了一遍。本章节,我们继续把剩余的 Time
结构的内部文档再翻译一遍。介绍下 Time
结构的那些成员属性:wall
、ext
还有 loc
。其实,最重要的还会上一章节中要讲但没讲的 Time 如何区分 wall clock 和 monotonic clocks 两种时钟。
我们再次熟悉下 Time
结构的源码 ( 删除了注释 )
type Time struct { wall uint64 ext int64 loc *Location }
可以看到有三个属性
属性 | 类型 | 说明 |
---|---|---|
wall | uint64 | wall clock 的总秒数,其实就是时间戳,1970 年 1 月 1 日 0 时 0 分 0 秒以来的总秒数 |
ext | int64 | 纳秒数 |
loc | *Location | 时区 ,默认为 nil ,也就是 UTC ,或者说格林威治时间 |
如果你熟悉其它语言的日期时间处理模块,就会有一个担忧,因为它们中有很多存储时间戳使用的是 int
的数据类型,在 32 位机器上,能表示的日期是 范围是1970 年 1 月 1 日到 2038 年 1 月 19 日。( 现在的电脑基本上是 64 位,能表示一个非常非常大的时刻 )
但 Go 语言 ,在出生那刹那开始,使用的就是 uint64
,如果全部用来表示时间,那将会是一个非常大非常大的时间。甚至超过 9999-12-31 23:59:59
。
我们看一下以下代码的输出结果就知道了
package main import "time" const UINT64_MIN uint64 = 0 const UINT64_MAX uint64 = ^uint64(0) const form = "2006-01-02 15:04:05" func main() { t, _ := time.Parse(form, "9999-12-31 23:59:59") println("unint64 的最大值为:", UINT64_MAX) println("9999-12-31 23:59:59 的时间戳为:", t.Unix()) }
输出结果为
unint64 的最大值为: 18446744073709551615 9999-12-31 23:59:59 的时间戳为: 253402300799
可以看到,253402300799 远远小于 18446744073709551615,所以,wall
中有些位 ( 总共 64 位 ) 可以拿来做其它事情。比如标识是否包含了 monotonic clocks 等。
实际上,Time 结构也是这么做的,我们可以看看官方文档对 wall
和 ext
的注释。
// wall and ext encode the wall time seconds, wall time nanoseconds, // and optional monotonic clock reading in nanoseconds. // // From high to low bit position, wall encodes a 1-bit flag (hasMonotonic), // a 33-bit seconds field, and a 30-bit wall time nanoseconds field. // The nanoseconds field is in the range [0, 999999999]. // If the hasMonotonic bit is 0, then the 33-bit field must be zero // and the full signed 64-bit wall seconds since Jan 1 year 1 is stored in ext. // If the hasMonotonic bit is 1, then the 33-bit field holds a 33-bit // unsigned wall seconds since Jan 1 year 1885, and ext holds a // signed 64-bit monotonic clock reading, nanoseconds since process start.
注释上说
-
wall
和ext
两个属性分别用于编码 wall time 中的总秒数和 wall time 中的纳秒数,还可能包含了可选的 monotonic clock 的纳秒格式的读数 -
从高位到低位, wall 编码时,第一个位 ( 1-bit ) 是一个标识符位,用于标识是否包含了 monotonic clock 。 可以将 wall 与
hasMonotonic
做位与 ( & ) 操作来检查。hasMonotonic
的定义如下hasMonotonic = 1 << 63
我们简称这个最高位为
hasMonotonic
位 -
然后接下来的 33 位和最后的 30 位,分别用于编码编码 wall time 中的总秒数和 wall time 中的纳秒数,纳秒的取值范围是
[0, 999999999]
-
如果 hasMonotonic 位的取值为
0
,那么中间的 33 位会被设置为且必须为0
,然后会将自 1 年 1 月 1 日 0 时 0 分 0 纳秒的有符号的 wall clock 总秒数都存储在ext
中。但是,纳秒数还是存储在原来的位置,也就是wall
的剩余的 30 位 -
如果 hasMonotonic 位的取值为
1
,那么中间的 33 位存储了自 1885 1 年 1 月 1 日 0 时 0 分 0 纳秒的以来的无符号的 wall clock 的总秒数,而ext
则存储了有符号的 64 位的 monotonic clock 读数,也就是,进程创建以来的总纳秒数
而对于 loc
这个属性,官方文档的解释为
// loc specifies the Location that should be used to // determine the minute, hour, month, day, and year // that correspond to this Time. // The nil location means UTC. // All UTC times are represented with loc==nil, never loc==&utcLoc.
意思就是说
loc
用于指定了用于确定与此时间对应的分钟,小时,月,日和年的时区。
如果 loc
的值为 nil
,则表示 UTC
。 所有的 UTC 时间都用 loc == nil
表示,而不是 loc ==&utcLoc
结束语
就先这样了,Time 结构的介绍到此完毕,我要出门了...