程序开发中,时间操作是不可避免的,在这里记录一下Go中常见的操作。
Duration
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
可以如何操作呢?
- time.Duration
seconds := 10
time.Duration(seconds)*time.Second // 返回Duration结构
复制代码
- time.ParseDuration
ParseDutation
主要用于解析字符串,使用字符串的可以避免使用time.Duration
不方便表示的时间段。
hours, _ := time.ParseDuration("10h") // 生成10个小时的duration
complex, _ := time.ParseDuration("1h10m10s") // 生成1小时10分钟10秒的duration
micro, _ := time.ParseDuration("1µs") // 生成1微妙的duration
复制代码
- time.Sub
如何计算两个时间的时间差,返回Duration
结构?注意
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.Since
等价于time.Now().Sub(t)
,用于计算当前时间和之前某个时间的时间差。
- time.Until
time.Until
等价于t.Sub(time.Now())
,用于计算之后的某个时间和当前时间的时间差。
那么Duration
到底是什么数据结构呢?Duration
只是int64
的一种昵称,在此之上也实现多种方法,如.Hours()
,.Minutes()
,.Seconds()
等。
type Duration int64
复制代码
Location
一般情况不需要设置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)
复制代码
Ticker
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
是操纵时间的核心对象。
- time.Parse,time.ParseInLocation
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
计算当前的时间戳
time.Unix() // 秒级 time.UnixNano() // 毫秒级
- time.Add
增加一个Duration
。
- time.AddDate
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
组合解决。
- t.After,t.Before
比较两个时间的先后
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
复制代码
- t.Date, t.Clock
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
复制代码
- t.IsZero
声明time.Time
未赋值,改值为January 1, year 1, 00:00:00 UTC.
- t.Local, t.UTC
分别使用本地时区生成时间, 0时区生成时间。
- t.Zone()
返回当前时区的名称和偏移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
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、Weekday
两个封装的方式相同,使用昵称的方式挂载更多的方法,是变量能够存在更多的可能性。
// 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
复制代码
有疑问加站长微信联系(非本文作者)