时间可分为时间点与时间段,golang 也不例外,提供了以下两种基础类型
- 时间点(Time)
- 时间段(Duration)
除此之外 golang 也提供了以下类型,做一些特定的业务
- 时区(Location)
- Ticker
- Timer(定时器)
1 时间点(Time)
go 针对不同的参数类型提供了以下初始化的方式
$ cat time0.go
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now())
fmt.Println(time.Now().Local())
fmt.Println(time.Now().Local().Hour())
}
输出结果
$ go run golang-time.go
2020-12-30 23:20:44.008514 +0800 CST m=+0.000139949
2020-12-30 23:20:44.008811 +0800 CST
23
$ cat time1.go
package main
import (
"fmt"
"time"
)
func main() {
// func Now() Time
fmt.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) Time
fmt.Println(time.Unix(1e9, 0))
// func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time
fmt.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.go
2020-12-30 23:22:30.977714 +0800 CST m=+0.000096359
0001-01-01 00:00:00 +0000 UTC parsing time "2020-12-30 18:22:00": month out of range
2020-12-12 15:09:09 +0800 CST <nil>
2001-09-09 09:46:40 +0800 CST
2018-01-03 15:30:10 +0800 CST
2020-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:30
fmt.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 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"
)
注意: galang 中指定的特定时间格式为 "2006-01-02 15:04:05 -0700 MST"
, 为了记忆方便,按照美式时间格式 月日时分秒年 外加时区 排列起来依次是 01/02 03:04:05PM ‘06 -0700
,刚开始使用时需要注意。
3 to time stamp
方法
func (t Time) Unix() int64
func (t Time) UnixNano() int64
$ cat time2.go
package main
import (
"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.go
1609342320
-62135596800
1609313410
4 其他
time 包还提供了一些常用的方法
func (t Time) Date() (year int, month Month, day int)
func (t Time) Clock() (hour, min, sec int)
func (t Time) Year() int
func (t Time) Month() Month
func (t Time) Day() int
func (t Time) Hour() int
func (t Time) Minute() int
func (t Time) Second() int
func (t Time) Nanosecond() int
func (t Time) YearDay() int
func (t Time) Weekday() Weekday
func (t Time) ISOWeek() (year, week int)
func (t Time) IsZero() bool
func (t Time) Local() Time
func (t Time) Location() *Location
func (t Time) Zone() (name string, offset int)
func (t Time) Unix() int64
5 时间段(Duartion)
介绍完了时间点,我们再来介绍时间段,即 Duartion 类型, 我们业务也是很常用的类型。
func (d Duration) Hours() float64
func (d Duration) Minutes() float64
func (d Duration) Seconds() float64
func (d Duration) Nanoseconds() int64
func (d Duration) Round(m Duration) Duration // 四舍五入
func (d Duration) Truncate(m Duration) Duration // 向下取整
$ cat time3.go
package main
import (
"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.go
1.5s 1.5s 1.5 1500000000
6 时区(Location)
$ cat time4.go
package main
import (
"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.go
2020-12-30 12:00:00 +0000 UTC
2020-12-30 12:00:00 +0800 CST
2020-12-30 12:00:00 -0800 PST
7 时间运算
语法:
//通过字符串,默认UTC时区初始化Time
func Parse(layout, value string) (Time, error)
//通过字符串,指定时区来初始化Time
func ParseInLocation(layout, value string, loc *Location) (Time, error)
//通过unix 标准时间初始化Time
func Unix(sec int64, nsec int64) Time
$ cat time5.go
package main
import (
"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.go
2020-12-30 23:39:34.743924 +0800 CST m=-59.999920355
2020-12-30 15:40:34.743924 +0800 CST m=-28799.999920355
2020-12-29 23:40:34.743924 +0800 CST m=-86399.999920355
##################################################
2020-12-30 23:50:34.743924 +0800 CST m=+600.000079645
2020-12-31 00:40:34.743924 +0800 CST m=+3600.000079645
2020-12-31 23:40:34.743924 +0800 CST m=+86400.000079645
##################################################
1 分钟
8 小时
1 天
$ cat time6.go
package main
import (
"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.go
720h0m0s
$ cat time7.go
package main
import (
"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.go
2023-04-01 16:09:45
2020-12-30 19:36:25
2020-12-31 11:36:25
8 比较两个时间点
$ cat time8.go
package main
import (
"fmt"
"time"
)
func main() {
dt := time.Date(2020, 12, 30, 12, 34, 45, 100, time.Local)
fmt.Println(time.Now().After(dt)) // true
fmt.Println(time.Now().Before(dt)) // false
// 是否相等 判断两个时间点是否相等时推荐使用 Equal 函数
fmt.Println(dt.Equal(time.Now()))
}
$ go run golang-time.go
true
false
false
9 Ticker类型
Ticker 类型包含一个 channel,有时我们会遇到每隔一段时间执行的业务(比如设置心跳时间等),就可以用它来处理,这是一个重复的过程。
$ cat time9.go
package main
import (
"fmt"
"time"
)
func main() {
d := time.Duration(time.Second*2)
t := time.NewTicker(d)
defer t.Stop()
for {
<- t.C
fmt.Println("timeout...")
}
}
[root@localhost time]# go run time9.go
timeout...
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.go
package main
import (
"fmt"
"time"
)
func main() {
d := time.Duration(time.Second*2)
t := time.NewTimer(d)
defer t.Stop()
for {
<- t.C
fmt.Println("timeout...")
// need reset
t.Reset(time.Second*2)
}
}
[root@localhost time]# go run time10.go
timeout...
timeout...
11 总结
package main
import (
"fmt"
"time"
)
func main() {
//time.Time代表一个纳秒精度的时间点
var t time.Time
//返回当前时间:2020-12-30 23:48:37.311332 +0800 CST m=+0.000068759
t = time.Now()
fmt.Printf("%v\n", t)
//返回所在时区:Local
fmt.Printf("%v\n", t.Location())
//返回UTC时间和UTC时区:2020-12-30 15:48:37.311332 +0000 UTC UTC
fmt.Printf("%v %v\n", t.UTC(), t.UTC().Location())
//同上,In()返回指定时区的时间:2020-12-30 15:48:37.311332 +0000 UTC UTC
fmt.Printf("%v %v\n", t.In(time.UTC), t.In(time.UTC).Location())
//返回当地时区的时间:2020-12-30 23:48:37.311332 +0800 CST Local
fmt.Printf("%v %v\n", t.Local(), t.Local().Location())
//根据时间戳返回本地时间,参数分别表示秒数和纳秒数
//2023-06-26 19:46:50 +0800 CST
t2 := time.Unix(1687780010, 0)
fmt.Println(t2)
//根据指定时间返回time.Time,分别指定年,月,日,时,分,秒,纳秒,时区
//2020-05-26 15:30:20 +0800 CST
t3 := time.Date(2020, time.Month(5), 26, 15, 30, 20, 0, t.Location())
fmt.Println(t3)
//格式化输出时间:2020-12-30 23:49:51
t4 := time.Now()
fmt.Println(t4.Format("2006-01-02 15:04:05"))
//获取时间信息:2020-12-30 23:49:51
t5 := time.Now()
//返回日期:2020 December 30
fmt.Println(t5.Date())
//返回年:2020
fmt.Println(t5.Year())
//返回月:December
fmt.Println(t5.Month())
//返回日:30
fmt.Println(t5.Day())
//返回星期:Wednesday
fmt.Println(t5.Weekday())
//返回ISO 9601标准下的年份和星期编号:2020 53
fmt.Println(t5.ISOWeek())
//返回时分秒:23 49 51
fmt.Println(t5.Clock())
//返回小时:23
fmt.Println(t5.Hour())
//返回分钟:49
fmt.Println(t5.Minute())
//返回秒:51
fmt.Println(t5.Second())
//返回纳秒:222602000
fmt.Println(t5.Nanosecond())
//返回一年中对应的天:365
fmt.Println(t5.YearDay())
//返回时区的规范名,时区相对于UTC的时间偏移量(秒):CST 28800
fmt.Println(t5.Zone())
//返回时间戳:1609343391
fmt.Println(t5.Unix())
//返回纳秒时间戳:1609343391222602000
fmt.Println(t5.UnixNano())
//时间的比较与计算
t6 := time.Now()
//是否零时时间:false
fmt.Println(t6.IsZero())
//t6时间在t5时间之后,返回真:true
fmt.Println(t6.After(t5))
//t5时间在t6时间之前,返回真:true
fmt.Println(t5.Before(t6))
//时间是否相同:true
fmt.Println(t6.Equal(t6))
//返回t6加上纳秒的时间:2020-12-30 23:49:51.222631 +0800 CST m=+0.000295290
fmt.Println(t6.Add(10000))
//返回两个时间之差的纳秒数:18.768µs
fmt.Println(t6.Sub(t5))
//返回t6加1年,1月,1天的时间:2022-01-31 23:49:51.222621 +0800 CST
fmt.Println(t6.AddDate(1, 1, 1))
//时间的序列化
t7 := time.Now()
//序列化二进制
bin, _ := t7.MarshalBinary()
//反序列化二进制:2020-12-30 23:49:51.222631 +0800 CST
t7.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 CST
t7.UnmarshalJSON(json)
fmt.Println(t7)
//序列化文本:2020-12-30T23:49:51.222631+08:00
txt, _ := t7.MarshalText()
fmt.Println(string(txt))
//反序列化文本:2020-12-30 23:49:51.222631 +0800 CST
t7.UnmarshalText(txt)
fmt.Println(t7)
//gob编码:2020-12-30 23:49:51.222631 +0800 CST
gob, _ := t7.GobEncode()
t7.GobDecode(gob)
fmt.Println(t7)
//时间段time.Duration
dur := time.Duration(6666666600000)
//返回字符串表示:1h51m6.6666s
fmt.Println(dur.String())
//返回小时表示:1.8518518333333334
fmt.Println(dur.Hours())
//返回分钟表示:111.11111
fmt.Println(dur.Minutes())
//返回秒表示:6666.6666
fmt.Println(dur.Seconds())
//返回纳秒表示:6666666600000
fmt.Println(dur.Nanoseconds())
//时区time.Location,返回时区名:local
fmt.Println(time.Local.String())
//通过地点名和时间偏移量返回时区:Shanghai
fmt.Println(time.FixedZone("Shanghai", 800))
//通过给定时区名称,返回时区:Asia/Shanghai
loc, _ := time.LoadLocation("Asia/Shanghai")
fmt.Println(loc)
//阻塞当前进程3秒
time.Sleep(time.Second * 3)
//定时器time.Timer,创建一个1秒后触发定时器
timer1 := time.NewTimer(time.Second * 1)
<-timer1.C
fmt.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 := 1
for {
if num > 5 {
ticker.Stop()
break
}
select {
case <-ticker.C:
num++
fmt.Println("1 second...")
}
}
}
12 实用场景
t := 5
time.Sleep(time.Second * 5) // ok 正常
time.Sleep(time.Second * t) // error 出现标题错误提示
time.Sleep(time.Second * time.Duration(t)) // ok 应该这样转
13 时间的格式化和解析
package main
import "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:00
2012-11-01 22:08:41 +0000 +0000
11:06AM
Mon Nov 23 11:06:33 2020
2020-11-23T11:06:33.251533+08:00
0000-01-01 20:41:00 +0000 UTC
2020-11-23T11:06:33-00:00
parsing 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