Golang 常用标准库 time 1x

在编程中,我们经常会用到时间和日期,Golang 中内置的 time 包,提供了一些关于时间显示和测量用的函数

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

  • 时间类型 time.Time
  • 时间对象                                             // 时间戳:时间戳与时间对象的转换
    • time.Now()  获取当前时间然后,可以从时间对象中,获取年月日时分秒等信息
    • time.Date()  创建时间对象
      • 时区:加载时区 FixedZone() / loadLocation() 、改变时区 In()
  • 时间间隔:time.Duration
    • 时间操作:Add()、Sub()、Equal()、Before()、After()
    • 定时器  time.Tick()
  • 时间格式化  time.Format()
    • 解析字符串格式的时间:time.Parse()、time.ParseInLocation()

time 包

「 时间类型 」Golang 中,使用 time.Time 类型表示时间

  • time.Now(),可以获取当前时间对象;然后,可以从时间对象中获取年月日时分秒等信息
	// 代码示例:可以使用 time.Now(),获取当前时间对象,然后从时间对象中获取年月日时分秒等信息
	var now time.Time
	now = time.Now() // 获取当前时间对象(默认当地时区)
	fmt.Println(now) // 2022-09-26 15:05:33.349815 +0800 CST m=+0.000196251
	// 获取当前时间对象的年月日时分秒等信息
	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) // 2022 September 26 15 5 33

「 时区(Time Zone)」时区,是根据世界各国家与地区不同的经度而划分的时间定义,全球共分为24个时区

说明:中国差不多跨5个区,但是为了使用方便,只使用东八区的标准时,即北京时间为准


	// (1)加载不同的时区
	// 方式1(推荐):FixedZone,返回始终使用给定区域名称和偏移量(UTC 以东秒)的的时区
	// 中国没有夏令时,使用一个固定的8小时UTC时差;对于很多其他国家,需要考虑夏令时
	cstZone := time.FixedZone("CST", int((8 * time.Hour).Seconds())) // 东八区

	// 方式2:loadLocation,如果当前系统有时区数据库,则可以加载一个位置得到对应的时区
	// 需注意的是,windows系统上,没有安装go语言环境的情况下,time.LoadLocation会加载失败
	tokyoZone, err := time.LoadLocation("Asia/Tokyo") // 东京,东九区
	if err != nil {
		fmt.Println("load Asia/Tokyo location failed", err)
		return
	}
	fmt.Println(cstZone, tokyoZone) // CST Asia/Tokyo

	// (2)改变时区:Golang 中,并没有全局设置时区,每次输出时间都需要调用一个In()函数,改变时区
	fmt.Println(time.Now())               // 2022-09-26 15:30:29.401767 +0800 CST m=+0.000317710
	fmt.Println(time.Now().In(cstZone))   // 2022-09-26 15:30:29.401847 +0800 CST
	fmt.Println(time.Now().In(tokyoZone)) // 2022-09-26 16:30:29.401849 +0900 JST

「 time.Date() 」创建时间对象,需要指定时区,常用的有:time.Local( 当地时间 )和 time.UTC( UTC时间 )

	cstZone := time.FixedZone("CST", int((8 * time.Hour).Seconds())) // 东八区
	
	//timeInLocal := time.Date(2010, 1, 1, 20, 0, 0, 0, time.Local)  // 系统本地时间
	//fmt.Println(timeInLocal)
	timeInUTC := time.Date(2010, 1, 1, 12, 0, 0, 0, time.UTC)    // UTC时间
	fmt.Println(timeInUTC)                                       // 2010-01-01 12:00:00 +0000 UTC
	timeInBeijing := time.Date(2010, 1, 1, 20, 0, 0, 0, cstZone) // 东八区时间
	fmt.Println(timeInBeijing)                                   // 2010-01-01 20:00:00 +0800 CST

	// 另,判断两个时间是否相同:两个时间看似差了8小时,但东八区时间比UTC早8小时,所以,二者表示的是同一个时间
	timeEqual := timeInUTC.Equal(timeInBeijing)
	fmt.Println(timeEqual) // true

「 时间戳 」~,是自1970年1月1日 00:00:00 UTC 至当前时间经过的总秒数,也被称为 Unix 时间戳

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

	// time 包,还提供了一系列将 int64 位类型的时间戳转化为时间对象的方法
	timeObj := time.Unix(timestamp, 22) // 将秒级时间戳转换为时间对象( 第二个参数为不足1秒的纳秒数 )
	fmt.Println(timeObj)                // 2022-09-26 15:41:55.000000022 +0800 CST
	timeObj = time.UnixMilli(milli)     // 将毫秒级时间戳转换为时间对象
	fmt.Println(timeObj)                // 2022-09-26 15:41:55.309 +0800 CST
	timeObj = time.UnixMicro(micro)     // 将微秒级时间戳转化为时间对象
	fmt.Println(timeObj)                // 2022-09-26 15:41:55.30982 +0800 CST

「 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.Second,表示 1 秒

「 时间操作 」Golang 中,时间对象有提供以下方法:

  • Add
// 基本语法:func (t Time) Add(d Duration) Time
// 代码示例:
func main() {
	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
// 作用:判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较
// 说明:与 t==u 不同的是,这种方法还会比较地点和时区信息
  • Before
// 基本语法:func (t Time) Before(u Time) bool
// 作用:如果t代表的时间点在u之前,返回真;否则返回假
  • After
// 基本语法:func (t Time) After(u Time) bool
// 作用:如果t代表的时间点在u之后,返回真;否则返回假

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

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:年(Y)
  01:月(m)
  02:日(d)
  15:时(H)
  04:分(M)
  05:秒(S)
 另,
  如果想格式化为12小时格式,需在格式化布局中添加PM。
  小数部分想保留指定位数就写0,如果想省略末尾可能的 0 就写 9

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,因为有3个0所以格式化输出的结果也保留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"))
}

「 解析字符串格式的时间 」即,从文本的时间表示中解析出时间对象

  • 方式一:time.Parse,在解析时,不需要额外指定时区信息
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,需要在解析时,额外指定时区信息
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))
}