Golang语言标准库time之日期和时间相关函数

                                              作者:尹正杰

版权声明:原创作品,谢绝转载!否则将追究法律责任。

一.时间类型

package main

import (
	"time"
	"fmt"
)

func main() {
	// 获取当前时间对象,后从时间对象中可以获取到年、月、日、时、分、秒等信息。
	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

1.时区介绍

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

中国差不多跨5个时区,但为了使用方便只用东八时区的标准时即北京时间为准。在日常编码过程中使用时间对象的时候一定要注意其时区信息。

2.时区案例

package main

import (
	"fmt"
	"time"
)

func main() {
	// 中国没有夏令时,使用一个固定的8小时的UTC时差(东八区,UTC +08:00),对于很多其他国家需要考虑夏令时。
	timezone := int((8 * time.Hour).Seconds())

	// FixedZone 返回始终使用给定区域名称和偏移量(UTC 以东秒)的Location。UTC +08:00
	shanghaiTimezone := time.FixedZone("Asia/Shanghai", timezone)

	// 如果当前系统有时区数据库,则可以加载一个位置得到对应的时区,例如,加载纽约所在的时区,UTC -05:00
	newYorkTimezone, _ := time.LoadLocation("America/New_York")

	utc := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
	shanghai := time.Date(2009, 1, 1, 20, 0, 0, 0, shanghaiTimezone)
	NewYork := time.Date(2009, 1, 1, 7, 0, 0, 0, newYorkTimezone)

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

	// 纽约(西五区)比UTC晚5小时,所以上面两个时间看似差了5小时,但表示的是同一个时间
	t2  := utc.Equal(NewYork)


	fmt.Printf("[%v] = [%v] => [%t]\n",utc,shanghai,t1)
	fmt.Printf("[%v] = [%v] => [%t]\n",utc,NewYork,t2)
}

三.时间戳unix time

1.Unix Time概述

Unix Time是自1970年1月1日 00:00:00 UTC至当前时间经过的总秒数。下面的代码片段演示了如何基于时间对象获取到Unix 时间。

2.获取时间戳

package main

import (
	"fmt"
	"time"
)

func main() {
	// 获取当前时间
	now := time.Now()

	// 秒级时间戳
	timestamp := now.Unix()

	// 毫秒时间戳 Go1.17+
	milli := now.UnixMilli()

	// 微秒时间戳 Go1.17+
	micro := now.UnixMicro()

	// 纳秒时间戳
	nano := now.UnixNano()

	fmt.Printf("秒级时间戳: %v\n毫级时间戳: %v\n微级时间戳: %v\n纳级时间戳: %v\n", timestamp, milli, micro, nano)
}

3.将时间戳转为时间对象

package main

import (
	"fmt"
	"time"
)

func main() {
	// 获取北京时间所在的东八区时区对象
	secondsEastOfUTC := int((8 * time.Hour).Seconds())
	beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)

	// 北京时间 2022-02-22 22:22:22.000000022 +0800 CST
	t := time.Date(2030, 11, 11, 23, 59, 59, 59, beijing)

	var (
		sec  = t.Unix()
		msec = t.UnixMilli()
		usec = t.UnixMicro()
	)

	// 将秒级时间戳转为时间对象(第二个参数为不足1秒的纳秒数)
	t1 := time.Unix(sec, 99999)

	// 毫秒级时间戳转为时间对象
	t2 := time.UnixMilli(msec)

	// 微秒级时间戳转为时间对象
	t3 := time.UnixMicro(usec)

	fmt.Printf("t1 = [%v], t2 = [%v], t3 = [%v]\n", t1, t2, t3)
}

四.时间间隔设置及比较

1.时间间隔类型的常量

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

time.Duration表示一段时间间隔,可表示的最长时间段大约290年。

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秒。

2.Add

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	/*
		Go语言的时间对象有提供Add方法如下:
			func (t Time) Add(d Duration) Time
	*/

	later := now.Add(time.Hour) // 当前时间加1小时后的时间

	fmt.Printf("now = [%v] later = [%v]\n", now, later)
}

3.sub

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()
	

	t1, _ := time.Parse("2006/01/02 15:04:05", "2024/08/20 11:25:20")

	/*
		Go语言的时间对象有提供Sub方法如下:
			func (t Time) Sub(u Time) Duration
	*/
	t2 := now.Sub(t1) // 比较现在和t1时间相差的时间

	fmt.Printf("now = [%v] t2 = [%v]\n", now, t2)
}

4.Equal

package main

import (
	"fmt"
	"time"
)

func main() {

	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/08/20 11:25:20")

	t2, _ := time.Parse(time.RFC3339, "2030-08-20T19:25:20+08:00")

	/*
		Go语言的时间对象有提供Equal方法如下:
			func (t Time) Equal(u Time) bool

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

		本方法和用t==u不同,这种方法还会比较地点和时区信息。
	*/
	flag := t1.Equal(t2)

	fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}

5.Before

package main

import (
	"fmt"
	"time"
)

func main() {

	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/08/21 12:25:20")

	t2, _ := time.Parse(time.RFC3339, "2030-08-30T19:25:20+08:00")

	/*
		Go语言的时间对象有提供Before方法如下:
				func (t Time) Before(u Time) bool

		如果t代表的时间点在u之前,返回真;否则返回假。
	*/
	flag := t1.Before(t2)

	fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}

6.After

package main

import (
	"fmt"
	"time"
)

func main() {

	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/09/21 12:25:20")

	t2, _ := time.Parse(time.RFC3339, "2030-08-30T19:25:20+08:00")

	/*
		Go语言的时间对象有提供Before方法如下:
			func (t Time) After(u Time) bool
			
		如果t代表的时间点在u之后,返回真;否则返回假。
	*/
	flag := t1.After(t2)

	fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}

五.定时器

1.定时器概述

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

2.定时器案例

package main

import (
	"fmt"
	"time"
)

func main() {
	// //定义一个1秒间隔的定时器,如果想要换成每分钟,可以使用"time.Minute",依此类推...
	ticker := time.Tick(time.Second)

	for i := range ticker {
		//每秒都会执行的任务
		fmt.Println(i)
	}
}

六.时间格式化

1.时间格式化

time.Format函数能够将一个时间对象格式化输出为指定布局的文本表示形式,需要注意的是Go语言中时间格式化的布局不是常见的Y-m-d H:M:S,而是使用"2006-01-02 15:04:05.000"(记忆口诀为2006 1 2 3 4 5)。

其中:
	- 2006:年(Y)
	- 01:月(m)
	- 02:日(d)
	- 15:时(H)
	- 04:分(M)
	- 05:秒(S)
	
	
温馨提示:
	(1)如果想格式化为12小时格式,需在格式化布局中添加PM。
	(2)小数部分想保留指定位数就写0,如果想省略末尾可能的0就写9。

2.参考案例

package main

import (
	"fmt"
	"time"
)

func main() {
	// 获取当前时间对象,后续方便基于对时间对象进行格式化操作
	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,因为有3个0所以格式化输出的结果也保留3位小数
	fmt.Println(now.Format("2006/01/02 15:04:05.000"))

	// 小数点后写9,会省略末尾可能出现的0
	fmt.Println(now.Format("2006/01/02 15:04:05.999"))

	// 只格式化时分秒部分
	fmt.Println(now.Format("15:04:05"))

	// 只格式化日期部分
	fmt.Println(now.Format("2006.01.02"))
}

七.解析字符串的时间

1.解析时间的函数

对于从文本的时间表示中解析出时间对象,time包中提供了time.Parse和time.ParseInLocation两个函数。

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

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

2.Parse从文本解析时间

package main

import (
	"fmt"
	"time"
)

func main() {
	// 在没有时区指示符的情况下,time.Parse 返回UTC时间
	t1, _ := time.Parse("2006/01/02 15:04:05", "2030/10/05 11:25:20")

	// 在有时区指示符的情况下,time.Parse 返回对应时区的时间表示
	// RFC3339     = "2006-01-02T15:04:05Z07:00"
	t2, _ := time.Parse(time.RFC3339, "2030-10-05T11:25:20+08:00")

	fmt.Printf("t1 = [%v], t2 = [%v]\n", t1, t2)
}

3.ParseInLocation从文本解析时间

package main

import (
	"fmt"
	"time"
)

func main() {
	now := time.Now()

	// 加载时区
	timezone, _ := time.LoadLocation("Asia/Shanghai")

	// 按照指定时区和指定格式解析字符串时间
	t1, _ := time.ParseInLocation("2006/01/02 15:04:05", "2030/07/20 11:25:20", timezone)

	fmt.Println(now)

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

八.练习题

1.获取当前时间,格式化输出为"2030/01/01 23:30:05"格式

package main

import (
	"fmt"
	"time"
)

func PrintTime(t time.Time) {
	// 方式一: Go语言中时间格式化的布局不是常见的Y-m-d H:M:S,而是使用 2006-01-02 15:04:05.000(记忆口诀为2006 1 2 3 4 5)
	// 温馨提示: 
	// 		1."2006/01/02 15:04:05"分别对应着年月日时分秒;
	//		2.如果只想看年则传入"2006",如果想要看月份则传入"01",如果想要看小时则传入15,以此推类;
	t1 := t.Format("2006/01/02 15:04:05")
	fmt.Printf("t1 = [%v]\n", t1)

	// 方式二: 使用Sprintf
	t2 := fmt.Sprintf("%d/%d/%d %d:%d:%d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
	fmt.Printf("t2 = [%v]\n", t2)

}

func main() {
	now := time.Now()
	PrintTime(now)
}

2.编写程序统计一段代码的执行耗时时间,单位精确到微秒。

package main

import (
	"fmt"
	"time"
)

func calctime1() {
	// 计算出纳秒
	start := time.Now().UnixNano() / 1000 
	
	fmt.Println("正在执行代码...")
	time.Sleep(time.Millisecond * 50)
	end := time.Now().UnixNano() / 1000

	fmt.Printf("in calctime1()... 耗费了%v微妙\n", end-start)

}

func calctime2() {
	start := time.Now()
	fmt.Println("正在执行代码...")
	time.Sleep(time.Millisecond * 100)

	// 注意, time.Since时内置的方法,就是拿当前的时间减去start的时间哟。
	fmt.Printf("in calctime2()... 耗费了%v\n", time.Since(start))

}

func main() {
	calctime1()
	calctime2()
}

posted @ 2024-07-19 01:01  尹正杰  阅读(428)  评论(0编辑  收藏  举报