时间背景知识

UTC = Coordinated Universal Time(世界标准时间)

Wed Aug 14 08:21:05 UTC 2013 //标准UTC时间
Wed Aug 14 16:21:05 UTC+8 2013 //东8区,即我们的北京时间
Wed Aug 14 03:21:05 UTC-5 2013 //西5区,美国和加拿大时间

GMT = Greenwich Mean Time(格林尼治平时)

Wed Aug 14 08:21:05 GMT 2013 //标准GMT时间
Wed Aug 14 16:21:05 GMT+8 2013 //东8区,即我们的北京时间
Wed Aug 14 03:21:05 GMT-5 2013 //西5区,美国和加拿大时间

CST = China Standard Time(北京时间),CST 不推荐使用因为它还可以有其他含义:

  • 澳洲中部时间,Central Standard Time (Australia)
  • 中部标准时区(北美洲),Central Standard Time (North America)
  • 古巴标准时间,Cuba Standard Time
Wed Aug 14 08:21:05 CST 2013 // 北京、北美中部、古巴、澳洲中部?

DST = Daylight Saving(夏令时) Time,为节约能源而人为规定地方时间的制度,一般在天亮早的夏季人为将时间提前一小时,在欧美的软件系统中通常会涉及到夏令时的处理,中国地区不支持 DST。

CDT = North American Central Daylight Time(北美中部夏令时)

ISO8601 用于取代 GMT/UTC

# YYYY-MM-DDTHH:mm:ssZ
2019-07-23T11:40:06.284Z
2016-01-01T11:13:00+08:00
2016-01-01T11:13:00.333+08:00

RFC3339 格式

RFC3339     = "2006-01-02T15:04:05+07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999+07:00"

时间单位:

ms = 1/1000 s(milisecond 毫秒)
us = 10^-6 s (microsecond微秒)
ns = 10^-9s (nanosecond 纳秒)
ps = 10^-12s (picosecond 皮秒)
fs = 10^-15s (femtosecond 飞秒)
as = 10^-18s (attosecond 阿秒),用于光子研究

关于 2006-01-02 15:04:05

这个格式里,每个位置的数字都不一样,所以比 YYYY-MM-DD HH:MM:ss 这样的格式更直观,记忆方法 2006-01-02-03(15-12)-04-05 => 200612345.

1: month (January, Jan, 01, etc)
2: day
3: hour (15 is 3pm on a 24 hour clock)
4: minute
5: second
6: year (2006)
7: timezone (GMT-7 is MST)
const (
	Layout      = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
	ANSIC       = "Mon Jan _2 15:04:05 2006"
	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
	RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
	RFC822      = "02 Jan 06 15:04 MST"
	RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
	RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
	RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
	RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
	RFC3339     = "2006-01-02T15:04:05Z07:00"
	RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
	Kitchen     = "3:04PM"
	// Handy time stamps.
	Stamp      = "Jan _2 15:04:05"
	StampMilli = "Jan _2 15:04:05.000"
	StampMicro = "Jan _2 15:04:05.000000"
	StampNano  = "Jan _2 15:04:05.000000000"
)

创建时间

在线运行open in new window启动 AI 助手open in new window

loc, _ := time.LoadLocation("Asia/Shanghai")
// now := time.Now()
// now, _ := time.Parse(time.RFC3339, "2022-09-10T23:11:12+08:00")
now := time.Date(2022, 9, 10, 23, 11, 12, 0, loc)
fmt.Println(now.Unix())
fmt.Println(now.UnixMilli())

fmt.Println(now.Year())
fmt.Println(now.Month())
fmt.Println(now.Day())
fmt.Println(now.Hour())
fmt.Println(now.Minute())
fmt.Println(now.Second())
fmt.Println(now.Nanosecond())
fmt.Println(now.Weekday())

fmt.Println(now.Format(time.UnixDate))
fmt.Println(now.Format("2006-01-02 15:04:05"))
fmt.Println(now.Format("2006-01-02 15:04:05 -0700"))
fmt.Println(now.Format(time.RFC3339))
fmt.Println(now.Format(time.RFC3339Nano))

内定的时间格式

在线运行open in new window启动 AI 助手open in new window

func main() {
	// now := time.Now()
	now := time.Unix(1657628514, 123123123)
	fmt.Println(now)

	tz, _ := time.LoadLocation("America/Chicago")
	// tz, _ := time.LoadLocation("Asia/Shanghai")
	now = now.In(tz)

	fmt.Println(now.Format("2006-01-02 15:04:05"))
	fmt.Println(now.Format("2006-01-02 -07:00"))
	fmt.Println(now.Format("15:04:05 -07:00"))
	fmt.Println(now.Format("2006"))
	fmt.Println(now.Format("-07:00"))

	// fmt.Println(time.RFC3339)
	fmt.Println(now.Format(time.RFC3339))

	// fmt.Println(time.RFC3339Nano)
	fmt.Println(now.Format(time.RFC3339Nano))
}

代码演示了Go语言中关于时间和时区的处理。

首先,代码使用time.Unix()函数将一个Unix时间戳转换为time.Time类型的值,并将该值赋值给now变量。这个时间戳的值是1657628514,表示2022年7月12日16时48分34秒。

然后,代码使用time.LoadLocation()函数来加载一个时区,将当前时间now转换为该时区的时间,并将转换后的时间赋值给now变量。这里使用了"America/Chicago"时区,表示美国中部的标准时间。在实际开发中,应该根据实际需要选择合适的时区来进行处理。

接下来,代码使用now.Format()函数来格式化时间,并将格式化后的字符串输出到标准输出流中。在这里,代码使用了不同的时间格式字符串,例如"2006-01-02 15:04:05"、"2006-01-02 -07:00"、"15:04:05 -07:00"等等。这些格式字符串中的占位符可以帮助开发者格式化时间,例如"2006"表示年份,"01"表示月份,"02"表示日期,"15"表示小时数(24小时制),"04"表示分钟数,"05"表示秒数,"-07:00"表示时区偏移量。在输出时间的同时,代码还使用了time.RFC3339和time.RFC3339Nano常量来格式化时间,这两个常量分别表示RFC3339和RFC3339Nano标准中定义的时间格式。

获得一个小时的时间段

在线运行open in new window启动 AI 助手open in new window

now := time.Now()
hStart := now.Truncate(time.Hour)
hEnd := hStart.Add(time.Hour - time.Nanosecond)

// 2009-11-10T23:00:00Z 2009-11-10T23:59:59Z
fmt.Println(hStart.Format(time.RFC3339), hEnd.Format(time.RFC3339))

// 59m59.999999999s
fmt.Println(hEnd.Sub(hStart))

// 3599.999999999 (3600 秒 - 1)
fmt.Println(hEnd.Sub(hStart).Seconds())

// MongoDB query: bson.M{ "createdAt": {"$gte": hStart, "lte": $hEnd} }
// SqlDB query: Where("created_at >= ? AND created_at <= ?", hStart, hEnd)

代码展示了如何使用Go语言中的time包处理时间。

首先,代码使用time.Now()函数获取当前时间,并将其赋值给now变量。接着,代码使用now.Truncate(time.Hour)函数将now变量的时间戳截断到小时级别,生成一个新的时间戳,将其赋值给hStart变量。这样,hStart变量表示当前时间所在的小时的开始时间。

然后,代码使用hStart.Add(time.Hour - time.Nanosecond)函数来计算当前时间所在的小时的结束时间,并将其赋值给hEnd变量。这里使用了time.Hour和time.Nanosecond常量,分别表示1小时和1纳秒的时间量。

接下来,代码使用hStart.Format(time.RFC3339)和hEnd.Format(time.RFC3339)函数来将hStart和hEnd变量格式化为RFC3339格式的字符串,并将这两个字符串输出到标准输出流中。这里需要注意,RFC3339格式是一种常见的时间格式,常用于在计算机系统之间传输和存储时间信息。

最后,代码使用hEnd.Sub(hStart)函数计算hStart和hEnd之间的时间差,并将其输出到标准输出流中。由于hEnd比hStart晚1纳秒,因此这个时间差是59m59.999999999s。接着,代码使用hEnd.Sub(hStart).Seconds()函数将这个时间差转换为秒数,并将其输出到标准输出流中。由于Go语言的时间处理精度高,因此这个时间差的计算结果为3599.999999999,非常接近3600秒(即1小时)。

需要注意的是,在进行时间计算时,应该使用time.Duration类型来存储时间差,而不是使用float64等其他类型来存储。这样可以确保计算结果的精确性,并避免由于浮点数精度等问题引发的错误。

获得一个月的时间段

在线运行open in new window启动 AI 助手open in new window

now := time.Now()
y, m, _ := now.Date()
loc := now.Location()

start := time.Date(y, m, 1, 0, 0, 0, 0, loc)
// end := start.AddDate(0, 1, -1).Add(24*time.Hour - time.Nanosecond)
end := start.AddDate(0, 1, 0).Add(-time.Nanosecond)

// 2022-08-01 00:00:00 +0800 CST
fmt.Println(start)

// 2022-08-31 23:59:59.999999999 +0800 CST
fmt.Println(end)

代码展示了如何使用Go语言中的time包计算某个月的开始时间和结束时间。

首先,代码使用time.Now()函数获取当前时间,并将其赋值给now变量。然后,代码使用now.Date()函数获取当前时间的年份和月份,并将其分别赋值给y和m变量。接着,代码使用now.Location()函数获取当前时间所在的时区,并将其赋值给loc变量。

接下来,代码使用time.Date()函数构造一个新的时间,表示当前时间所在月份的第一天的开始时间,并将其赋值给start变量。在这里,代码使用y和m变量来表示年份和月份,1表示日期,0表示小时数、分钟数和秒数,loc表示时区。

然后,代码使用start.AddDate(0, 1, 0).Add(-time.Nanosecond)函数计算当前时间所在月份的最后一天的结束时间,并将其赋值给end变量。在这里,代码使用start.AddDate(0, 1, 0)函数将start变量加上一个月的时间量,得到下一个月的开始时间,然后使用Add(-time.Nanosecond)函数将这个时间戳往前推1纳秒,得到当前月份的最后一天的结束时间。这种方式比使用AddDate(0, 1, -1)函数更加简洁和直观。

最后,代码分别使用start和end变量的Format()函数将它们格式化为字符串,并将这两个字符串输出到标准输出流中。这里需要注意,start和end变量的类型都是time.Time,它们的时间戳存储的是UTC时间,但是由于Format()函数会根据时区进行转换,因此输出的时间字符串会显示成本地时间(CST时区)。

获得整点整天的时间值

在线运行open in new window启动 AI 助手open in new window

// t1 := time.Now()
t1, _ := time.Parse("2006-01-02 15:04:05 -0700", "2022-09-03 20:12:30 +0800")
fmt.Println(t1.Format(time.RFC3339Nano))
t1 = t1.Truncate(60 * time.Minute)
fmt.Println(t1.Format(time.RFC3339Nano))

// 指定时区的时间
loc, _ := time.LoadLocation("Asia/Shanghai")
t2 := t1.In(loc)
fmt.Println(t2.Format(time.RFC3339Nano))
t2 = t2.Truncate(time.Hour)
fmt.Println(t2.Format(time.RFC3339Nano))

// 直接用 Date 函数构建,也能很方便的获得整天时间值
t3 := time.Date(2022, 8, 20, 18, 0, 0, 0, loc)
fmt.Println(t3.Format(time.RFC3339Nano))

代码展示了如何使用Go语言中的time包进行时间戳的转换和截取。

首先,代码使用time.Parse()函数将一个字符串解析为一个时间戳,并将其赋值给t1变量。在这里,代码使用"2006-01-02 15:04:05 -0700"格式的字符串作为解析模板,将字符串"2022-09-03 20:12:30 +0800"解析为一个UTC时间戳。接着,代码使用t1.Truncate()函数将t1变量的时间戳截断到小时级别,并将截断后的时间戳重新赋值给t1变量。这里使用了60 * time.Minute作为截断时间,表示将时间戳的分钟数和秒数清零。

然后,代码使用time.LoadLocation()函数加载一个时区,并将其赋值给loc变量。接着,代码使用t1.In(loc)函数将t1变量的时间戳转换为loc时区的时间戳,并将转换后的时间戳赋值给t2变量。这里使用了In()函数来进行时区转换。

接下来,代码使用t2.Truncate()函数将t2变量的时间戳截断到小时级别,并将截断后的时间戳重新赋值给t2变量。这里使用了time.Hour作为截断时间,表示将时间戳的分钟数、秒数和纳秒数清零。

最后,代码使用time.Date()函数直接构建一个时间戳,并将其赋值给t3变量。在这里,代码使用time.Date()函数指定了年份、月份、日期、小时数、分钟数和秒数,将它们组合成一个时间戳,并将其赋值给t3变量。需要注意的是,这里使用了loc变量来指定时区。

判断时间先后和其差值

在线运行open in new window启动 AI 助手open in new window

t1 := time.Now()
t2 := t1.Add(time.Nanosecond)

fmt.Println(t2.After(t1))  // true
fmt.Println(t1.Before(t2)) // true

// 时间差
fmt.Println(t1.Sub(t2)) // -1ns

// 差值的结果是 time.Duration
t3 := t2.Add(time.Hour - time.Nanosecond)
distance := t3.Sub(t1)
fmt.Println(distance)           // 1h0m0s
fmt.Println(distance.Seconds()) // 3600
fmt.Println(distance.Hours())   // 1

代码展示了如何使用Go语言中的time包比较时间戳并计算时间差。

首先,代码使用time.Now()函数获取当前时间戳,并将其赋值给t1变量。然后,代码使用t1.Add()函数将一个纳秒数加到t1变量上,并将得到的时间戳赋值给t2变量。

接下来,代码分别使用t2.After(t1)和t1.Before(t2)函数比较t1和t2两个时间戳的先后顺序,并将比较结果输出到标准输出流中。这里需要注意的是,After()函数表示t2是否在t1之后,而Before()函数表示t1是否在t2之前,它们的返回值类型都是bool。

然后,代码使用t1.Sub(t2)函数计算t2与t1之间的时间差,并将结果输出到标准输出流中。这里需要注意的是,Sub()函数的返回值类型是time.Duration,它表示两个时间戳之间的时间差。

最后,代码使用t3.Sub(t1)函数计算t1和t3之间的时间差,并将结果赋值给distance变量。然后,代码分别使用distance.Seconds()和distance.Hours()函数将时间差转换为秒数和小时数,并将这些值输出到标准输出流中。需要注意的是,time.Duration类型提供了许多用于计算时间差的方法,例如Seconds()函数和Hours()函数。

Last Updated:
Contributors: Bob Wang