Golang time模块常用示例

本文就不对官方文档做详细解析了,只贴一些常用的示例。如需查看官网点击上述链接即可。

一、时间的加减以及格式化示例:

func main()  {
	s := time.Now().Add(time.Hour * -2)
	now := fmt.Sprintf("%04d-%02d-%02d %02d:%02d:%02d", s.Year(), s.Month(), s.Day(), s.Hour(), s.Minute(), s.Second())
	fmt.Println(now)
}
func Parse(layout, value string) (Time, error)
func (t Time) Format(layout string) string

这两个函数前者用于从字符串中解析构造出Time对象,后者将Time对象重新格式化为想要的格式。
这其中最重要的是layout,layout是string类型的,类似于SQL中的YYYY-MM-DD这样的格式符。
time包自带的的layout有如下几种:

const (
	Layout      = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
	ANSIC       = "Mon Jan _2 15:04:05 2006"
	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822      = "02 Jan 06 15:04 MST"
	RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
	RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
	RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
	RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
	RFC3339     = "2006-01-02T15:04:05Z07:00"
	RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
	Kitchen     = "3:04PM"
	// Handy time stamps.
	Stamp      = "Jan _2 15:04:05"
	StampMilli = "Jan _2 15:04:05.000"
	StampMicro = "Jan _2 15:04:05.000000"
	StampNano  = "Jan _2 15:04:05.000000000"
)

如果想要自定义layout,那么只要使用这个固定的时间戳"2006-01-02T15:04:05Z07:00"进行拼接即可,示例如下:

func main() {
	mytime := "2011-02-03 00:00:00 +0000 UTC"
	t, err := time.Parse("2006-01-02 15:04:05 -0700 MST", mytime)
	fmt.Println(t, err)
}
// 2011-02-03 00:00:00 +0000 UTC <nil>

需要注意的是layout中的时间必须是这个2006年1月2号15:05:05,MST时区。
写其他的时间or时区可能会造成解析失败...

二、通过time.Date()和time.Parse(),time.Unix()快速构造time.Time类型

t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC)
t, err := time.Parse(time.RFC3339, "2009-10-23T12:04:05+08:00")
// 此处需注意,虽然time.RFC3339展示的时区前缀为Z,但实际使用时使用+号才有效,使用Z会错误解析为0000-01-01 00:00:00 +0000 UTC
t := time.Unix(<epoch time second>, 0)
t := time.UnixMicro(<epoch time microsecond>)
t := time.UnixMilli(<epoch time millisecond>)
// epoch time即unix time

三、通过time.Since()快速的计算到当前的时间

time.Since(u time)可以实现时间的快速计算,得到一个可打印的、易于人眼识别的time.Duration类型。其相当于time.Now().Sub(t)。

t, _ = time.Parse(time.RFC3339, "2020-09-30T11:04:05+08:00")
fmt.Println(time.Since(t))
// 打印结果为2h28m1.0416486s

四、时间乘法

time.Second/Hour等可以直接与数字相乘,但不能直接与数字类型的变量相乘.......这是一个很不合理、很反直觉的设计,目前只能接受,未来go团队可能改进。

变通办法为使用time.Duration将数字变量转化为一个time.Duration类型,这样就可以与time.Second相乘了。例如:

time.Since(startTime) > 24 * time.Hour * time.Duration(bc.KeepDays)

time.Second就是Duration类型,而time.Duration本质上是一个int64的数字。可以将time.Duration(数字)得到的结果看作时间计量值,乘以对应的时间单位后得到一个具体的时间长度。

五、有用的计时channel

很多时候我们需要为某个/多个任务计时,或者有每隔几秒打印日志等待任务执行完毕的需求。time包提供了实现此类需求的简易channel。

使用time.After()和time.NewTicker可以便捷的构造相关时间等待的channel和对象,接下来看两个简单示例:

func test(done chan<- bool)  {
	time.Sleep(2 * time.Second)
	done <- true
}
func main()  {
	timeOutSec := 5
	timeOutChan := time.After(time.Second * time.Duration(timeOutSec))
	// 开启一个goroutine,检测其是5秒否超时
	testDoneChan := make(chan bool)
	go test(testDoneChan)
	select {
	case <- testDoneChan:
		fmt.Println("Test Done!")
	case <- timeOutChan:
		fmt.Println("Test Time Out!")
        return
	}
}
// 如果需要同时检测多个子任务,可以把他们的doneChan放入一个waitGroup中,然后开启一个单独的goroutine和chan等待wg.Wait()完毕后写入chan。之后通过select这个chan来判断所有任务是否都已执行完毕。

  

func test(done chan<- bool)  {
	time.Sleep(10 * time.Second)
	done <- true
}
func main()  {
	ticker := time.NewTicker(time.Second * 2)
	defer ticker.Stop()
	// 开启一个goroutine,每2秒tick一次直到test执行完
	testDoneChan := make(chan bool)
	go test(testDoneChan)
	for {
		select {
		case <- testDoneChan:
			fmt.Println("Test Done!")
			return
		case t := <- ticker.C:
			fmt.Println("Current time:", t.Format(time.RFC3339))
		}
	}
}

  

posted @ 2021-12-02 17:12  realcp1018  阅读(420)  评论(0编辑  收藏  举报