Go 标准库之 time (获取时_分_秒的单位值、标准时间和Unix时间转换、字符串时间和Time类型转换、时区转换、时间的加减_休眠)

1. 概要说明

import "time"

time 包提供了时间的显示和测量用的函数。日历的计算采用的是公历。

Go 提供以下几种时间类型:

  • 时间点 Time
  • 时间段 Duration
  • 时区 Location
  • Ticker
  • 定时器 Timer

2. Time 类型

type Time struct {
    // 内含隐藏或非导出字段
}

Time 代表一个纳秒精度的时间点。

程序中应使用 Time 类型值来保存和传递时间,而不能用指针。就是说,表示时间的变量和字段,应为 time.Time 类型,而不是 *time.Time 类型。

时间点可以使用 BeforeAfterEqual 方法进行比较。

  • Sub 方法让两个时间点相减,生成一个 Duration 类型值(代表时间段);
  • Add 方法给一个时间点加上一个时间段,生成一个新的Time类型时间点;

Time 零值代表时间点 January 1, year 1, 00:00:00.000000000 UTC。因为本时间点一般不会出现在使用中, IsZero 方法提供了检验时间是否显式初始化的一个简单途径。

每一个时间都具有一个地点信息(及对应地点的时区信息),当计算时间的表示格式时,如 FormatHourYear 等方法,都会考虑该信息。 LocalUTCIn 方法返回一个指定时区(但指向同一时间点)的 Time 。修改地点/时区信息只是会改变其表示;不会修改被表示的时间点,因此也不会影响其计算。

2.1 Time 类型函数

2.1.1 func Date

func Date(year int, month Month, day, hour, min, sec, nsec int, loc *Location) Time

Date 返回一个时区为 loc 、当地时间为:
year-month-day hour:min:sec + nsec nanoseconds 的时间点。

代码示例:

func main() {
	timeDate := time.Date(2020, 05, 23, 10, 11, 12, 13, time.Local)
	fmt.Printf("timeDate is %v, type is %T", timeDate, timeDate)
    // timeDate is 2020-05-23 10:11:12.000000013 +0800 CST, type is time.Time
}

2.1.2 func Now

func Now() Time

Now 返回当前本地时间。

代码示例:

func main() {
	timeNow := time.Now()
	fmt.Printf("timeNow is %v, type is %T", timeNow, timeNow)
	// timeNow is 2020-05-23 10:23:11.061117 +0800 CST m=+0.005000301, type is time.Time
}

2.1.3 func Parse

func Parse(layout, value string) (Time, error)

Parse 解析一个格式化的时间字符串并返回它代表的时间。 layout 定义了参考时间:
Mon Jan 2 15:04:05 -0700 MST 2006,注意 layout 必须为 “2006-01-02 15:04:05”,否则会报错误:

parsing time "2020-05-22 10:25:30": month out of range

代码示例:

func main() {
	timeParse, err := time.Parse("2006-01-02 15:04:05", "2020-05-22 10:25:30")
	if err != nil {
		fmt.Println("time parse failed: ", err)
	}
	fmt.Printf("timeParse is %v, type is %T", timeParse, timeParse)
	// timeParse is 2020-05-22 10:25:30 +0000 UTC, type is time.Time
}

2.1.4 func ParseInLocation

func ParseInLocation(layout, value string, loc *Location) (Time, error)

ParseInLocation 类似 Parse 但有两个重要的不同之处:

  • 当缺少时区信息时, Parse 将时间解释为 UTC 时间,而 ParseInLocation 将返回值的 Location 设置为 loc
  • 当时间字符串提供了时区偏移量信息时, Parse 会尝试去匹配本地时区,而 ParseInLocation 会去匹配loc

代码示例:

func main() {
	ParseInLocation, err := time.ParseInLocation("2006-01-02 15:04:05", "2020-05-22 10:25:30", time.Local)
	if err != nil {
		fmt.Println("time ParseInLocation failed: ", err)
	}
	fmt.Printf("ParseInLocation is %v, type is %T", ParseInLocation, ParseInLocation)
	// ParseInLocation is 2020-05-22 10:25:30 +0800 CST, type is time.Time
}

2.1.5 func Unix

func Unix(sec int64, nsec int64) Time

Unix 创建一个本地时间,对应 secnsec 表示的 Unix 时间(从January 1, 1970 UTC至该时间的秒数和纳秒数)。
nsec 的值在 [0, 999999999] 范围外是合法的。

代码示例:

func main() {
	timeUnix := time.Unix(322020993, 3939993399848320)
	fmt.Printf("timeUnix is %v, type is %T", timeUnix, timeUnix)
	// timeUnix is 1980-05-01 00:43:06.39984832 +0800 CST, type is time.Time
}

以上的函数 DateNowParseParseInLocationUnix 返回的都是 Time 类型的结构体。

2.2 Time 类型方法

Time 类型有很多结构体方法,如下表所示:

func (t Time) Location() *Location
func (t Time) Zone() (name string, offset int)
func (t Time) IsZero() bool
func (t Time) Local() Time
func (t Time) UTC() Time
func (t Time) In(loc *Location) Time
func (t Time) Unix() int64
func (t Time) UnixNano() int64
func (t Time) Equal(u Time) bool
func (t Time) Before(u Time) bool
func (t Time) After(u Time) bool
func (t Time) Date() (year int, month Month, day int)
func (t Time) Clock() (hour, min, sec int)
func (t Time) Year() int
func (t Time) Month() Month
func (t Time) ISOWeek() (year, week int)
func (t Time) YearDay() int
func (t Time) Day() int
func (t Time) Weekday() Weekday
func (t Time) Hour() int
func (t Time) Minute() int
func (t Time) Second() int
func (t Time) Nanosecond() int
func (t Time) Add(d Duration) Time
func (t Time) AddDate(years int, months int, days int) Time
func (t Time) Sub(u Time) Duration
func (t Time) Round(d Duration) Time
func (t Time) Truncate(d Duration) Time
func (t Time) Format(layout string) string
func (t Time) String() string
func (t Time) GobEncode() ([]byte, error)
func (t *Time) GobDecode(data []byte) error
func (t Time) MarshalBinary() ([]byte, error)
func (t *Time) UnmarshalBinary(data []byte) error
func (t Time) MarshalJSON() ([]byte, error)
func (t *Time) UnmarshalJSON(data []byte) error
func (t Time) MarshalText() ([]byte, error)
func (t *Time) UnmarshalText(data []byte) error

代码示例如下:

func main() {
	nowTime := time.Now()
	fmt.Println("nowTime.Location", nowTime.Location())
	zoneName, _ := nowTime.Zone()
	fmt.Println("nowTime.Zone", zoneName)
	fmt.Println("nowTime.IsZero", nowTime.IsZero())
	fmt.Println("nowTime.Location", nowTime.Local())
	fmt.Println("nowTime.UTC", nowTime.UTC())
	fmt.Println("nowTime.In", nowTime.In(nowTime.Location()))
	fmt.Println("nowTime.Unix", nowTime.Unix())
	fmt.Println("nowTime.UnixNano", nowTime.UnixNano())
	fmt.Println("nowTime.Equal", nowTime.Equal(nowTime))
	fmt.Println("nowTime.Before", nowTime.Before(nowTime))
	fmt.Println("nowTime.After", nowTime.After(nowTime))
	fmt.Println(nowTime.Date())
	fmt.Println(nowTime.Clock())
	fmt.Println("nowTime.Year", nowTime.Year())
	fmt.Println("nowTime.YearDay", nowTime.YearDay())
	fmt.Println("nowTime.Month", nowTime.Month())
	fmt.Println(nowTime.ISOWeek())
	fmt.Println("nowTime.Day", nowTime.Day())
	fmt.Println("nowTime.Weekday", nowTime.Weekday())
	fmt.Println("nowTime.Hour", nowTime.Hour())
	fmt.Println("nowTime.Minute", nowTime.Minute())
	fmt.Println("nowTime.Second", nowTime.Second())
	fmt.Println("nowTime.Nanosecond", nowTime.Nanosecond())
	fmt.Println("nowTime.Add", nowTime.Add(time.Hour*3))
	fmt.Println("nowTime.AddDate", nowTime.AddDate(2, 3, 4))
	fmt.Println("nowTime.Sub", nowTime.Sub(nowTime))
	fmt.Println("nowTime.String", nowTime.String())
	fmt.Println("nowTime.Format", nowTime.Format("2006-01-02 15:04:05"))
	fmt.Println("nowTime.Format", nowTime.Format("2006-01-02 15-04-05"))
	fmt.Println("nowTime.Format", nowTime.Format("2006-01-02"))

}

输出结果:

nowTime.Location Local
nowTime.Zone CST
nowTime.IsZero false
nowTime.Location 2020-05-23 15:03:24.4848344 +0800 CST
nowTime.UTC 2020-05-23 07:03:24.4848344 +0000 UTC
nowTime.In 2020-05-23 15:03:24.4848344 +0800 CST
nowTime.Unix 1590217404
nowTime.UnixNano 1590217404484834400
nowTime.Equal true
nowTime.Before false
nowTime.After false
2020 May 23
15 3 24
nowTime.Year 2020
nowTime.YearDay 144
nowTime.Month May
2020 21
nowTime.Day 23
nowTime.Weekday Saturday
nowTime.Hour 15
nowTime.Minute 3
nowTime.Second 24
nowTime.Nanosecond 484834400
nowTime.Add 2020-05-23 18:03:24.4848344 +0800 CST m=+10800.007000401
nowTime.AddDate 2022-08-27 15:03:24.4848344 +0800 CST
nowTime.Sub 0s
nowTime.String 2020-05-23 15:03:24.4848344 +0800 CST m=+0.007000401
nowTime.Format 2020-05-23 15:03:24
nowTime.Format 2020-05-23 15-03-24
nowTime.Format 2020-05-23

3. Duration 类型

type Duration int64

Duration 类型代表两个时间点之间经过的时间,以纳秒为单位。

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

常用的时间段。没有定义一天或超过一天的单元,以避免夏时制的时区切换的混乱。

要将 Duration 类型值表示为某时间单元的个数,用除法:

second := time.Second
fmt.Print(int64(second/time.Millisecond)) // prints 1000

要将整数个某时间单元表示为 Duration 类型值,用乘法:

seconds := 10
fmt.Print(time.Duration(seconds)*time.Second) // prints 10s

3.1 Duration 类型函数

3.1.1 func ParseDuration

func ParseDuration(s string) (Duration, error)

ParseDuration 解析一个时间段字符串。一个时间段字符串是一个序列,每个片段包含可选的正负号、十进制数、可选的小数部分和单位后缀,如"300ms"、"-1.5h"、“2h45m”。合法的单位有"ns"、“us” /“µs”、“ms”、“s”、“m”、“h”。

3.1.2 func Since

func Since(t Time) Duration

Since 返回从 t 到现在经过的时间,等价于 time.Now().Sub(t)

func test() {
    start := time.Now() // 获取当前时间
    sum := 0
    for i := 0; i < 100000000; i++ {
        sum++
    }
    elapsed := time.Since(start)	// 等价于  elapsed := time.Now().Sub(start)
    fmt.Println("该函数执行完成耗时:", elapsed)
}

3.2 Duration 类型方法

ParseDuration 解析一个时间段字符串。一个时间段字符串是一个序列,每个片段包含可选的正负号、十进制数、可选的小数部分和单位后缀,如"300ms"、"-1.5h"、“2h45m”。
合法的单位有"ns"、“us”、“µs”、“ms”、“s”、“m”、“h”。

func (d Duration) Hours() float64
func (d Duration) Minutes() float64
func (d Duration) Seconds() float64
func (d Duration) Nanoseconds() int64
func (d Duration) String() string

代码示例:

func main() {
	tp, _ := time.ParseDuration("120s")
	fmt.Println("tp.Hours", tp.Hours())             // tp.Hours 0.03333333333333333
	fmt.Println("tp.Minutes", tp.Minutes())         // tp.Minutes 2
	fmt.Println("tp.Seconds", tp.Seconds())         // tp.Seconds 120
	fmt.Println("tp.Nanoseconds", tp.Nanoseconds()) // tp.Nanoseconds 120000000000
	fmt.Println("tp.String", tp.String())           // tp.String 2m0s
}

4. Location 类型

func LoadLocation(name string) (*Location, error)
func FixedZone(name string, offset int) *Location
func (l *Location) String() string

代码示例:

func main() {
	loc, _ := time.LoadLocation("")
	// 服务器设定的时区,一般为CST
	loc, _ = time.LoadLocation("Local")
	fmt.Println("loc is ", loc) // loc is  Local
	// 美国洛杉矶PDT
	loc, _ = time.LoadLocation("America/Los_Angeles")
	fmt.Println("loc is ", loc) // loc is  America/Los_Angeles
	// 获取指定时区的时间点
	local, _ := time.LoadLocation("America/Los_Angeles")
	fmt.Println(time.Date(2018, 1, 1, 12, 0, 0, 0, local)) //2018-01-01 12:00:00 -0800 PST

}

5. 实际业务使用场景

5.1 获取时、分、秒的单位值

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

源码包定义以上常量,在代码中可以通过 time.XXX 得到,代码如下:

func main() {
	fmt.Println("time.Nanosecond", time.Nanosecond)   // time.Nanosecond 1ns
	fmt.Println("time.Microsecond", time.Microsecond) // time.Microsecond 1µs
	fmt.Println("time.Millisecond", time.Millisecond) // time.Millisecond 1ms
	fmt.Println("time.Second", time.Second)           // time.Second 1s
	fmt.Println("time.Minute", time.Minute)           // time.Minute 1m0s
	fmt.Println("time.Hour", time.Hour)               // time.Hour 1h0m0s
}

5.2 标准时间和Unix时间转换

代码如下:

func main() {
	timeNow := time.Now()
	fmt.Println("timeNow is ", timeNow)
	// timeNow is  2020-05-23 22:29:53.0060736 +0800 CST m=+0.005000301
	timeUnix := timeNow.Unix()
	fmt.Println("timeUnix is ", timeUnix)
	// timeUnix is  1590244193
	timeCurrent := time.Unix(timeUnix, 0)
	fmt.Println("timeCurrent is ", timeCurrent)
	// timeCurrent is  2020-05-23 22:29:53 +0800 CST

}

5.3 Time 类型转换为字符串

注意: Go 中指定的特定时间格式为 2006-01-02 15:04:05 -0700 MST , 为了记忆方便,按照美式时间格式 月日时分秒年 外加时区 排列起来依次是 01/02 03:04:05PM ‘06 -0700,刚开始使用时需要注意

这一点与 Python 中的 %Y-%m-%d %H-%M-%S 有区别。

示例代码:

const (
	//time format
	FormatDay      = "2006-01-02"
	FormatSecond   = "2006-01-02 15:04:05"
	FormatMinute   = "2006-01-02 15:04"
	FormatOnlyHour = "15:04"
)

func main() {
	timeFormatDay := time.Now().Format(FormatDay)
	fmt.Printf("timeFormatDay is %#v, type is %T\n", timeFormatDay, timeFormatDay)
	// timeFormatDay is "2020-05-23", type is string
	timeFormatSecond := time.Now().Format(FormatSecond)
	fmt.Println("timeFormatSecond is ", timeFormatSecond)
	// timeFormatSecond is  2020-05-23 22:44:26
	timeFormatMinute := time.Now().Format(FormatMinute)
	fmt.Println("timeFormatMinute is ", timeFormatMinute)
	// timeFormatMinute is  2020-05-23 22:44
	timeFormatOnlyHour := time.Now().Format(FormatOnlyHour)
	fmt.Println("timeFormatOnlyHour is ", timeFormatOnlyHour)
	// timeFormatOnlyHour is  22:44

}

5.4 字符串转换为Time类型

代码如下:

const (
	//time format
	FormatDay      = "2006-01-02"
	FormatSecond   = "2006-01-02 15:04:05"
	FormatMinute   = "2006-01-02 15:04"
	FormatOnlyHour = "15:04"
)

func main() {
	timestamp, _ := time.Parse(FormatSecond, "2020-05-23 22:20:30")
	fmt.Printf("timestamp is %v, type is %T\n", timestamp, timestamp)
	// timestamp is 2020-05-23 22:20:30 +0000 UTC, type is time.Time
	fmt.Println(timestamp.Unix()) //时间戳 1590272430
    fmt.Println(time.Date(2020, 05, 23, 10, 11, 12, 13, time.Local).Unix())

}

5.5 时区变更后获取时间戳

示例代码:

const (
	//time format
	FormatDay      = "2006-01-02"
	FormatSecond   = "2006-01-02 15:04:05"
	FormatMinute   = "2006-01-02 15:04"
	FormatOnlyHour = "15:04"
)

func main() {
	loc, _ := time.LoadLocation("Asia/Shanghai")
	t, _ := time.ParseInLocation(FormatSecond, "2020-05-23 22:20:30", loc)
	fmt.Printf("t is %v, type is %T\n", t, t)
	// 标准时间格式 t is 2020-05-23 22:20:30 +0800 CST, type is time.Time
	fmt.Println(t.Unix()) //时间戳 1590243630

}

5.6 比较两个时间点

      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

      // 是否相等 判断两个时间点是否相等时推荐使用 Equal 函数
      fmt.Println(dt.Equal(time.Now()))

5.7 时区之间转换

      // time.Local 用来表示当前服务器时区
      // 自定义地区时间
      secondsEastOfUTC := int((8 * time.Hour).Seconds())
      beijing := time.FixedZone("Beijing Time", secondsEastOfUTC)
      fmt.Println(time.Date(2018,1,2,0,0,0,0, beijing))  // 2018-01-02 00:00:00 +0800 Beijing Time  

      // 当前时间转为指定时区时间
      fmt.Println(time.Now().In(beijing))

      // 指定时间转换成指定时区对应的时间
      dt, err := time.ParseInLocation("2006-01-02 15:04:05", "2017-05-11 14:06:06", time.Local)

      // 当前时间在零时区年月日   时分秒  时区
      year, mon, day := time.Now().UTC().Date()     // 2018 April 24 
      hour, min, sec := time.Now().UTC().Clock()    // 3 47 15
      zone, _ := time.Now().UTC().Zone()            // UTC

5.8 基于当前时间的加减

      now := time.Now()

      // 一年零一个月一天之后
      fmt.Println(now.Date(1,1,1))
      // 一段时间之后
      fmt.Println(now.Add(time.Duration(10)*time.Minute))

      // 计算两个时间点的相差天数
      dt1 = time.Date(dt1.Year(), dt1.Month(), dt1.Day(), 0, 0, 0, 0, time.Local)
      dt2 = time.Date(dt2.Year(), dt2.Month(), dt2.Day(), 0, 0, 0, 0, time.Local)
      fmt.Println(int(math.Ceil(dt1.Sub(dt2).Hours() / 24)))

5.9 时间差值

      dt1 := time.Date(2018, 1, 10, 0, 0, 1, 100, time.Local)
      dt2 := time.Date(2018, 1, 9, 23, 59, 22, 100, time.Local)
      // 不用关注时区,go会转换成时间戳进行计算
      fmt.Println(dt1.Sub(dt2))        

5.10 时间运算

      // func Sleep(d Duration)   休眠多少时间,休眠时处于阻塞状态,后续程序无法执行
      time.Sleep(time.Duration(10) * time.Second)

      // func After(d Duration) <-chan Time  非阻塞,可用于延迟
      time.After(time.Duration(10) * time.Second)

      // func Since(t Time) Duration 两个时间点的间隔
      start := time.Now()
      fmt.Println(time.Since(start))   // 等价于 Now().Sub(t), 可用来计算一段业务的消耗时间

      func Until(t Time) Duration     //  等价于 t.Sub(Now()),t与当前时间的间隔

      // func (t Time) Add(d Duration) Time
      fmt.Println(dt.Add(time.Duration(10) * time.Second))   // 加

      func (t Time) Sub(u Time) Duration                    // 减 

      // func (t Time) AddDate(years int, months int, days int) Time
      fmt.Println(dt.AddDate(1, 1, 1))

      func (t Time) Before(u Time) bool
      func (t Time) After(u Time) bool
      func (t Time) Equal(u Time) bool          比较时间点时尽量使用Equal函数 

参考:
https://segmentfault.com/a/1190000015040923?utm_source=tag-newest
https://blog.csdn.net/wschq/article/details/80114036
https://studygolang.com/static/pkgdoc/pkg/time.htm

你可能感兴趣的:(Go)