写点什么

「Go 工具箱」推荐一个轻量级、语义化的时间处理库:carbon

作者:Go学堂
  • 2022-11-16
    北京
  • 本文字数:2546 字

    阅读完需:约 8 分钟

「Go工具箱」推荐一个轻量级、语义化的时间处理库:carbon

在工作中,主动性不仅体现在像老黄牛一样把本职工作做好,还要主动和领导沟通,承担更多、更重要的任务。 --- 吴军 《格局》


大家好,我是渔夫子。「Go 学堂」新推出“Go 工具箱”系列,意在给大家分享使用 go 语言编写的、实用的、好玩的工具。


今天给大家推荐一个轻量级、语义化、对开发者友好的 golang 时间处理库:carbon

carbon 小档案

star: 595 used by: 198. contributors: 22 作者: guogouyin

功能简介: 一个轻量级、语义化、对开发者友好的 golang 时间处理库。该库支持链式调用和 gorm、xorm 等主流 orm

项目地址: https://github.com/golang-module/carbon


一、安装

当 go 版本 ≥1.16 时,推荐使用 v2 包,如下:


 go get -u github.com/golang-module/carbon/v2
复制代码


go 小于 1.16 时,必须使用第一个版本


go get -u github.com/golang-module/carbon
复制代码

二、carbon 的使用及实现原理

在 Go 的标准库中,日期的处理是基于 time.Time 结构体的。而 carbon 包也是基于 time.Time 结构体,并对一些常用的行为进行了封装,提高了对时间处理的效率以及代码的可读性。所以在 carbon 包中所有的行为是基于 Carbon 结构体的。下面是 carbon 结构体的数据结构



Carbon 结构体很简单,共 5 个字段。由各字段可知该包能够处理日期和时间、设置时区、国际化支持以及错误处理。其主要功能如下图所示:



在 carbon 的项目主页对各种功能的使用已经说的非常详细了,这里就不再重复介绍。接下来我们会通过两个示例来说明 carbon 的具体应用。结构体中的时间字段转 json 时的时间格式和计算两个日期相差几个自然天。

示例一:结构体中的时间字段转 json

这里主要是想说明在对 time.Time 的字段进行 json 格式化时如何自定义日期输出的格式。因为 time.Time 类型的字段默认是按 RFC3339 标准格式输出的,即 “2022-08-08T12:12:12+08:00”这种格式。我们先来看一个示例:


type Person struct {    Name string    Birthday time.Time}
birthday := carbon.Parse("2022-08-08 12:12:12").Carbon2Time()
p:= Person{ Name: "渔夫子", Birthday: birthday,}
encodeToJson, _ := json.Marshal(p) //输出{"Name":"渔夫子","Birthday":"2022-08-08T12:12:12+08:00"}
复制代码


这里最终输出的 json 字符串如下:


{  "Name":"渔夫子",  "Birthday":"2022-08-08T12:12:12+08:00"}
复制代码


Birthday 字段输出的日期格式是“2022-08-08T12:12:12+08:00”,原因在于在 json 包中定义了一个 Marshaler 接口,数据类型只要实现了该接口,那么就优先使用该类型自定义的 MarshalJSON 方法。如下:


type Marshaler interface {    MarshalJSON() ([]byte, error)}
复制代码


time.Time 类型就是实现了该接口,并且在具体的实现中采用了 RFC3339 标准的日期格式。所以才看到我们的输出是"2022-08-08T12:12:12+08:00"。我们看下 time.Time 类型中 MarshalJson 方法:


func (t Time) MarshalJSON() ([]byte, error) {    if y := t.Year(); y < 0 || y >= 10000 {        // RFC 3339 is clear that years are 4 digits exactly.        // See golang.org/issue/4556#c15 for more discussion.        return nil, errors.New("Time.MarshalJSON: year outside of range [0,9999]")    }
b := make([]byte, 0, len(RFC3339Nano)+2) b = append(b, '"') b = t.AppendFormat(b, RFC3339Nano) b = append(b, '"') return b, nil}
复制代码


显然,这种日期的格式是不符合我们平时的阅读习惯的。我们的习惯是"2022-08-08 12:12:12"这种格式就好。那怎么实现呢?那就是自定义一种类型,并且这种类型实现 json 包中的 Marshaler 接口。


carbon 中就已经帮我们做了这些事情。我们看 carbon 中的 DateTime 类型。


type Person struct {    Name string    Birthday carbon.DateTime}
birthday := carbon.DateTime{ Carbon:carbon.Parse("2022-08-08 12:12:12")}
p:= Person{ Name: "渔夫子", Birthday: birthday,}
encodeToJson, _ := json.Marshal(p) //输出{"Name":"渔夫子","Birthday":"2022-08-08 12:12:12"}
复制代码


我们看到最终 json 串中的 Birthday 字段输出是“2022-08-08 12:12:12"的格式了。这是因为 carbon.DateTime 类型也实现了 json 包中的 Marshaler 接口,在 MarshalJSON 的实现方法中让 time.Time 字段按"2006-01-02 15:04:05"这种格式输出。当然在 carbon 中还有其他的实现了 json 包中的 Marshaler 接口,大家自行查看即可。

示例二:计算两个日期相差几个自然日

以北京时间为例,给定开始时间 2022-10-31 21:23:45,作为第 1 个自然日。那么日期 2022-11-01 14:23:45 相对于开始时间就是第 2 个自然日。这里需注意的是 只要到了 2022-11-01 日,就算作第 2 个自然日了。


那么,给定任意两个日期,用程序该怎么计算呢?我的方法是以开始日期的 00:00:00 作为起点,以结束日期的 23:59:59 秒再加 1 秒作为终点,计算终点和起点的时间差,然后再除以一天的秒数 86400,得出来的商就是结束日期相对于开始日期的第几个自然日。


一天的结束是在 23:59:59,再加 1 秒实际就到了次日的 00:00:00,这样做是为了得到 86400(一天总共有 86400 秒)的整数倍。



所以我们这里就要利用 carbon 中获取一天开始时间和结束时间相关的函数了。代码如下:


startDate := "2022-10-31 04:13:14"endDate := "2022-11-02 01:13:14"
startDateUnix := carbon.Parse(startDate).StartOfDay().Timestamp()endDateUnix := carbon.Parse(endDate).EndOfDay().AddSeconds(1).Timestamp()
days := (endDateUnix - startDateUnix) / 86400
复制代码


StartOfDay 和 EndOfDay 的实现,本质上还是利用了 time.Date 函数。一天的开始就是指定时分秒时都为 0,一天的结束就是指定时分秒时为 23 点,59 分,59 秒。如下:


locat, error:= time.LoadLocation("Asia/Shanghai")// 初始化成一天的开始time.Date(2022, time.Month(10), 31, 0, 0, 0, 0, locat)
// 初始化成一天的结束time.Date(2022, time.Month(11), 1, 23, 59, 59, 0, locat)
复制代码


关于更多 time.Time 时间的处理大家可以参考我之前的文章:golang 中 time 包使用教程之基础使用篇


---特别推荐 ---

特别推荐:一个专注 go 项目实战、项目中踩坑经验及避坑指南、各种好玩的 go 工具的公众号。「Go 学堂 」,专注实用性,非常值得大家关注。点击下方公众号卡片,直接关注。关注送《100 个 go 常见的错误》pdf 文档。

发布于: 刚刚阅读数: 3
用户头像

Go学堂

关注

关注「Go学堂」,学习更多编程知识 2019-08-06 加入

专注Go编程知识、案例、常见错误及原理分析。意在通过阅读更多优秀的代码,提高编程技能。同名公众号「Go学堂」期待你的关注

评论

发布
暂无评论
「Go工具箱」推荐一个轻量级、语义化的时间处理库:carbon_Go_Go学堂_InfoQ写作社区