Go的time包 | 青训营笔记

147 阅读6分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第10天


time 包中日历的计算采用的是公历,不考虑润秒

使用time.Time类型表示时间, 通过time.Now函数获取当前的时间对象, 然后从时间对象中可以获取到年、月、日、时、分、秒等信息。

// timeDemo 时间对象的年月日时分秒
func timeDemo() {
        now := time.Now() // 获取当前时间
        fmt.Printf("current time:%v\n", now)

        year := now.Year()     // 年
        month := now.Month()   // 月
        day := now.Day()       // 日
        hour := now.Hour()     // 小时
        minute := now.Minute() // 分钟
        second := now.Second() // 秒
        fmt.Println(year, month, day, hour, minute, second)}

Location和time zone

Go 语言中使用 location 来映射具体的时区。时区(Time Zone)是根据世界各国家与地区不同的经度而划分的时间定义,全球共分为24个时区。

// timezoneDemo 时区示例
func timezoneDemo() {
        // 中国没有夏令时,使用一个固定的8小时的UTC时差。
        // 对于很多其他国家需要考虑夏令时。
        secondsEastOfUTC := int((8 * time.Hour).Seconds())
        // FixedZone 返回始终使用给定区域名称和偏移量(UTC 以东秒)的 Location。
        beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)

        // 如果当前系统有时区数据库,则可以加载一个位置得到对应的时区
        // 例如,加载纽约所在的时区
        newYork, err := time.LoadLocation("America/New_York") // UTC-05:00
        if err != nil {
                fmt.Println("load America/New_York location failed", err
                return
        }
        fmt.Println()

        // 加载上海所在的时区
        //shanghai, err := time.LoadLocation("Asia/Shanghai") // UTC+08:00

        // 加载东京所在的时区
        //tokyo, err := time.LoadLocation("Asia/Tokyo") // UTC+09:00

        // 创建时间对象需要指定位置。常用的位置是 time.Local(当地时间) 和 time.UTC(UTC时间)。
        //timeInLocal := time.Date(2009, 1, 1, 20, 0, 0, 0, time.Local)  // 系统本地时间
        timeInUTC := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
        sameTimeInBeijing := time.Date(2009, 1, 1, 20, 0, 0, 0, beijing)
        sameTimeInNewYork := time.Date(2009, 1, 1, 7, 0, 0, 0, newYork)

        // 北京时间(东八区)比UTC早8小时,所以上面两个时间看似差了8小时,但表示的是同一个时间
        timesAreEqual := timeInUTC.Equal(sameTimeInBeijing)
        fmt.Println(timesAreEqual)

        // 纽约(西五区)比UTC晚5小时,所以上面两个时间看似差了5小时,但表示的是同一个时间
        timesAreEqual = timeInUTC.Equal(sameTimeInNewYork)
        fmt.Println(timesAreEqual)}

Unix Time

Unix Time是自1970年1月1日 00:00:00 UTC 至当前时间经过的总秒数。

// timestampDemo 时间戳
func timestampDemo() {

        now := time.Now()        // 获取当前时间
        timestamp := now.Unix()  // 秒级时间戳
        milli := now.UnixMilli() // 毫秒时间戳 Go1.17+
        micro := now.UnixMicro() // 微秒时间戳 Go1.17+
        nano := now.UnixNano()   // 纳秒时间戳

        fmt.Println(timestamp, milli, micro, nano)}

将 int64 类型的时间戳转换为时间对象的方法

// timestamp2Time 将时间戳转为时间对象
func timestamp2Time() {
        // 获取北京时间所在的东八区时区对象
        secondsEastOfUTC := int((8 * time.Hour).Seconds())
        beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
        // 北京时间 2022-02-22 22:22:22.000000022 +0800 CST
        t := time.Date(2022, 02, 22, 22, 22, 22, 22, beijing)
        var (
                sec  = t.Unix()
                msec = t.UnixMilli()
                usec = t.UnixMicro()
        )
        // 将秒级时间戳转为时间对象(第二个参数为不足1秒的纳秒数)
        timeObj := time.Unix(sec, 22)
        fmt.Println(timeObj)           // 2022-02-22 22:22:22.000000022 +0800 CST
        timeObj = time.UnixMilli(msec) // 毫秒级时间戳转为时间对象
        fmt.Println(timeObj)           // 2022-02-22 22:22:22 +0800 CST
        timeObj = time.UnixMicro(usec) // 微秒级时间戳转为时间对象
        fmt.Println(timeObj)           // 2022-02-22 22:22:22 +0800 CST}

时间间隔

time.Duration是time包定义的一个类型,它代表两个时间点之间经过的时间,以纳秒为单位。

const (

    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

time.Duration表示1纳秒,time.Second表示1秒。


时间操作

Add

func (t Time) Add(d Duration) Time
   now := time.Now()
   later := now.Add(time.Hour) // 当前时间加1小时后的时间
   fmt.Println(later)

Sub

求两个时间之差

func (t Time) Sub(u Time) Duration

返回一个时间段t-u。如果结果超出了Duration可以表示的最大值/最小值,将返回最大值/最小值。要获取时间点t-d(d为Duration),可以使用t.Add(-d)。

Equal

func (t Time) Equal(u Time) bool

判断两个时间是否相同,会考虑时区和地点的影响,因此不同时区标准的时间也可以正确比较。

Before

func (t Time) Before(u Time) bool

如果t代表的时间点在u之前,返回真;否则返回假。

After

func (t Time) After(u Time) bool


定时器

使用time.Tick(时间间隔)来设置定时器,定时器的本质上是一个通道(channel)。

func tickDemo() {
        ticker := time.Tick(time.Second) //定义一个1秒间隔的定时器
        for i := range ticker {
                fmt.Println(i)//每秒都会执行的任务
        }}

时间格式化

time.Format函数能够将一个时间对象格式化输出为指定布局的文本表示形式。

需要注意的是 Go 语言中时间格式化的布局不是常见的Y-m-d H:M:S,而是使用 2006-01-02 15:04:05.000(记忆口诀为2006 1 2 3 4 5)。

// formatDemo 时间格式化
func formatDemo() {
        now := time.Now()
        // 格式化的模板为 2006-01-02 15:04:05
        // 24小时制
        fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))
        // 12小时制
        fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
        // 小数点后写0,因为有30所以格式化输出的结果也保留3位小数
        fmt.Println(now.Format("2006/01/02 15:04:05.000")) // 2022/02/27 00:10:42.960
        // 小数点后写9,会省略末尾可能出现的0
        fmt.Println(now.Format("2006/01/02 15:04:05.999")) // 2022/02/27 00:10:42.96
        // 只格式化时分秒部分
        fmt.Println(now.Format("15:04:05"))

        // 只格式化日期部分
        fmt.Println(now.Format("2006.01.02"))}
  • 如果想格式化为12小时格式,需在格式化布局中添加PM。

  • 小数部分想保留指定位数就写0,如果想省略末尾可能的0就写 9。

从文本的时间表示中解析出时间对象:

time包中提供了time.Parse和time.ParseInLocation两个函数。

其中time.Parse在解析时不需要额外指定时区信息。

// parseDemo 指定时区解析时间
func parseDemo() {
        // 在没有时区指示符的情况下,time.Parse 返回UTC时间
        timeObj, err := time.Parse("2006/01/02 15:04:05", "2022/10/05 11:25:20")
        if err != nil {
                fmt.Println(err)
                return
        }
        fmt.Println(timeObj) // 2022-10-05 11:25:20 +0000 UTC
        // 在有时区指示符的情况下,time.Parse 返回对应时区的时间表示
        // RFC3339     = "2006-01-02T15:04:05Z07:00"
        timeObj, err = time.Parse(time.RFC3339, "2022-10-05T11:25:20+08:00")
        if err != nil {
                fmt.Println(err)
                return
        }
        fmt.Println(timeObj) // 2022-10-05 11:25:20 +0800 CST}

time.ParseInLocation函数需要在解析时额外指定时区信息。

// parseDemo 解析时间
func parseDemo() {

        now := time.Now()
        fmt.Println(now)

        // 加载时区
        loc, err := time.LoadLocation("Asia/Shanghai")
        if err != nil {
                fmt.Println(err)
                return
        }

        // 按照指定时区和指定格式解析字符串时间
        timeObj, err := time.ParseInLocation("2006/01/02 15:04:05", "2022/10/05 11:25:20", loc)
        if err != nil {
                fmt.Println(err)
                return
        }

        fmt.Println(timeObj)
        fmt.Println(timeObj.Sub(now))}