作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.时间类型
package main
import (
"time"
"fmt"
)
func main() {
// 获取当前时间对象,后从时间对象中可以获取到年、月、日、时、分、秒等信息。
now := time.Now()
fmt.Printf("current time: [%v]\n", now)
// 年
year := now.Year()
// 月
month := now.Month()
// 日
day := now.Day()
// 小时
hour := now.Hour()
// 分钟
minute := now.Minute()
// 秒
second := now.Second()
fmt.Println(year, month, day, hour, minute, second)
}
二.Location和time zone
1.时区介绍
Go语言中使用location来映射具体的时区。时区(Time Zone)是根据世界各国家与地区不同的经度而划分的时间定义,全球共分为24个时区。
中国差不多跨5个时区,但为了使用方便只用东八时区的标准时即北京时间为准。在日常编码过程中使用时间对象的时候一定要注意其时区信息。
2.时区案例
package main
import (
"fmt"
"time"
)
func main() {
// 中国没有夏令时,使用一个固定的8小时的UTC时差(东八区,UTC +08:00),对于很多其他国家需要考虑夏令时。
timezone := int((8 * time.Hour).Seconds())
// FixedZone 返回始终使用给定区域名称和偏移量(UTC 以东秒)的Location。UTC +08:00
shanghaiTimezone := time.FixedZone("Asia/Shanghai", timezone)
// 如果当前系统有时区数据库,则可以加载一个位置得到对应的时区,例如,加载纽约所在的时区,UTC -05:00
newYorkTimezone, _ := time.LoadLocation("America/New_York")
utc := time.Date(2009, 1, 1, 12, 0, 0, 0, time.UTC)
shanghai := time.Date(2009, 1, 1, 20, 0, 0, 0, shanghaiTimezone)
NewYork := time.Date(2009, 1, 1, 7, 0, 0, 0, newYorkTimezone)
// 北京时间(东八区)比UTC早8小时,所以上面两个时间看似差了8小时,但表示的是同一个时间
t1 := utc.Equal(shanghai)
// 纽约(西五区)比UTC晚5小时,所以上面两个时间看似差了5小时,但表示的是同一个时间
t2 := utc.Equal(NewYork)
fmt.Printf("[%v] = [%v] => [%t]\n",utc,shanghai,t1)
fmt.Printf("[%v] = [%v] => [%t]\n",utc,NewYork,t2)
}
三.时间戳unix time
1.Unix Time概述
Unix Time是自1970年1月1日 00:00:00 UTC至当前时间经过的总秒数。下面的代码片段演示了如何基于时间对象获取到Unix 时间。
2.获取时间戳
package main
import (
"fmt"
"time"
)
func main() {
// 获取当前时间
now := time.Now()
// 秒级时间戳
timestamp := now.Unix()
// 毫秒时间戳 Go1.17+
milli := now.UnixMilli()
// 微秒时间戳 Go1.17+
micro := now.UnixMicro()
// 纳秒时间戳
nano := now.UnixNano()
fmt.Printf("秒级时间戳: %v\n毫级时间戳: %v\n微级时间戳: %v\n纳级时间戳: %v\n", timestamp, milli, micro, nano)
}
3.将时间戳转为时间对象
package main
import (
"fmt"
"time"
)
func main() {
// 获取北京时间所在的东八区时区对象
secondsEastOfUTC := int((8 * time.Hour).Seconds())
beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
// 北京时间 2022-02-22 22:22:22.000000022 +0800 CST
t := time.Date(2030, 11, 11, 23, 59, 59, 59, beijing)
var (
sec = t.Unix()
msec = t.UnixMilli()
usec = t.UnixMicro()
)
// 将秒级时间戳转为时间对象(第二个参数为不足1秒的纳秒数)
t1 := time.Unix(sec, 99999)
// 毫秒级时间戳转为时间对象
t2 := time.UnixMilli(msec)
// 微秒级时间戳转为时间对象
t3 := time.UnixMicro(usec)
fmt.Printf("t1 = [%v], t2 = [%v], t3 = [%v]\n", t1, t2, t3)
}
四.时间间隔设置及比较
1.时间间隔类型的常量
time.Duration是time包定义的一个类型,它代表两个时间点之间经过的时间,以纳秒为单位。
time.Duration表示一段时间间隔,可表示的最长时间段大约290年。
time包中定义的时间间隔类型的常量如下:
const (
Nanosecond Duration = 1
Microsecond = 1000 * Nanosecond
Millisecond = 1000 * Microsecond
Second = 1000 * Millisecond
Minute = 60 * Second
Hour = 60 * Minute
)
例如:time.Duration表示1纳秒,time.Second表示1秒。
2.Add
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
/*
Go语言的时间对象有提供Add方法如下:
func (t Time) Add(d Duration) Time
*/
later := now.Add(time.Hour) // 当前时间加1小时后的时间
fmt.Printf("now = [%v] later = [%v]\n", now, later)
}
3.sub
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
t1, _ := time.Parse("2006/01/02 15:04:05", "2024/08/20 11:25:20")
/*
Go语言的时间对象有提供Sub方法如下:
func (t Time) Sub(u Time) Duration
*/
t2 := now.Sub(t1) // 比较现在和t1时间相差的时间
fmt.Printf("now = [%v] t2 = [%v]\n", now, t2)
}
4.Equal
package main
import (
"fmt"
"time"
)
func main() {
t1, _ := time.Parse("2006/01/02 15:04:05", "2030/08/20 11:25:20")
t2, _ := time.Parse(time.RFC3339, "2030-08-20T19:25:20+08:00")
/*
Go语言的时间对象有提供Equal方法如下:
func (t Time) Equal(u Time) bool
判断两个时间是否相同,会考虑时区的影响,因此不同时区标准的时间也可以正确比较。
本方法和用t==u不同,这种方法还会比较地点和时区信息。
*/
flag := t1.Equal(t2)
fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}
5.Before
package main
import (
"fmt"
"time"
)
func main() {
t1, _ := time.Parse("2006/01/02 15:04:05", "2030/08/21 12:25:20")
t2, _ := time.Parse(time.RFC3339, "2030-08-30T19:25:20+08:00")
/*
Go语言的时间对象有提供Before方法如下:
func (t Time) Before(u Time) bool
如果t代表的时间点在u之前,返回真;否则返回假。
*/
flag := t1.Before(t2)
fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}
6.After
package main
import (
"fmt"
"time"
)
func main() {
t1, _ := time.Parse("2006/01/02 15:04:05", "2030/09/21 12:25:20")
t2, _ := time.Parse(time.RFC3339, "2030-08-30T19:25:20+08:00")
/*
Go语言的时间对象有提供Before方法如下:
func (t Time) After(u Time) bool
如果t代表的时间点在u之后,返回真;否则返回假。
*/
flag := t1.After(t2)
fmt.Printf("[%v] = [%v] ---> [%t]\n", t1, t2, flag)
}
五.定时器
1.定时器概述
使用time.Tick(时间间隔)来设置定时器,定时器的本质上是一个通道(channel)。
2.定时器案例
package main
import (
"fmt"
"time"
)
func main() {
// //定义一个1秒间隔的定时器,如果想要换成每分钟,可以使用"time.Minute",依此类推...
ticker := time.Tick(time.Second)
for i := range ticker {
//每秒都会执行的任务
fmt.Println(i)
}
}
六.时间格式化
1.时间格式化
time.Format函数能够将一个时间对象格式化输出为指定布局的文本表示形式,需要注意的是Go语言中时间格式化的布局不是常见的Y-m-d H:M:S,而是使用"2006-01-02 15:04:05.000"(记忆口诀为2006 1 2 3 4 5)。
其中:
- 2006:年(Y)
- 01:月(m)
- 02:日(d)
- 15:时(H)
- 04:分(M)
- 05:秒(S)
温馨提示:
(1)如果想格式化为12小时格式,需在格式化布局中添加PM。
(2)小数部分想保留指定位数就写0,如果想省略末尾可能的0就写9。
2.参考案例
package main
import (
"fmt"
"time"
)
func main() {
// 获取当前时间对象,后续方便基于对时间对象进行格式化操作
now := time.Now()
// 格式化的模板为 2006-01-02 15:04:05
// 24小时制
fmt.Println(now.Format("2006-01-02 15:04:05.000 Mon Jan"))
// 12小时制
fmt.Println(now.Format("2006-01-02 03:04:05.000 PM Mon Jan"))
// 小数点后写0,因为有3个0所以格式化输出的结果也保留3位小数
fmt.Println(now.Format("2006/01/02 15:04:05.000"))
// 小数点后写9,会省略末尾可能出现的0
fmt.Println(now.Format("2006/01/02 15:04:05.999"))
// 只格式化时分秒部分
fmt.Println(now.Format("15:04:05"))
// 只格式化日期部分
fmt.Println(now.Format("2006.01.02"))
}
七.解析字符串的时间
1.解析时间的函数
对于从文本的时间表示中解析出时间对象,time包中提供了time.Parse和time.ParseInLocation两个函数。
其中time.Parse在解析时不需要额外指定时区信息。
time.ParseInLocation函数需要在解析时额外指定时区信息。
2.Parse从文本解析时间
package main
import (
"fmt"
"time"
)
func main() {
// 在没有时区指示符的情况下,time.Parse 返回UTC时间
t1, _ := time.Parse("2006/01/02 15:04:05", "2030/10/05 11:25:20")
// 在有时区指示符的情况下,time.Parse 返回对应时区的时间表示
// RFC3339 = "2006-01-02T15:04:05Z07:00"
t2, _ := time.Parse(time.RFC3339, "2030-10-05T11:25:20+08:00")
fmt.Printf("t1 = [%v], t2 = [%v]\n", t1, t2)
}
3.ParseInLocation从文本解析时间
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
// 加载时区
timezone, _ := time.LoadLocation("Asia/Shanghai")
// 按照指定时区和指定格式解析字符串时间
t1, _ := time.ParseInLocation("2006/01/02 15:04:05", "2030/07/20 11:25:20", timezone)
fmt.Println(now)
fmt.Println(t1.Sub(now))
}
八.练习题
1.获取当前时间,格式化输出为"2030/01/01 23:30:05"格式
package main
import (
"fmt"
"time"
)
func PrintTime(t time.Time) {
// 方式一: Go语言中时间格式化的布局不是常见的Y-m-d H:M:S,而是使用 2006-01-02 15:04:05.000(记忆口诀为2006 1 2 3 4 5)
// 温馨提示:
// 1."2006/01/02 15:04:05"分别对应着年月日时分秒;
// 2.如果只想看年则传入"2006",如果想要看月份则传入"01",如果想要看小时则传入15,以此推类;
t1 := t.Format("2006/01/02 15:04:05")
fmt.Printf("t1 = [%v]\n", t1)
// 方式二: 使用Sprintf
t2 := fmt.Sprintf("%d/%d/%d %d:%d:%d", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second())
fmt.Printf("t2 = [%v]\n", t2)
}
func main() {
now := time.Now()
PrintTime(now)
}
2.编写程序统计一段代码的执行耗时时间,单位精确到微秒。
package main
import (
"fmt"
"time"
)
func calctime1() {
// 计算出纳秒
start := time.Now().UnixNano() / 1000
fmt.Println("正在执行代码...")
time.Sleep(time.Millisecond * 50)
end := time.Now().UnixNano() / 1000
fmt.Printf("in calctime1()... 耗费了%v微妙\n", end-start)
}
func calctime2() {
start := time.Now()
fmt.Println("正在执行代码...")
time.Sleep(time.Millisecond * 100)
// 注意, time.Since时内置的方法,就是拿当前的时间减去start的时间哟。
fmt.Printf("in calctime2()... 耗费了%v\n", time.Since(start))
}
func main() {
calctime1()
calctime2()
}