11

Go中的time操作

 4 years ago
source link: https://studygolang.com/articles/26783
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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
复制代码

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK