一文带你理解Golang中的Time结构

 更新时间:2023年09月19日 14:09:05   作者:Golang私房菜  
根据golang的time包的文档可以知道,golang的time结构中存储了两种时钟,一种是Wall Clocks,一种是Monotonic Clocks,下面我们就来简单了解一下这两种结构吧

在golang中创建并打印一个时间对象,会看到如下输出

2018-10-26 14:15:50.306558969 +0800 CST m=+0.000401093

前面表示的意义好理解,分别是年月日和时间时区,最后的m=+xxxx这部分代表什么呢?

Monotonic Clocks 和 Wall Clocks

根据golang的time包的文档可以知道,golang的time结构中存储了两种时钟,一种是Wall Clocks,一种是Monotonic Clocks。

Wall Clocks,顾名思义,表示墙上挂的钟,在这里表示我们平时理解的时间,存储的形式是自 1970 年 1 月 1 日 0 时 0 分 0 秒以来的时间戳,当系统和授时服务器进行校准时间时间操作时,有可能造成这一秒是2018-1-1 00:00:00,而下一秒变成了2017-12-31 23:59:59的情况。Monotonic Clocks,意思是单调时间的,所谓单调,就是只会不停的往前增长,不受校时操作的影响,这个时间是自进程启动以来的秒数。

如果每隔一秒生成一个Time并打印出来,就会看到如下输出。

2018-10-26 14:15:50.306558969 +0800 CST m=+0.000401093
2018-10-26 14:15:51.310559881 +0800 CST m=+1.004425285
2018-10-26 14:15:52.311822486 +0800 CST m=+2.005711106
2018-10-26 14:15:53.314599457 +0800 CST m=+3.008511329
2018-10-26 14:15:54.31882248 +0800 CST m=+4.012757636
2018-10-26 14:15:55.320059921 +0800 CST m=+5.014018292
2018-10-26 14:15:56.323814998 +0800 CST m=+6.017796644
2018-10-26 14:15:57.324858749 +0800 CST m=+7.018863606
2018-10-26 14:15:58.325164174 +0800 CST m=+8.019192224
2018-10-26 14:15:59.329058535 +0800 CST m=+9.023109863
2018-10-26 14:16:00.329591268 +0800 CST m=+10.023665796

可以看到m=+后面所显示的数字,就是文档中所说的Monotonic Clocks。

Time结构

那么Monotonic Clock和Wall Clock在Time中是怎么存储的呢?来看一下Time结构体。

type Time struct {
    wall uint64
    ext  int64
    loc *Location
}

Time结构体中由三部分组成,loc比较明了,表示时区,wall和ext所存储的信息规则相对复杂,根据文档的介绍总结成了下图:

golang中的Time结构,不像很多语言保存Unix时间戳(也就是最早只能表示到1970年1月1日),而是至少可以安全的表示1885年以来的时间。

t, _ := time.Parse(time.RFC3339, "1890-01-02T15:04:05Z")
fmt.Println(t) // 1890-01-02 15:04:05 +0000 UTC

实践中需要注意的问题

既然Time结构所表示的时间,有可能有Monotonic Clock也可能没有,那么在使用中就有可能遇到一些问题,例如下面这种情况。

now := time.Now()
encodeNow, _ := json.Marshal(now)
decodeNow := time.Time{}
json.Unmarshal(encodeNow, &decodeNow)
fmt.Println(now)  // 2018-10-26 16:04:55.230121766 +0800 CST m=+0.000520419
fmt.Println(decodeNow)  // 2018-10-26 16:04:55.230121766 +0800 CST

可以看到,经过JSON转码之后,Time结构体会被表示成不带Monotonic Clock的字符串,丢失了Monotonic Clock信息,而将字符串转码回Time结构时,自然也就和转码之前的不一样了。同样的情况,也发生在数据库存储中,存储到数据库里的Time结构和从数据库取出来的也是不一样的。

当调用Equal比较两个Time时,只有两个Time都含有Monotonic Clock时,才会根据Monotonic Clock比较大小,其他情况只比较Wall Clock部分。

timeA := time.Now()
timeB := time.Unix(0, timeA.UnixNano())
fmt.Println(timeA)  // 2018-10-26 16:37:02.216165074 +0800 CST m=+0.000363156
fmt.Println(timeB)  // 2018-10-26 16:37:02.216165074 +0800 CST
r := timeA.Equal(timeB)
fmt.Println(r)  // true

上面两个时间的Wall Clock部分相同,一个有Monotonic Clock一个没有,但是比较的结果是两个时间是相同的。

timeA := time.Now()
timeB := time.Unix(timeA.Unix(), 0)
fmt.Println(timeA)  // 2018-10-26 16:38:25.653953438 +0800 CST m=+0.000364851
fmt.Println(timeB)  // 2018-10-26 16:38:25 +0800 CST
r := timeA.Equal(timeB)
fmt.Println(r)  // false

需要注意的是Wall Clock并不是秒之前的部分,Wall Clock本身也可以精确到纳秒级别,所以一个精确到纳秒的时间和一个精确到秒的时间也是不同的。

对于Time中的Monotonic Clock,我们可以使用time.Round(0)方法将其消除掉,以实现和其他语言一致的行为。

timeA := time.Now()
timeB := timeA.Round(0)
fmt.Println(timeA)  // 2018-10-26 16:43:03.799263739 +0800 CST m=+0.000357758
fmt.Println(timeB)  // 2018-10-26 16:43:03.799263739 +0800 CST

到此这篇关于一文带你理解Golang中的Time结构的文章就介绍到这了,更多相关Go Time结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • go micro微服务proto开发安装及使用规则

    go micro微服务proto开发安装及使用规则

    这篇文章主要为大家介绍了go micro微服务proto开发中安装Protobuf及基本规范字段的规则详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-01-01
  • GO语言zap日志库理解和使用方法示例

    GO语言zap日志库理解和使用方法示例

    Zap是一个高性能、结构化日志库,专为Go语言设计,它由Uber开源,并且在Go社区中非常受欢迎,这篇文章主要介绍了GO语言zap日志库理解和使用方法的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-11-11
  • 分享6个Go处理字符串的技巧小结

    分享6个Go处理字符串的技巧小结

    这篇文章主要介绍了分享6个Go处理字符串的技巧小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • Golang语言如何避免空指针引发的panic详解

    Golang语言如何避免空指针引发的panic详解

    简单地说go语言的指针类型和C/C++的指针类型用法是一样的,除了出去安全性的考虑,go语言增加了一些限制,这篇文章主要给大家介绍了关于Golang语言如何避免空指针引发panic的相关资料,需要的朋友可以参考下
    2022-01-01
  • Golang中使用不定数量空格分割字符串的方法

    Golang中使用不定数量空格分割字符串的方法

    有这样一个使用空格分割字符串的场景,字符串中被分割的子串之间的空格数量不确定,有一个两个或者多个空格,这种场景下,使用最容易想到的strings.Split函数就做不到了,本文接下来就介绍几种行之有效的方法,需要的朋友可以参考下
    2023-07-07
  • 基于Go和Gin的环境配置方法

    基于Go和Gin的环境配置方法

    今天小编就为大家分享一篇基于Go和Gin的环境配置方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-07-07
  • Go语言操作Excel利器之excelize类库详解

    Go语言操作Excel利器之excelize类库详解

    Excelize是Go语言编写的用于操作Office Excel文档基础库,基于ECMA-376,ISO/IEC 29500国际标准,可以使用它来读取、写入由Excel 2007及以上版本创建的电子表格文档,下面这篇文章主要给大家介绍了关于Go语言操作Excel利器之excelize类库的相关资料,需要的朋友可以参考下
    2022-10-10
  • Go调用链可视化工具使用实例探究

    Go调用链可视化工具使用实例探究

    本文介绍一款工具 go-callvis,它能够将 Go 代码的调用关系可视化出来,并提供了可交互式的 web 服务,在接手他人代码或调研一些开源项目时,如果能够理清其中的代码调用链路,这将加速我们对实现的理解
    2024-01-01
  • gin框架Context如何获取Get Query Param函数数据

    gin框架Context如何获取Get Query Param函数数据

    这篇文章主要为大家介绍了gin框架Context Get Query Param函数获取数据,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-03-03
  • Go语言中处理错误的技巧分享

    Go语言中处理错误的技巧分享

    编写 Go 语言程序时,有效地处理错误是至关重要的,Go 语言提供了一些强大的工具和模式来处理错误,本文将介绍这些方法,以便编写健壮的 Go 代码,更好地处理错误,需要的朋友可以参考下
    2023-09-09

最新评论