43

Go package(1) time 用法

 4 years ago
source link: https://www.tuicool.com/articles/BJB7Frr
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.

Go package(1) time 用法

golang使用的版本:

go version go1.10.3

一:功能介绍

time的一些功能,比如时区,像linux中的定时器,时间计算等

  • 格式化时间
  • 时区(Location)
  • 时间计算
  • Ticker
  • Timer(定时器)

Time一般分为时间Time 和 时段Duration

二:Time 结构体

time结构体定义:

type Time struct {
    wall unit64     //表示距离公元1年1月1日00:00:00UTC的秒数
    ext  int64      //表示纳秒
    loc  *Location  //代表时区,主要处理偏移量。因为不同的时区,对应的时间不一样
}

上面的loc表示时区, 那什么是时区呢?

因为地球是圆的,所以同一个时刻,在地球的一边是白天,一边是黑夜。而因为人类使用一天 24 小时的制度,所以,在地球对角的两边就应该差了 12 的小时才对。由于同一个时间点上面, 整个地球的时间应该都不一样,为了解决这个问题,所以可以想见的,地球就被分成 24 个时区了,

因为绕地球一圈是 360 度角,这 360 度角共分为 24 个时区,当然一个时区就是 15 度角啦! 又由于是以格林威治时间为标准时间( Greenwich Mean Time, GMT 时间),加上地球自转的关系,因此,在格林威治以东的区域时间是比较快的(+小时), 而以西的地方当然就是较慢啰!

UTC又是什么 ?

在计算时间的时候,最准确的计算应该是使用‘原子震荡周期’所计算的物理时钟了 (Atomic Clock, 也被称为原子钟),这也被定义为标准时间 (International Atomic Time)。而我们常常看见的 UTC 也就是 Coordinated Universal Time (协和标准时间)就是利用这种 Atomic Clock 为基准所定义出来的正确时间。例如 1999 年在美国启用的原子钟 NIST F-1, 他所产生的时间误差每两千年才差一秒钟!真的是很准呐! 这个 UTC 标准时间是以 GMT 这个时区为主的喔!所以本地时间与 UTC 时间的时差就是本地时间与 GMT 时间的时差就是了

UTC + 时区差 = 本地时间,

国内一般使用的是北京时间,与UTC的时间关系如下:

UTC + 8个小时 = 北京时间

更多关于时间的内容请查看 鸟哥的私房菜

初始化Time (struct)

下面的这些函数都是返回结构体Time,相当于把不同类型的日期格式初始化为结构体Time

  • 当前时间
func Now() Time

例子1:

fmt.Println(time.Now())
//output: 2019-04-25 23:15:12.2473056 +0800 CST m=+0.042979701

fmt.Println(time.Now().Year(), time.Now().Month())
//output: 2019 April

从上面可以看出,Now()返回的是一个+0800 CST 的时间

  • Parse 将字符串转换为Time类型
func Parse(layout, value string, defaultLocation, local *Location) (Time, error)

layout 定义输入的时间格式,value 的时间格式需与 layout 保持一致

例子1:

fmt.Println(time.Parse("2006-01-02 15:04:05", "2018-04-23 00:00:23"))
//output: 2018-04-23 00:00:23 +0000 UTC <nil>

从上面示例可以看出,Parse()默认返回的是+0000 UTC 时间

  • ParseInLocation 功能与 Parse 类似,但有两个重要的不同之处:

    • 第一,当缺少时区信息时,Parse 将时间解释为 UTC 时间,而 ParseInLocation 将返回值的 Location 设置为 loc;
    • 第二,当时间字符串提供了时区偏移量信息时,Parse 会尝试去匹配本地时区,而 ParseInLocation 会去匹配 loc。
func ParseInLocation(layout, value string, loc *Location) (Time, error)

例子1:

fmt.Println(time.ParseInLocation("2006-01-02 15:04:05", "2017-05-11 14:06:06", time.Local))
//output: 2017-05-11 14:06:06 +0800 CST <nil>
  • Unix

根据秒和纳秒返回一个时间

func Unix(sec int64, nsec int64) Time

例子1:

fmt.Println(time.Unix(1e9, 0))
//output:2001-09-09 09:46:40 +0800 CST
  • Date
func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

例子1:

fmt.Println(time.Date(2018, 1, 2, 15, 30, 10, 0, time.Local))
//output: 2018-01-02 15:30:10 +0800 CST
  • Local

返回本地时间

func (t Time) Local() Time

例子1:

fmt.Println(time.Now())
fmt.Println(time.Now().Local())
//output:  2019-03-26 00:51:19.5597562 +0800 CST m=+0.006832001
//output:  2019-03-26 00:51:19.5987973 +0800 CST

其他的返回Time的方法,请到 godoc 查看time方法列表

三:时间的格式化

  • Format

把时间(string)转化为string格式

func (t Time) Format(layout string) string

例子1:

fmt.Println(time.Now().Format("2006-01-02 15:04:05"))
fmt.Println(time.Now().Format("2006/01/02"))
//2019-03-26 01:20:55
//2019/03/26

const TimeFormat = "15:04:05"
fmt.Println(time.Now().Format(TimeFormat))
//02:05:52

const MicroFormat = "2006/01/02 15:04:05.000000"
fmt.Println(time.Now().Format(MicroFormat))
//2019/03/26 02:07:45.051045
  • 返回Unix时间戳
func (t Time) Unix() int64

例子1:返回现在时间的时间戳

fmt.Println(time.Now().Unix())
// 1553580240

例子2:返回指定格式日期的时间戳

t, _ := time.Parse("2006-01-02 15:04:05", "2018-03-23 00:00:23")
fmt.Println(t.Unix())
//1524441623
  • 时间戳转日期
Unix(sec int64, nsec int64) Time

把时间time转化为日期date

例子1:

fmt.Println(time.Unix(time.Now().Unix(), 0))
//2019-03-26 02:03:45 +0800 CST
  • 返回年月日星期

返回Time结构体后,就可以调用Time的一些方法得到年月日

例子1:

t := time.Now()
fmt.Println(t.Year())
fmt.Println(t.Month())
fmt.Println(t.Day())
fmt.Pritnln(t.Weekday())
  • 年月日返回日期

用Date() 函数实现

例子1:

t := time.Date(2012, 2, 20, 23, 59, 59, 0, time.UTC)
fmt.Println(t)
//2012-02-20 23:59:59 +0000 UTC

t = time.Date(2012, 2, 20, 23, 59, 59, 0, time.Local)
fmt.Println(t)
//2012-02-20 23:59:59 +0800 CST

Date()函数后面还可以加一个时区参数,得到相关时区的日期

四:时区

  • 设置时区的函数
LoadLocation(name string) (*Location, error)

例子1:

loc, _ := time.LoadLocation("Asia/Shanghai") //设置时区
t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2012-02-20 15:07:51", loc)
fmt.Println(t)
fmt.Println(t.Unix()) //获取时间戳
//2012-02-20 15:07:51 +0800 CST
//1329721671

例子2:

loc, _ := time.LoadLocation("Asia/Shanghai") //设置时区
t := time.Unix(1329721671, 0)
fmt.Println(t.In(loc).Format("2006-01-02 15:04:05"))
//2012-02-20 15:07:51
  • LoadLocation函数的一些常用参数
loc, err := time.LoadLocation("")     //默认UTC时间
loc, err := time.LoadLocation("local") //服务器设定本地时区,一般为CST
loc, err := time.LoadLocation("Asia/Shanghai") //设置指定时区,指定为亚洲上海时区

五:时间段

  • 1、Duration 定义
type Duration int64

定义了以下持续时间类型.多用于时间的加减需要传入Duration做为参数的时候

const (
    Nanosecond  Duration = 1
    Microsecond          = 1000 * Nanosecond
    Millisecond          = 1000 * Microsecond
    Second               = 1000 * Millisecond
    Minute               = 60 * Second
    Hour                 = 60 * Minute
)

例子1:

这个我们写一个完整的例子

package main

import (
    "fmt"
    "reflect"
    "time"
)

func main() {
    fmt.Println(reflect.TypeOf(1))
    fmt.Println(reflect.TypeOf(1 * time.Second))
}
//int
//time.Duration
  • 2、将duration字符串转化为Duration类型
func ParseDuration(s string) (Duration, error)

例子2:

td, _ := time.ParseDuration("2h20m")
fmt.Println(td)
fmt.Println("min:", td.Minutes(), "second:", td.Seconds())
//min: 140 second: 8400

六:时间计算

相加

  • 1、根据时间段Duration相加
func (t Time) Add(d Duration) Time

例子1:

t := time.Date(2012, 2, 20, 23, 59, 59, 0, time.Local)
fmt.Println(t)

t = t.Add(60 * time.Second) //加60秒
fmt.Println(t)

t = t.Add(1 * time.Hour)  //加1小时
fmt.Println(t)

//output:
//2012-02-20 23:59:59 +0800 CST
//2012-02-21 00:00:59 +0800 CST
//2012-02-21 00:59:59 +0800 CST
  • 2、根据年,月,日来相加
func (t Time) AddDate(years int, months int, days int) Time

例子2:

t = time.Date(2019, 3, 25, 23, 59, 59, 0, time.Local)
t2 := t.AddDate(0, 0, 1) //增加 1日
fmt.Println(t2)

t2 = t.AddDate(2, 0, 0) //增加 2年
fmt.Println(t2)

//output:
//2019-03-26 23:59:59 +0800 CST
//2021-03-25 23:59:59 +0800 CST

相减

  • 1、计算2个时间的时差 (参数 t-u)
func (t Time) Sub(u Time) Duration
  • 2、返回与当前时间的时间差 (Now - t)
func Since(t Time) Duration:

例子1:

t := time.Date(2019, 4, 25, 23, 59, 59, 0, time.Local)
fmt.Println(t)
sub := t.Sub(time.Now())  // t - time.Now()
fmt.Println(sub)

sub = time.Since(t) //time.Now() - t, 相当于time.Now().Sub(t)
fmt.Println(sub)
  • 3、与当前时间相减 (t - Now)
func Until(t Time) Duration

函数原型

// Until returns the duration until t.
// It is shorthand for t.Sub(time.Now()).
func Until(t Time) Duration {
    return t.Sub(Now())
}

例子1:

t := time.Date(2019, 3, 25, 23, 59, 59, 0, time.Local)
fmt.Println(t)
t3 := time.Until(t)
fmt.Println(t3) //相当于 t - Now() 相当于 t.Sub(time.Now())

比较

  • 时间t是否在u之前
func (t Time) Before(u Time) bool
  • 时间t是否在u之后
func (t Time) After(u Time) bool
  • 2时间是否相等
func (t Time) Equal(u Time) bool

例子1:

t := time.Date(2012, 2, 20, 23, 59, 59, 0, time.Local)
now := time.Now()
ok := t.Before(now)
fmt.Println(ok)

ok = t.After(now)
fmt.Println(ok)

ok = t.Equal(now)
fmt.Println(ok)

//true
//false
//false

七:Ticker

Ticker:  按照指定的周期来调用函数或计算表达式

  • Ticker结构
type Ticker struct {
    C <-chan Time // The channel on which the ticks are delivered.
    r runtimeTimer
}
  • 创建一个Ticker
func NewTicker(d Duration) *Ticker

例子1:

可以取消定时

package main

import (
    "fmt"
    "time"
)

func main() {
    //NewTicker 函数可以取消定时
    ticker := time.NewTicker(time.Millisecond * 500)
    go func() {
        for t := range ticker.C {
            fmt.Println("Tick at", t)
        }
    }()

    time.Sleep(time.Millisecond * 1500) //阻塞
    ticker.Stop() //停止ticker
    fmt.Println("Ticker stopped")
}

//Tick at 2019-03-26 18:53:34.3215978 +0800 CST m=+0.506824001
//Tick at 2019-03-26 18:53:34.8226754 +0800 CST m=+1.007901601
//Ticker stopped

例子2:不能取消定时的Tick,所以我们一般用上面的NewTicker

package main

import (
    "fmt"
    "time"
)

func main() {
    tick := time.Tick(2 * time.Second)
    for v := range tick {
        fmt.Println("Tick val:", v)
    }
}

//Tick val: 2019-03-26 18:04:10.3579389 +0800 CST m=+2.007946901
//Tick val: 2019-03-26 18:04:12.3586132 +0800 CST m=+4.008621301
//Tick val: 2019-03-26 18:04:14.3570512 +0800 CST m=+6.007059201
//Tick val: 2019-03-26 18:04:16.3580495 +0800 CST m=+8.008057601

八:定时器Timer

Timer: Timer类型用来代表一个独立的事件,当设置的时间过期后,发送当前时间到channel

使用Timer定时器,超时后需要重置,才能继续触发

  • Timer结构:
type Timer struct {
    C <-chan Time
    r runtimeTimer
}
  • 创建新的定时器
func NewTimer(d Duration) *Timer
  • 停止定时器
func (t *Timer) Stop() bool
  • 重置定时器,以 d 为触发时间
func (t *Timer) Reset(d Duration) bool

例子1:

package main

import (
    "fmt"
    "time"
)

func main() {
    timer1 := time.NewTimer(2 * time.Second)

    <-timer1.C
    fmt.Println("Timer 1 expired")

    timer2 := time.NewTimer(time.Second)
    go func() {
        <-timer2.C
        fmt.Println("Timer 2 expired")
    }()
    stop2 := timer2.Stop()
    if stop2 {
        fmt.Println("Timer 2 stopped")
    }
}
  • 过多长时间运行func函数
func AfterFunc(d Duration, f func()) *Timer

例子1:

package main

import (
    "fmt"
    "time"
)

func main() {
    t := time.Second * 5
    timer := time.AfterFunc(t, func() {
        fmt.Printf("you %d second timer finished", t)
    })
    defer timer.Stop()
    time.Sleep(time.Second * 6)
}
  • After() 在经过时长 d 之后,向返回的只读信道发送当前时间
func After(d Duration) <-chan Time

例子1:

package main

import (
    "fmt"
    "time"
)

func main() {
    done := make(chan struct{}) //采用协程等待结束

    go func(ch <-chan time.Time) {
        fmt.Printf("Now is %s\n", <-ch)
        done <- struct{}{} // 通知主线程协程退出
    }(time.After(time.Second * 3)) //调用After,将返回的只读信道传递给协程函数

    <-done

    close(done)
}

参考:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK