Skip to content
On this page

time包

查看当前时间

Go
func Now() Time

TIP

时间戳精确到

代码示例

Go
// 获取当前时间
t := time.Now()
// 获取当前时间戳
curTimestamp := t.Unix()
fmt.Println("当前时间戳为", curTimestamp)

获取两个时间的间隔

time.Time.Sub

Go
func (time.Time).Sub(u time.Time) time.Duration

代码示例

Go
// 获取当前时间
t := time.Now()
// 睡眠两秒
time.Sleep(2 * time.Second)
t2 := time.Now()
// 获取两个时间的间隔
timeInterval := t2.Sub(t)
// t2和t之前相差的时间按秒来看为: 2.001279042s
fmt.Println("t2和t之前相差的时间按秒来看为:", timeInterval)
// t2和t之前相差的时间按毫秒来看为: 2001
fmt.Println("t2和t之前相差的时间按毫秒来看为:", timeInterval.Milliseconds())
// t2和t之前相差的时间按纳秒来看为: 2001279
fmt.Println("t2和t之前相差的时间按纳秒来看为:", timeInterval.Microseconds())

time.Since

Go
func Since(t Time) Duration

TIP

time.Since(t)time.Now().Sub(t)的快捷方式

Go
// 获取当前时间
t := time.Now()
// 睡眠两秒
time.Sleep(2 * time.Second)
d := time.Since(t)
fmt.Println(d) // 2.001039875s

两个时间相加

time.Time.Add

Go
func (time.Time).Add(d time.Duration) time.Time

代码示例

Go
// 计算时间的加法
duration := time.Duration(2 * time.Second)
t3 := time.Now()
fmt.Println("t3时间戳为", t3.Unix())
addRes := t3.Add(duration)
fmt.Println("t3+duration时间戳为", addRes.Unix())

时间格式化

go的时间格式化比较特别,定义了一套基础格式化模板,如下格式,从01-07分别表示时区

Go
const (
	Layout      = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
)
UnitLayoutResult
Year0621, 81, 01
Year20062021, 1981, 0001
Month11, 2, 12
Month0101, 02, 12
Day21, 2, 11, 31
Day0201, 02, 11, 31
Part of dayPMAM, PM
Part of daypmam, pm
Hour 24h1500, 01, 12, 23
Hour 12h31, 2, 12
Hour 12h0301, 02, 12
Minute40, 4 ,10, 35
Minute0400, 04 ,10, 35
Second50, 5, 25
Second0500, 05, 25

Timer和Ticker

如果想在未来某个时刻执行某个任务,或者在某个时间间隔重复执行代码,可以使用timer/tikcer

Timer

类似于定时器(setTimeout)

  • 下面的例子使用time.NewTimer(time)创建一个计时器,time就是我们想让其等待多久类似于time.Sleep(time)

  • time.Sleep(time)不一样的是,可以在计时器触发之前取消它,如timer2,本来需要2s后触发,我们手动取消了

Go
func demo1() {
	timer1 := time.NewTimer(time.Second * 1)

	<-timer1.C
	fmt.Println("timer1 完成")

	timer2 := time.NewTimer(time.Second * 2)

	go func ()  {
		<- timer2.C
	}()
	isTimer2Stop := timer2.Stop()
	fmt.Println("timer2 stop", isTimer2Stop)
}

func main() {
	demo1()
}

计时器

类似于setInterval

  • 下面的例子,在done被发送为true之前,会每500毫秒打印一次时间
Go
func demo2() {
	ticker := time.NewTicker(500 * time.Millisecond)
	done := make(chan bool)

	go func ()  {
		for {
			select {
				case isDone := <- done:
					fmt.Println("完成了", isDone)
					return
				case t := <- ticker.C:
					fmt.Println("Tick at", t)
			}
		}
	}()
	timer := time.NewTimer(2000 * time.Millisecond)
	<- timer.C
	ticker.Stop()
	done <- true
	fmt.Println("========end==========")
}

func main() {
	demo2()
}

速率限制

  • 模拟实现一个定时调度处理,每200ms处理一次值

  • 通过源码可知time.Tick(200 * time.Millisecond)的返回值其实就是time.NewTicker(200 * time.Millisecond).C

Go
func scheduledProcessing() {
	// 声明并初始化一个缓冲区为6的通道,并填充缓冲区,表示有6个任务需要处理
	processing := make(chan int, 6)
	for i := 0; i < 6; i++ {
		processing <- i
	}
	// 关闭通道
	close(processing)
	// 声明一个每200ms执行一次的调度器
	tick := time.NewTicker(200 * time.Millisecond)
	// 或者 tick1 := time.Tick(200 * time.Millisecond)
	// 遍历需要处理的任务
	for req := range processing {
		// 每200ms会发送一个time数据
		t := <- tick.C
		// 上面如果使用tick1 这里就是 t := <- tick1
		// 每200ms 会执行一次打印
		fmt.Println("处理了req, req为:", req, t)
	}
}

func main() {
   scheduledProcessing()
}

控制并发数量

Go
func burstyLimter() {
	// 初始化一个能容纳3个缓冲的时间通道
	timeLimter := make(chan time.Time, 3)
	// 填充时间通道的缓冲区
	for i := 0; i < 3; i++ {
		timeLimter <- time.Now()
	}

	// 开启一个协程,每200ms向timLimter通道中发送一个time数据
	go func ()  {
		for t:= range time.Tick(200 * time.Millisecond) {
			timeLimter <- t
		}
	}()
	// 声明一个tasks任务通道,并向通道发送数据,填满缓冲区
	tasks := make(chan int, 6)
	for i := 0; i < 6; i++ {
		tasks <- i
	}
	// 关闭tasks通道
	close(tasks)
	for task := range tasks {
		t := <- timeLimter
		fmt.Println("执行task", task, "时间是: ", t)
	}
	// 前3次任务并发执行,后面的每200毫秒处理剩余请求
}

func main() {
	burstyLimter()
}