golang时间、时区、格式的使用方法

[复制链接]
查看2208 | 回复0 | 2019-6-10 10:33:57 | 显示全部楼层 |阅读模式
开发中,我们对时间的使用是比较多的,其应用场景,按照使用概率,从大到小,通常是:
  • 获取当前或数据库中存储的时间
  • 比较两个时间点的先后
  • 显示打印时间
  • 时区转换
对应到go,也就是几个基本定义:
  • 时间点与时间段:Time,Duration。好比MVC中的M。
  • 时 区:Location,在时间转换上,好比是MVC中的C。
  • 格式化:Format的layout定义,好比MVC中的V。
单独就Duration没什么好谈的,使用非常简单。Time实例中的Add、Sub与其相关,非常容易上手,就不再多说。
时区

时区是时间运算非常重要的概念,特别强调与layout是两个完全不同的概念。go语言通过Location来作为时区的运行实例,同一时刻转换成为不同的时区,就需要通过不同的Location来进行。默认情况下,采用UTC(unix标准时间),而不是过去式的GMT(格林尼治标准时间)。


以下代码展示了UTC标准、北京、美国洛杉矶在同一时刻的转换:
  1. now := time.Now()
  2. local1, err1 := time.LoadLocation("") //等同于"UTC"
  3. if err1 != nil {
  4.   fmt.Println(err1)
  5. }
  6. local2, err2 := time.LoadLocation("Local")//服务器设置的时区
  7. if err2 != nil {
  8.   fmt.Println(err2)
  9. }
  10. local3, err3 := time.LoadLocation("America/Los_Angeles")
  11. if err3 != nil {
  12.   fmt.Println(err3)
  13. }

  14. fmt.Println(now.In(local1))
  15. fmt.Println(now.In(local2))
  16. fmt.Println(now.In(local3))
  17. //output:
  18. //2016-12-04 07:39:06.270473069 +0000 UTC
  19. //2016-12-04 15:39:06.270473069 +0800 CST
  20. //2016-12-03 23:39:06.270473069 -0800 PST
复制代码
代码中,LoadLocation的输入参数的取值,除了该函数的源代码中可看到的”UTC”、”Local”,其余的值其实是遵照“IANA Time Zone”的规则,可以解压$GOROOT/lib/time/zoneinfo.zip 这个文件打开查看。在Asia这个目录,我看到了Chongqing,Hong_Kong,但没Beijing。在国外获取中国北京时间,要用”PRC”,当然”Asia/Chongqing”也是个方法:
  1. loc, _:= time.LoadLocation("Asia/Chongqing")  //参数就是解压文件的“目录”+“/”+“文件名”。
  2. fmt.Println(time.Now().In(loc))
复制代码
值得强调的是,Location仅用于时区转化,而不对time内部的数据产生影响(内部其实是unix标准时),因此,当几个time实例进行Add、Sub的时候,不用关注Location是否相同。
时间格式化

前面例子中,打印结果非常丑陋,通常没人关心秒之后的ns;明确时区后,很少需要与UTC的时差。这时候,就需要定义我们的layout了。
网上好多都说,“2006-01-02 15:04:05是go的诞生时间,所以这么设计Format的Layout”,应该不是真的。请看下表:
QQ截图20190610103105.jpg

也就是1234567,分别对应:月日时分秒年 时差,很好记忆。只是稍微注意一下:
  • 月:01或Jan都可以
  • 小时:03表示12小时制,15表示24小时制。
  • 时差:是 -07 ,不是 07,后边可以增加“00”或“:00”,表示更进一步的分秒时差。
  • 上下午:使用PM,不是AM。
  • 摆放顺序:随意,甚至重复都可以。源代码包也有定义的常用格式供使用。
也许是因为06对应的“年”与go的项目启动时间差不多,也就有了网上的误传。在源代码time/time.go中,有非常明确的描述,粘贴一下,就不翻译了:
  1. // These are predefined layouts for use in Time.Format and Time.Parse.
  2. // The reference time used in the layouts is the specific time:
  3. // Mon Jan 2 15:04:05 MST 2006
  4. // which is Unix time 1136239445. Since MST is GMT-0700,
  5. // the reference time can be thought of as
  6. // 01/02 03:04:05PM ‘06 -0700
复制代码
虽然go已经提供了10多个常用格式:
  1. const (
  2.   ANSIC    = "Mon Jan _2 15:04:05 2006"
  3.   UnixDate  = "Mon Jan _2 15:04:05 MST 2006"
  4.   RubyDate  = "Mon Jan 02 15:04:05 -0700 2006"
  5.   RFC822   = "02 Jan 06 15:04 MST"
  6.   RFC822Z   = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
  7.   RFC850   = "Monday, 02-Jan-06 15:04:05 MST"
  8.   RFC1123   = "Mon, 02 Jan 2006 15:04:05 MST"
  9.   RFC1123Z  = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
  10.   RFC3339   = "2006-01-02T15:04:05Z07:00"
  11.   RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
  12.   Kitchen   = "3:04PM"
  13.   // Handy time stamps.
  14.   Stamp   = "Jan _2 15:04:05"
  15.   StampMilli = "Jan _2 15:04:05.000"
  16.   StampMicro = "Jan _2 15:04:05.000000"
  17.   StampNano = "Jan _2 15:04:05.000000000"
  18. )
复制代码
但个人习惯还是“2006-01-02 15:04:05 Mon”,之前代码稍加修改,就是这样:
  1. formate:="2006-01-02 15:04:05 Mon"
  2. now := time.Now()
  3. local1, err1 := time.LoadLocation("UTC") //输入参数"UTC",等同于""
  4. if err1 != nil {
  5.   fmt.Println(err1)
  6. }
  7. local2, err2 := time.LoadLocation("Local")
  8. if err2 != nil {
  9.   fmt.Println(err2)
  10. }
  11. local3, err3 := time.LoadLocation("America/Los_Angeles")
  12. if err3 != nil {
  13.   fmt.Println(err3)
  14. }

  15. fmt.Println(now.In(local1).Format(formate))
  16. fmt.Println(now.In(local2).Format(formate))
  17. fmt.Println(now.In(local3).Format(formate))
  18. //output:
  19. //2016-12-04 08:06:39 Sun
  20. //2016-12-04 16:06:39 Sun
  21. //2016-12-04 00:06:39 Sun
复制代码
时间初始化
除了最常用的time.Now,go还提供了通过unix标准时间、字符串两种方式来初始化:
  1. //通过字符串,默认UTC时区初始化Time
  2. func Parse(layout, value string) (Time, error)
  3. //通过字符串,指定时区来初始化Time
  4. func ParseInLocation(layout, value string, loc *Location) (Time, error)

  5. //通过unix 标准时间初始化Time
  6. func Unix(sec int64, nsec int64) Time
复制代码
时间初始化的时候,一定要注意原始输入值的时区。正好手里有一个变量,洛杉矶当地时间“2016-11-28 19:36:25”,unix时间精确到秒为1480390585。将其解析出来的代码如下:
  1. local, _ := time.LoadLocation("America/Los_Angeles")
  2. timeFormat := "2006-01-02 15:04:05"
  3. //func Unix(sec int64, nsec int64) Time {
  4. time1 := time.Unix(1480390585, 0)                           //通过unix标准时间的秒,纳秒设置时间
  5. time2, _ := time.ParseInLocation(timeFormat, "2016-11-28 19:36:25", local) //洛杉矶时间
  6. fmt.Println(time1.In(local).Format(timeFormat))
  7. fmt.Println(time2.In(local).Format(timeFormat))
  8. chinaLocal, _ := time.LoadLocation("Local")//运行时,该服务器必须设置为中国时区,否则最好是采用"Asia/Chongqing"之类具体的参数。
  9. fmt.Println(time2.In(chinaLocal).Format(timeFormat))
  10. //output:
  11. //2016-11-28 19:36:25
  12. //2016-11-28 19:36:25
  13. //2016-11-29 11:36:25
复制代码
当然,如果输入值是字符串,且带有时区
  1. “2016-12-04 15:39:06 +0800 CST”
复制代码
则不需要采用ParseInLocation方法,直接使用Parse即可。
当然,其他time包中的函数还有很多,但网上已经有很多描述
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则