golang time模块

Golang时间模块详解
本文介绍了Golang中的time模块,包括如何获取当前时间、转换时间格式、处理时区、超时控制等方面。重点讨论了time.After、time.Tick和time.NewTicker的使用,强调了在循环中使用这些功能时需要注意的事项,以避免死锁和资源浪费。

时间

  • time.Now()获取当前时间
    • 返回值是time类型
    • 默认获取的是当地时间
      • 使用time.Now().UTC()获取对应的格林威治时间

在这里插入图片描述

  • time类型

    • 实际是一个结构体
      • Unix时间地域信息组成
    • 字符串打印: 2018-11-21 11:50:39.540473 +0800 CST m=+0.000311562
      • +8000 CST 指中国标准时间
      • +0000 UTC 指格林威治时间
  • unix时间

    • 从格林威治时间1970年1月1日0时开始到现在的总秒数
time.Now().Unix()
// 总纳秒数
time.Now().UnixNano()

格式化时间

  • time类型->字符串
    • 只能用2006-01-02 15:04:05这个时间点作为格式化模板
    • 格式化模板中的数字均有对应的含义,无论出现在哪个位置
      • 例如2006代表年,06代表年的后两位,03代表月份
str1 := time.Now().Format("2006-01-02 15:04:05")
str2 := time.Now().Format("2006年1月2日 15:04:05")

在这里插入图片描述

  • 字符串->time类型
    • 返回值是time类型
    • 默认被解析的时间是UTC时间,而不是北京时间
      • 我们应该总是使用 time.ParseInLocation 来解析时间,并给第三个参数传递 time.Local
timestamp1, err := time.Parse("2006-01-02 15:04:05", str1)
timestamp2, err := time.Parse("2006年1月2日 15:04:05", str2)
  • 时间格式常量
RFC3339     = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"

时间长度(Duration)

type Duration int64

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

time.ParseDuration(s string) (Duration, error)
// 减去7分钟
m,_ := time.ParseDuration("-7m")
// 加上10秒
s,_ := time.ParseDuration("10s")
  • time.Duration表示时间长度
    • 以纳秒为基数
    • 底层数据类型为int64
  • int64类型的变量不能直接和time.Duration类型相乘,需要显示转换; 常量除外
    • 不行:num * time.Second
    • 可以: time.Duration(num) * time.Second
    • 可以: 5 * time.Second

时间比较

dt := time.Date(2018, 1, 10, 0, 0, 1, 100, time.Local)
fmt.Println(time.Now().After(dt))     // true
fmt.Println(time.Now().Before(dt))    // false
fmt.Println(dt.Equal(time.Now())) // 判断两个时间点是否相等时使用Equal函数

时间计算

  • time.Add()用来获得指定时间

// 将t0加duration获取t1使用Add方法
func (t Time) Add(d Duration) Time

//一天之前
time.Now().Add(-24 * time.Hour)
// 一年前+2月后+三天前
time.Now().AddDate(-1,2,-3)
  • time.Sub()用来计算时间长度
//获取t0和t1的duration使用Sub
func (t Time) Sub(u Time) Duration

start := time.Now()
longCalculation()
end := time.Now()
delta := end.Sub(start)
// 获取当日0点
func Today() time.Time {
	t := time.Now()
	return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
}
// 获取昨日0点
func Yesterday() time.Time {
	t := Today()
	return t.AddDate(0, 0, -1)
}
  • time.Roundtime.Truncate获取整点时间
t, _ := time.ParseInLocation("2006-01-02 15:04:05", "2016-06-13 15:34:39", time.Local)
// 整点(向下取整)
fmt.Println(t.Truncate(1 * time.Hour))
// 整点(最接近)
fmt.Println(t.Round(1 * time.Hour))

时区

// 本地时区
time.Local
// UTC时区
time.UTC

在这里插入图片描述

超时控制

time.After

func After(d Duration) <-chan Time
// 在时间d后自动执行函数f
func AfterFunc(d Duration, f func()) *Timer
  • 一个time.After应该只被使用一次,否则会发生死锁

  • time.After执行到定义的那一行开始计时

  • time.After和select联合使用以实现超时

    • select中定义的time.After从select执行时开始计时,如果select在超时前再被执行则重新开始计时
      • 当外层有for循环时容易发生
      • 因此如果需要全局超时,而不是每次执行的超时,需要在for循环前定义 time.After
    • 如果select中包含default分支则超时永远执行不到
  • time.AfterFunc等待一定时间后执行函数

    • 底层启动一个goroutine执行函数
    • 可以利用返回值的Stop操作取消执行

time.Tick

  • time.Tick 是对time.NewTicker的简化
  • 不要定义在for循环内,容易造成CPU暴涨
    • 例如for range time.Tick(time.Second)
    • 这样会导致每次循环都创建一个计时goroutine
    • 应该定义在循环前
  • time.Tick 函数 仅仅在应用整个生命周期都需要时才适合
    • 否则应该使用time.NewTicker并手动stop
    • time.Tick 函数的行为很像创建一个 goroutine 在循环里面调用time.Sleep,然后在它每次醒来时发送事件
      • 如果停止监听 tick,但是计时器 goroutine 还在运行,徒劳地向一个没有 goroutine 在接收的通道中不断发送
      • 这会造成goroutine泄露
func Tick(d Duration) <-chan Time

// 定时执行任务
timer := time.Tick(time.Second)
for range timer {
	fmt.Println("hello")
}
  • timer 是一个四叉堆实现,在 timer 数量较多、频繁创建和删除 timer 的场景下,会频繁对这个 timer 堆进行调整,开销较大
    • 如果对于 timer 的精度要求不高,可以采用类似 netty 的方案,基于时间轮做超时
      • 将删除和创建 timer 的复杂度变成了 O(1)
  • 同时多个请求复用一个 timer,可以大幅减少 timer 小对象的分配开销

time.NewTicker

  • 同上,不要定义在for循环内
  • 用完后记得用Stop函数关闭goroutine
func() {
	ticker := time.NewTicker(time.Second)
	defer ticker.Stop() //一定要stop
	
	for range ticker.C {
		fmt.Println("hello")
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值