时间可分为时间点与时间段,golang 也不例外,提供了以下两种基础类型
- 时间点(Time)
- 时间段(Duration)
除此之外 golang 也提供了以下类型,做一些特定的业务
- 时区(Location)
- Ticker
- Timer(定时器)
1 时间点(Time)
go 针对不同的参数类型提供了以下初始化的方式
$ cat time0.gopackage mainimport ("fmt""time")func main() {fmt.Println(time.Now())fmt.Println(time.Now().Local())fmt.Println(time.Now().Local().Hour())}输出结果$ go run golang-time.go2020-12-30 23:20:44.008514 +0800 CST m=+0.0001399492020-12-30 23:20:44.008811 +0800 CST23
$ cat time1.gopackage mainimport ("fmt""time")func main() {// func Now() Timefmt.Println(time.Now())// func Parse(layout, value string) (Time, error)fmt.Println(time.Parse("2016-01-02 15:04:05", "2020-12-30 18:22:00"))// func ParseInLocation(layout, value string, loc *Location) (Time, error) (layout已带时区时可直接用Parse)fmt.Println(time.ParseInLocation("2006-01-02 15:04:05", "2020-12-12 15:09:09", time.Local))// func Unix(sec int64, nsec int64) Timefmt.Println(time.Unix(1e9, 0))// func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Timefmt.Println(time.Date(2018, 1, 3, 15, 30, 10, 0, time.Local))// func (t Time) In(loc *Location) Time 当前时间对应指定时区的时间loc, _ := time.LoadLocation("America/Los_Angeles")fmt.Println(time.Now().In(loc))}$ go run golang-time.go2020-12-30 23:22:30.977714 +0800 CST m=+0.0000963590001-01-01 00:00:00 +0000 UTC parsing time "2020-12-30 18:22:00": month out of range2020-12-12 15:09:09 +0800 CST <nil>2001-09-09 09:46:40 +0800 CST2018-01-03 15:30:10 +0800 CST2020-12-30 07:22:30.977961 -0800 PST
2 格式化
to string
格式化为字符串我们需要使用 time.Format 方法来转换成我们想要的格式
fmt.Println(time.Now().Format("2006-01-02 15:04:05")) // 2020-12-30 23:22:30fmt.Println(time.Now().Format(time.UnixDate)) // Wed Dec 30 23:25:46 CST 2020
复制代码Format 函数中可以指定你想使用的格式,同时 time 包中也给了一些我们常用的格式
const (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 zoneRFC850 = "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 zoneRFC3339 = "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")
注意: galang 中指定的特定时间格式为 "2006-01-02 15:04:05 -0700 MST", 为了记忆方便,按照美式时间格式 月日时分秒年 外加时区 排列起来依次是 01/02 03:04:05PM ‘06 -0700,刚开始使用时需要注意。
3 to time stamp
方法
func (t Time) Unix() int64func (t Time) UnixNano() int64
$ cat time2.gopackage mainimport ("fmt""time")func main() {fmt.Println(time.Now().Unix())// 获取指定日期的时间戳dt, _ := time.Parse("2016-01-02 15:04:05", "2020-12-30 12:24:51")fmt.Println(dt.Unix())fmt.Println(time.Date(2020, 12, 30, 15, 30, 10, 0, time.Local).Unix())}$ go run time2.go1609342320-621355968001609313410
4 其他
time 包还提供了一些常用的方法
func (t Time) Date() (year int, month Month, day int)func (t Time) Clock() (hour, min, sec int)func (t Time) Year() intfunc (t Time) Month() Monthfunc (t Time) Day() intfunc (t Time) Hour() intfunc (t Time) Minute() intfunc (t Time) Second() intfunc (t Time) Nanosecond() intfunc (t Time) YearDay() intfunc (t Time) Weekday() Weekdayfunc (t Time) ISOWeek() (year, week int)func (t Time) IsZero() boolfunc (t Time) Local() Timefunc (t Time) Location() *Locationfunc (t Time) Zone() (name string, offset int)func (t Time) Unix() int64
5 时间段(Duartion)
介绍完了时间点,我们再来介绍时间段,即 Duartion 类型, 我们业务也是很常用的类型。
func (d Duration) Hours() float64func (d Duration) Minutes() float64func (d Duration) Seconds() float64func (d Duration) Nanoseconds() int64func (d Duration) Round(m Duration) Duration // 四舍五入func (d Duration) Truncate(m Duration) Duration // 向下取整
$ cat time3.gopackage mainimport ("fmt""time")func main() {tp, _ := time.ParseDuration("1.5s")fmt.Println(tp.Truncate(1000), tp.Round(100), tp.Seconds(), tp.Nanoseconds())}$ go run golang-time.go1.5s 1.5s 1.5 1500000000
6 时区(Location)
$ cat time4.gopackage mainimport ("fmt""time")func main() {loc1, err := time.LoadLocation("")if err != nil {fmt.Print("time location error")}fmt.Println(time.Date(2020, 12, 30, 12, 0, 0, 0, loc1))loc2, err := time.LoadLocation("Local")fmt.Println(time.Date(2020, 12, 30, 12, 0, 0, 0, loc2))local, _ := time.LoadLocation("America/Los_Angeles")fmt.Println(time.Date(2020, 12, 30, 12, 0, 0, 0, local))}$ go run golang-time.go2020-12-30 12:00:00 +0000 UTC2020-12-30 12:00:00 +0800 CST2020-12-30 12:00:00 -0800 PST
7 时间运算
语法:
//通过字符串,默认UTC时区初始化Timefunc Parse(layout, value string) (Time, error)//通过字符串,指定时区来初始化Timefunc ParseInLocation(layout, value string, loc *Location) (Time, error)//通过unix 标准时间初始化Timefunc Unix(sec int64, nsec int64) Time
$ cat time5.gopackage mainimport ("fmt""strings""time")func main() {now := time.Now()m, _ := time.ParseDuration("-1m")m1 := now.Add(m)fmt.Println(m1)// 8个小时前h, _ := time.ParseDuration("-1h")h1 := now.Add(8 * h)fmt.Println(h1)// 一天前d, _ := time.ParseDuration("-24h")d1 := now.Add(d)fmt.Println(d1)printSplit(50)// 10分钟后mm, _ := time.ParseDuration("1m")mm1 := now.Add(mm)fmt.Println(mm1)// 8小时后hh, _ := time.ParseDuration("1h")hh1 := now.Add(hh)fmt.Println(hh1)// 一天后dd, _ := time.ParseDuration("24h")dd1 := now.Add(dd)fmt.Println(dd1)printSplit(50)// Sub 计算两个时间差subM := now.Sub(m1)fmt.Println(subM.Minutes(), "分钟")sumH := now.Sub(h1)fmt.Println(sumH.Hours(), "小时")sumD := now.Sub(d1)fmt.Printf("%v 天\n", sumD.Hours()/24)}func printSplit(count int) {fmt.Println(strings.Repeat("#", count))}
输出:
$ go run golang-time.go2020-12-30 23:39:34.743924 +0800 CST m=-59.9999203552020-12-30 15:40:34.743924 +0800 CST m=-28799.9999203552020-12-29 23:40:34.743924 +0800 CST m=-86399.999920355##################################################2020-12-30 23:50:34.743924 +0800 CST m=+600.0000796452020-12-31 00:40:34.743924 +0800 CST m=+3600.0000796452020-12-31 23:40:34.743924 +0800 CST m=+86400.000079645##################################################1 分钟8 小时1 天
$ cat time6.gopackage mainimport ("fmt""time")func main() {dt1 := time.Date(2020, 12, 30, 12, 40, 30, 30, time.Local)dt2 := time.Date(2020, 11, 30, 12, 40, 30, 30, time.Local)// 不用关注时区,go会转换成时间戳进行计算fmt.Println(dt1.Sub(dt2))}$ go run golang-time.go720h0m0s
$ cat time7.gopackage mainimport ("fmt""time")func main() {local, _ := time.LoadLocation("America/Los_Angeles")timeFormat := "2006-01-02 15:04:05"//func Unix(sec int64, nsec int64) Time {time1 := time.Unix(1680390585, 0) //通过unix标准时间的秒,纳秒设置时间time2, _ := time.ParseInLocation(timeFormat, "2020-12-30 19:36:25", local) //洛杉矶时间fmt.Println(time1.In(local).Format(timeFormat))fmt.Println(time2.In(local).Format(timeFormat))chinaLocal, _ := time.LoadLocation("Local") //运行时,该服务器必须设置为中国时区,否则最好是采用"Asia/Chongqing"之类具体的参数。fmt.Println(time2.In(chinaLocal).Format(timeFormat))}$ go run golang-time.go2023-04-01 16:09:452020-12-30 19:36:252020-12-31 11:36:25
8 比较两个时间点
$ cat time8.gopackage mainimport ("fmt""time")func main() {dt := time.Date(2020, 12, 30, 12, 34, 45, 100, time.Local)fmt.Println(time.Now().After(dt)) // truefmt.Println(time.Now().Before(dt)) // false// 是否相等 判断两个时间点是否相等时推荐使用 Equal 函数fmt.Println(dt.Equal(time.Now()))}$ go run golang-time.gotruefalsefalse
9 Ticker类型
Ticker 类型包含一个 channel,有时我们会遇到每隔一段时间执行的业务(比如设置心跳时间等),就可以用它来处理,这是一个重复的过程。
$ cat time9.gopackage mainimport ("fmt""time")func main() {d := time.Duration(time.Second*2)t := time.NewTicker(d)defer t.Stop()for {<- t.Cfmt.Println("timeout...")}}[root@localhost time]# go run time9.gotimeout...timeout...timeout...timeout...
10 Timer类型
Timer 类型用来代表一个单独的事件,当设置的时间过期后,发送当前的时间到 channel, 我们可以通过以下两种方式来创建
func AfterFunc(d Duration, f func()) *Timer // 指定一段时间后指定的函数func NewTimer(d Duration) *Timer
以上两函数都可以使用 Reset, 这个有个需要注意的地方是使用 Reset 时需要确保 t.C 通道被释放时才能调用,以防止发生资源竞争的问题,可通过以下方式解决
if !t.Stop() {<-t.C}t.Reset(d)
cat time10.gopackage mainimport ("fmt""time")func main() {d := time.Duration(time.Second*2)t := time.NewTimer(d)defer t.Stop()for {<- t.Cfmt.Println("timeout...")// need resett.Reset(time.Second*2)}}[root@localhost time]# go run time10.gotimeout...timeout...
11 总结
package mainimport ("fmt""time")func main() {//time.Time代表一个纳秒精度的时间点var t time.Time//返回当前时间:2020-12-30 23:48:37.311332 +0800 CST m=+0.000068759t = time.Now()fmt.Printf("%v\n", t)//返回所在时区:Localfmt.Printf("%v\n", t.Location())//返回UTC时间和UTC时区:2020-12-30 15:48:37.311332 +0000 UTC UTCfmt.Printf("%v %v\n", t.UTC(), t.UTC().Location())//同上,In()返回指定时区的时间:2020-12-30 15:48:37.311332 +0000 UTC UTCfmt.Printf("%v %v\n", t.In(time.UTC), t.In(time.UTC).Location())//返回当地时区的时间:2020-12-30 23:48:37.311332 +0800 CST Localfmt.Printf("%v %v\n", t.Local(), t.Local().Location())//根据时间戳返回本地时间,参数分别表示秒数和纳秒数//2023-06-26 19:46:50 +0800 CSTt2 := time.Unix(1687780010, 0)fmt.Println(t2)//根据指定时间返回time.Time,分别指定年,月,日,时,分,秒,纳秒,时区//2020-05-26 15:30:20 +0800 CSTt3 := time.Date(2020, time.Month(5), 26, 15, 30, 20, 0, t.Location())fmt.Println(t3)//格式化输出时间:2020-12-30 23:49:51t4 := time.Now()fmt.Println(t4.Format("2006-01-02 15:04:05"))//获取时间信息:2020-12-30 23:49:51t5 := time.Now()//返回日期:2020 December 30fmt.Println(t5.Date())//返回年:2020fmt.Println(t5.Year())//返回月:Decemberfmt.Println(t5.Month())//返回日:30fmt.Println(t5.Day())//返回星期:Wednesdayfmt.Println(t5.Weekday())//返回ISO 9601标准下的年份和星期编号:2020 53fmt.Println(t5.ISOWeek())//返回时分秒:23 49 51fmt.Println(t5.Clock())//返回小时:23fmt.Println(t5.Hour())//返回分钟:49fmt.Println(t5.Minute())//返回秒:51fmt.Println(t5.Second())//返回纳秒:222602000fmt.Println(t5.Nanosecond())//返回一年中对应的天:365fmt.Println(t5.YearDay())//返回时区的规范名,时区相对于UTC的时间偏移量(秒):CST 28800fmt.Println(t5.Zone())//返回时间戳:1609343391fmt.Println(t5.Unix())//返回纳秒时间戳:1609343391222602000fmt.Println(t5.UnixNano())//时间的比较与计算t6 := time.Now()//是否零时时间:falsefmt.Println(t6.IsZero())//t6时间在t5时间之后,返回真:truefmt.Println(t6.After(t5))//t5时间在t6时间之前,返回真:truefmt.Println(t5.Before(t6))//时间是否相同:truefmt.Println(t6.Equal(t6))//返回t6加上纳秒的时间:2020-12-30 23:49:51.222631 +0800 CST m=+0.000295290fmt.Println(t6.Add(10000))//返回两个时间之差的纳秒数:18.768µsfmt.Println(t6.Sub(t5))//返回t6加1年,1月,1天的时间:2022-01-31 23:49:51.222621 +0800 CSTfmt.Println(t6.AddDate(1, 1, 1))//时间的序列化t7 := time.Now()//序列化二进制bin, _ := t7.MarshalBinary()//反序列化二进制:2020-12-30 23:49:51.222631 +0800 CSTt7.UnmarshalBinary(bin)fmt.Println(t7)//序列化json:"2020-12-30T23:49:51.222631+08:00"json, _ := t7.MarshalJSON()fmt.Println(string(json))//反序列化json:2020-12-30 23:49:51.222631 +0800 CSTt7.UnmarshalJSON(json)fmt.Println(t7)//序列化文本:2020-12-30T23:49:51.222631+08:00txt, _ := t7.MarshalText()fmt.Println(string(txt))//反序列化文本:2020-12-30 23:49:51.222631 +0800 CSTt7.UnmarshalText(txt)fmt.Println(t7)//gob编码:2020-12-30 23:49:51.222631 +0800 CSTgob, _ := t7.GobEncode()t7.GobDecode(gob)fmt.Println(t7)//时间段time.Durationdur := time.Duration(6666666600000)//返回字符串表示:1h51m6.6666sfmt.Println(dur.String())//返回小时表示:1.8518518333333334fmt.Println(dur.Hours())//返回分钟表示:111.11111fmt.Println(dur.Minutes())//返回秒表示:6666.6666fmt.Println(dur.Seconds())//返回纳秒表示:6666666600000fmt.Println(dur.Nanoseconds())//时区time.Location,返回时区名:localfmt.Println(time.Local.String())//通过地点名和时间偏移量返回时区:Shanghaifmt.Println(time.FixedZone("Shanghai", 800))//通过给定时区名称,返回时区:Asia/Shanghailoc, _ := time.LoadLocation("Asia/Shanghai")fmt.Println(loc)//阻塞当前进程3秒time.Sleep(time.Second * 3)//定时器time.Timer,创建一个1秒后触发定时器timer1 := time.NewTimer(time.Second * 1)<-timer1.Cfmt.Println("timer1 end")//1秒后运行函数time.AfterFunc(time.Second*1, func() {fmt.Println("wait 1 second")})time.Sleep(time.Second * 3)//打点器time.Ticker,创建一个打点器,在固定1秒内重复执行ticker := time.NewTicker(time.Second)num := 1for {if num > 5 {ticker.Stop()break}select {case <-ticker.C:num++fmt.Println("1 second...")}}}
12 实用场景
t := 5time.Sleep(time.Second * 5) // ok 正常time.Sleep(time.Second * t) // error 出现标题错误提示time.Sleep(time.Second * time.Duration(t)) // ok 应该这样转
13 时间的格式化和解析
package mainimport "fmt"import "time"func main() {p := fmt.Println// 这里是一个基本的按照 RFC3339 进行格式化的例子,使用// 对应模式常量。t := time.Now()p(t.Format(time.RFC3339))// 时间解析使用同 `Format` 相同的形式值。t1, e := time.Parse(time.RFC3339,"2012-11-01T22:08:41+00:00")p(t1)// `Format` 和 `Parse` 使用基于例子的形式来决定日期格式,// 一般你只要使用 `time` 包中提供的模式常量就行了,但是你// 也可以实现自定义模式。模式必须使用时间 `Mon Jan 2 15:04:05 MST 2006`// 来指定给定时间/字符串的格式化/解析方式。时间一定要按照// 如下所示:2006为年,15 为小时,Monday 代表星期几,等等。p(t.Format("3:04PM"))p(t.Format("Mon Jan _2 15:04:05 2006"))p(t.Format("2006-01-02T15:04:05.999999-07:00"))form := "3 04 PM"t2, e := time.Parse(form, "8 41 PM")p(t2)// 对于纯数字表示的时间,你也可以使用标准的格式化字// 符串来提出出时间值得组成。fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",t.Year(), t.Month(), t.Day(),t.Hour(), t.Minute(), t.Second())// `Parse` 函数在输入的时间格式不正确是会返回一个// 错误。ansic := "Mon Jan _2 15:04:05 2006"_, e = time.Parse(ansic, "8:41PM")p(e)}
输出结果:
2020-11-23T11:06:33+08:002012-11-01 22:08:41 +0000 +000011:06AMMon Nov 23 11:06:33 20202020-11-23T11:06:33.251533+08:000000-01-01 20:41:00 +0000 UTC2020-11-23T11:06:33-00:00parsing time "8:41PM" as "Mon Jan _2 15:04:05 2006": cannot parse "8:41PM" as "Mon"
参考连接:
https://juejin.im/post/5ae32a8651882567105f7dd3
http://static.markbest.site/blog/92.html
Time 类型详解
https://blog.csdn.net/xixihahalelehehe/article/details/104540727?ops_request_misc=%25257B%252522request%25255Fid%252522%25253A%252522160932314316780288745853%252522%25252C%252522scm%252522%25253A%25252220140713.130102334.pc%25255Fblog.%252522%25257D&request_id=160932314316780288745853&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v1~rank_blog_v1-1-104540727.pc_v1_rank_blog_v1&utm_term=time
