形成肌肉记忆是一件好事,大脑可以从低级工作中解放出来在潜意识思考高级问题。 锻炼肌肉记忆的一种方法就是将需要训练的内容整理出来,反复练习即可。

Python中的 datetime 模块已经相当熟练,几乎不再需要翻文档。 Golang 写得还不多, 同样整理一遍,多加练习。

如果想不起来,多翻翻文档,大多数情景在标准库里都可以解决。

package main

import (
	"fmt"
	"log"
	"time"
)

func main() {

	var err error

	// 1. 当前时间
	log.Println("===== 1. current time =====")

	// 1.1 获取当前时间 (带时区信息)
	now := time.Now()
	log.Printf("now: %s", now)

	// 1.2 获取当前时间戳 int64 (获取任何 Time 对象的时间戳)
	timestamp := time.Now().Unix()
	log.Printf("timestamp: %d", timestamp)

	// 1.3 获取当前时间戳纳秒 int64 (获取任何 Time 对象的时间戳)
	timestampNano := time.Now().UnixNano()
	log.Printf("timestampNano: %d", timestampNano)

	// 1.4 获取 UTC 时间 (获取任何 Time 对象对应的 UTC 时间)
	utc := time.Now().UTC()
	log.Printf("utc: %s", utc)

	// 2. 格式化
	// Format 的字符串不是 UNIX STRFTIME(3)
	// 而是 golang 自己定的规则,cheatsheet 请参考
	// https://yourbasic.org/golang/format-parse-string-time-date-example/

	// 特别说明:
	// - 24-小时格式时,无法指定不带 0 前缀的小时格式
	// - 表示半夜时间不可使用 24:00 只能带上日期一起使用
	// - 不支持润秒 23:59:60 , golang time 包假设没有润秒的公历

	// 格式化记忆方法,考虑以下表示法,更容易理解
	// 01/02 03:04:05PM '06 -0700
	// 表示 -7 时区 , 2006 年,(上午)3点4分5秒,1月2日
	// 那么想表达24小时制时,应该使用什么呢? 15:04:05

	// 完整格式速查
	// Type         Option
	// -------------------
	// Year         06 2006
	// Month        01 1 Jan January
	// Day          02 2 _2 (width two, right justified)
	// Weekday      Mon Monday
	// Hours        03 3 15
	// Minutes      04 4
	// Seconds      05 5
	// ms us ns     .000 .000000 .000000000
	// ms us ns     .999 .999999 .999999999 (remove trailing zero)
	// am/pm        PM pm
	// Timezone     MST
	// Offset       -0700 -07 -07:00 Z0700 Z07:00

	log.Println("")
	log.Println("")
	log.Println("===== 2. format (Time -> string) =====")

	// 2.1 最常见的格式
	log.Printf("%%Y-%%m-%%d %%H:%%M:%%S: %s",
		now.Format("2006-01-02 15:04:05"))

	// 2.2 RFC3389 格式
	log.Printf("RFC3389: %s", now.Format(time.RFC3339))

	// 2.3 ISO886 周
	_, w := now.ISOWeek()
	log.Printf("ISO8601 Week: %d", w)

	// 3. 从字符串得到对应的时间
	log.Println("")
	log.Println("")
	log.Println("===== 3. parse (string -> Time) =====")

	// 3.1 RFC3389 (带时区)
	var t2 time.Time
	rfc3339 := "2019-01-20T16:45:34+08:00"
	t2, err = time.Parse(time.RFC3339, rfc3339)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("\"%s\" => %s", rfc3339, t2)

	// 3.2 日期 没有时区 (需加上,否则默认得到 UTC 时间)
	date := "2019-07-11"
	input := fmt.Sprintf("%s+0800", date)
	t2, err = time.Parse("2006-01-02-0700", input)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("\"%s\" => %s", date, t2)

	// 3.3 日期时间 没有时区 (需加上,否则默认得到 UTC 时间)
	date2 := "2008-12-31 09:12:47"
	input2 := fmt.Sprintf("%s +0800", date2)
	t2, err = time.Parse("2006-01-02 15:04:05 -0700", input2)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("\"%s\" => %s", date2, t2)

	// 3.4 时间,有小数点  (需加上,否则默认得到 UTC 时间)
	date3 := "15:37:00.965376860"
	t2, err = time.Parse("15:04:05.000000000", date3)
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("\"%s\" => %s", date3, t2)

	// 4. 从时间戳得到时间
	// 定义上时间戳本身是 UTC ,转换出来会根据系统配置设计设置时区
	log.Println("")
	log.Println("")
	log.Println("===== 4. parse (int timestamp -> Time) =====")
	i1 := int64(1562922019)
	t3 := time.Unix(i1, 0)
	log.Printf("%d => %v", i1, t3)

	// 5. 时间的比较
	log.Println("")
	log.Println("")
	log.Println("===== 5. compare  =====")

	// 需注意, == 操作会比较小数点以后的
	// Equal 操作则会考虑时区
	nt1 := time.Now()
	nt2 := time.Now()
	log.Printf("%v > %v ?: %t", nt1, nt2, nt1.After(nt2))
	log.Printf("%v == %v ?: %t", nt1, nt2, nt1.Equal(nt2))
	log.Printf("%v < %v ?: %t", nt1, nt2, nt1.Before(nt2))

	// 6. 时间计算
	log.Println("")
	log.Println("")
	log.Println("===== 5. calculate  =====")
	after := time.Now()

	// 6.1 差值 (都利用 Sub 方法) 返回 time.Duration
	d1 := now.Sub(after)
	log.Printf("%v = now - %v", d1, after)
	d2 := after.Sub(now)
	log.Printf("%v = %v - now", d2, after)

	// 6.2 加减操作 () 参数为 time.Duration
	second := 240
	nt3 := now.Add(time.Duration(second) * time.Second)
	log.Printf("now + %ds = %v", second, nt3)

	nt4 := now.Add(-time.Duration(second) * time.Second)
	log.Printf("now - %ds = %v", second, nt4)

	// 7. 时区操作
	// 时区定义请参考 https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
	log.Println("")
	log.Println("")
	log.Println("===== 7. timezone  =====")

	var zoneName string
	var location *time.Location

	log.Printf("now location: \"%v\"", now.Location())

	// 7.1 加载地区信息
	zoneName = "US/Alaska"
	location, err = time.LoadLocation(zoneName)
	log.Printf("\"%s\" location: %v", zoneName, location)

	// 7.2 得到不同时区的时间
	log.Printf("now in \"%v\": %v", location, now.In(location))
	zoneName = "Asia/Tokyo"
	location, err = time.LoadLocation(zoneName)
	log.Printf("\"%s\" location: %v", zoneName, location)
	log.Printf("now in \"%v\": %v", location, now.In(location))
}