Go中的time操作

大漠胡萝卜 · · 4361 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

程序开发中,时间操作是不可避免的,在这里记录一下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
复制代码

有疑问加站长微信联系(非本文作者)

本文来自:掘金

感谢作者:大漠胡萝卜

查看原文:Go中的time操作

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

4361 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传