程序开发中,时间操做是不可避免的,在这里记录一下Go中常见的操做。bash
Go
中的时间最底层的数据结构为Duration
, 在Duration
的基础上,咱们定义了下面的概念:数据结构
const (
Nanosecond Duration = 1 // 纳秒,计算Duration的是使用ns
Microsecond = 1000 * Nanosecond 微秒,计算Duration的是使用us
Millisecond = 1000 * Microsecond 毫秒, 计算Duration的是使用ms
Second = 1000 * Millisecond 秒,计算Duration的是使用s
Minute = 60 * Second 分,计算Duration的是使用m
Hour = 60 * Minute 时,计算Duration的是使用h
)
复制代码
那么Duration
能够如何操做呢?函数
seconds := 10
time.Duration(seconds)*time.Second // 返回Duration结构
复制代码
ParseDutation
主要用于解析字符串,使用字符串的能够避免使用time.Duration
不方便表示的时间段。hours, _ := time.ParseDuration("10h") // 生成10个小时的duration
complex, _ := time.ParseDuration("1h10m10s") // 生成1小时10分钟10秒的duration
micro, _ := time.ParseDuration("1µs") // 生成1微妙的duration
复制代码
如何计算两个时间的时间差,返回Duration
结构?注意ui
start := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
end := time.Date(2000, 1, 1, 12, 0, 0, 0, time.UTC)
difference := end.Sub(start)
fmt.Printf("difference = %v\n", difference)
复制代码
time.Since
等价于time.Now().Sub(t)
,用于计算当前时间和以前某个时间的时间差。spa
time.Until
等价于t.Sub(time.Now())
,用于计算以后的某个时间和当前时间的时间差。code
那么Duration
究竟是什么数据结构呢?Duration
只是int64
的一种昵称,在此之上也实现多种方法,如.Hours()
,.Minutes()
,.Seconds()
等。orm
type Duration int64
复制代码
通常状况不须要设置Location
,若是要设置location
,可以在哪些地方使用呢? 首先是在time.Date
构造time.Time
的过程当中,最后一个参数设置当前时间所在时区。对象
Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location)
复制代码
那么time.Location
如何初始化呢?使用time.LoadLocation
来加载开发
location, err := time.LoadLocation("America/Los_Angeles")
timeInUTC := time.Date(2018, 8, 30, 12, 0, 0, 0, time.UTC) // time.UTC是*Location结构
复制代码
带时区的时间转化,字符串
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC) // 当前时间为UTC时间
fmt.Printf("Go launched at %s\n", t.Local()) // t.Local转化本地时间, 2009-11-11 07:00:00 +0800 CST。
复制代码
东八区怎么表示呢?
// 方法一
l,_ := time.LoadLocation("Asia/Shanghai")
// 方法二,可能用的很少,定义一个名字,而后自行计算时区+-12 * 3600
var cstZone = time.FixedZone("CST", 8*3600) // 东八
fmt.Println(time.Now().In(cstZone).Format("01-02-2006 15:04:05"))
复制代码
为何是乘3600呢?从秒开始计算,下面两行获得北京时区。
secondsEastOfUTC := int((8 * time.Hour).Seconds())
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
复制代码
type Ticker struct {
C <-chan Time // channel 每隔固定的时间会发送消息
}
复制代码
每隔固定的时间会发送信号,这个固定时间怎么获取呢?经过NewTicker接收Duration对象获取,下面代码演示了每一个1秒打印,打印10秒的功能。
ticker := time.NewTicker(time.Second)
defer ticker.Stop() // 【重要】关闭ticker
done := make(chan bool)
go func() {
time.Sleep(10 * time.Second)
done <- true
}()
for {
select {
case <-done:
fmt.Println("Done!")
return
case t := <-ticker.C:
fmt.Println("Current time: ", t)
}
}
复制代码
Time
是操纵时间的核心对象。
time.Parse(layout, string) // 获取指定字符串表明的时间
time.ParseInLocation(layout, value string, loc *Location) // 带上时区的时间
复制代码
今天开发中遇到一个问题,计算两个时间相差多少秒?
todayEnd, _ := time.Parse(timeLayout, fmt.Sprintf("%s %s", time.Now().Format("2006-01-02"), "23:59:59"))
todayStart := time.Now()
validSeds := todayEnd.Sub(todayStart).Minutes()
fmt.Println("validSeds: ", int(validSeds))
复制代码
上面的代码计算时间一直不正确,就是由于time.Parse
获取出来的时间是相对0时区的,而time.Now
使用的是本地时区,须要将其中Parse
出的代码修为下面形式:
l, _ := time.LoadLocation("Asia/Shanghai")
todayEnd, _ := time.ParseInLocation(timeLayout, fmt.Sprintf("%s %s", time.Now().Format("2006-01-02"), "23:59:59"), l)
复制代码
计算当前的时间戳
time.Unix() // 秒级 time.UnixNano() // 毫秒级
增长一个Duration
。
play
start := time.Date(2009, 1, 1, 0, 0, 0, 0, time.UTC)
oneDayLater := start.AddDate(0, 0, 1) // 增长一天
oneMonthLater := start.AddDate(0, 1, 0) // 增长一月
oneYearLater := start.AddDate(1, 0, 0) // 增长一年
复制代码
不过AddDate
均可以使用Add
+Duraion
组合解决。
比较两个时间的前后
year2000 := time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)
year3000 := time.Date(3000, 1, 1, 0, 0, 0, 0, time.UTC)
isYear3000AfterYear2000 := year3000.After(year2000) // True
isYear2000AfterYear3000 := year2000.After(year3000) // False
isYear3000BeforeYear2000 := year3000.Before(year2000) // false
isYear2000BeforeYear3000 := year2000.Before(year3000) // true
复制代码
func (t Time) Clock() (hour, min, sec int) // 返回t的时分秒
func (t Time) Date() (year int, month Month, day int) // 返回t的年月日
复制代码
t.Format 时间格式化显示
t.In 经过复制的方式,改变当前时间的时区
func (t Time) In(loc *Location) Time
复制代码
声明time.Time
未赋值,改值为January 1, year 1, 00:00:00 UTC.
分别使用本地时区生成时间, 0时区生成时间。
返回当前时区的名称和偏移0时区多少秒
t := time.Date(2009, time.November, 10, 23, 0, 0, 0, time.Local)
name, offset := t.Zone()
fmt.Println(name, offset) // CST 28800(8*3600)
复制代码
Timer
是个什么东西?最基本仍是个channel
type Timer struct {
C <-chan Time // 时间到了,发送信号,作好接收准备
}
复制代码
怎么初始化Timer
呢?
func NewTimer(d Duration) *Timer
复制代码
时间到了,要执行什么函数呢?
func AfterFunc(d Duration, f func()) *Timer 复制代码
中途若是想着stop
定时器,怎么办?
func (t *Timer) Stop() bool 复制代码
为了确保关闭?
if !t.Stop() {
<-t.C
}
复制代码
两个封装的方式相同,使用昵称的方式挂载更多的方法,是变量可以存在更多的可能性。
// Month
type Month int
const (
January Month = 1 + iota
February
March
April
May
June
July
August
September
October
November
December
)
func (m Month) String() string{}
// Weekday
type Weekday int
const (
Sunday Weekday = iota
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
)
func (d Weekday) String() string 复制代码