欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2023-09-06 18:23:01
前几天,因为需要实现海外服务端定时停机,涉及到时区的概念。网上搜索了一下,大部分都是谈time.format中的layout,非常不成体系,这里就简单总结一下其中的时间初始...

前几天,因为需要实现海外服务端定时停机,涉及到时区的概念。网上搜索了一下,大部分都是谈time.format中的layout,非常不成体系,这里就简单总结一下其中的时间初始化、时区转化及格式转换。

开发中,我们对时间的使用是比较多的,其应用场景,按照使用概率,从大到小,通常是:

  1. 获取当前或数据库中存储的时间
  2. 比较两个时间点的先后
  3. 显示打印时间
  4. 时区转换

对应到go,也就是几个基本定义:

  1. 时间点与时间段:time,duration。好比mvc中的m。
  2. 时 区:location,在时间转换上,好比是mvc中的c。
  3. 格式化:format的layout定义,好比mvc中的v。

单独就duration没什么好谈的,使用非常简单。time实例中的add、sub与其相关,非常容易上手,就不再多说。

时区

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

以下代码展示了utc标准、北京、美国洛杉矶在同一时刻的转换:

  now := time.now()
  local1, err1 := time.loadlocation("") //等同于"utc"
  if err1 != nil {
    fmt.println(err1)
  }
  local2, err2 := time.loadlocation("local")//服务器设置的时区
  if err2 != nil {
    fmt.println(err2)
  }
  local3, err3 := time.loadlocation("america/los_angeles")
  if err3 != nil {
    fmt.println(err3)
  }

  fmt.println(now.in(local1))
  fmt.println(now.in(local2))
  fmt.println(now.in(local3))
  //output:
  //2016-12-04 07:39:06.270473069 +0000 utc
  //2016-12-04 15:39:06.270473069 +0800 cst
  //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”也是个方法:

loc, _:= time.loadlocation("asia/chongqing")  //参数就是解压文件的“目录”+“/”+“文件名”。
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”,应该不是真的。请看下表:

01/jan 02 03/15 04 05 06 -07[00][:00] pm mon
时差 上下午 星期几

也就是1234567,分别对应:月日时分秒年 时差,很好记忆。只是稍微注意一下:

  • 月:01或jan都可以
  • 小时:03表示12小时制,15表示24小时制。
  • 时差:是 -07 ,不是 07,后边可以增加“00”或“:00”,表示更进一步的分秒时差。
  • 上下午:使用pm,不是am。
  • 摆放顺序:随意,甚至重复都可以。源代码包也有定义的常用格式供使用。

也许是因为06对应的“年”与go的项目启动时间差不多,也就有了网上的误传。在源代码time/time.go中,有非常明确的描述,粘贴一下,就不翻译了:

// these are predefined layouts for use in time.format and time.parse.
// the reference time used in the layouts is the specific time:
// mon jan 2 15:04:05 mst 2006
// which is unix time 1136239445. since mst is gmt-0700,
// the reference time can be thought of as
// 01/02 03:04:05pm ‘06 -0700

虽然go已经提供了10多个常用格式:

const (
  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"
)

但个人习惯还是“2006-01-02 15:04:05 mon”,之前代码稍加修改,就是这样:

  formate:="2006-01-02 15:04:05 mon"
  now := time.now()
  local1, err1 := time.loadlocation("utc") //输入参数"utc",等同于""
  if err1 != nil {
    fmt.println(err1)
  }
  local2, err2 := time.loadlocation("local")
  if err2 != nil {
    fmt.println(err2)
  }
  local3, err3 := time.loadlocation("america/los_angeles")
  if err3 != nil {
    fmt.println(err3)
  }

  fmt.println(now.in(local1).format(formate))
  fmt.println(now.in(local2).format(formate))
  fmt.println(now.in(local3).format(formate))
  //output:
  //2016-12-04 08:06:39 sun
  //2016-12-04 16:06:39 sun
  //2016-12-04 00:06:39 sun

时间初始化

除了最常用的time.now,go还提供了通过unix标准时间、字符串两种方式来初始化:

//通过字符串,默认utc时区初始化time
func parse(layout, value string) (time, error) 
//通过字符串,指定时区来初始化time
func parseinlocation(layout, value string, loc *location) (time, error) 

//通过unix 标准时间初始化time
func unix(sec int64, nsec int64) time 

时间初始化的时候,一定要注意原始输入值的时区。正好手里有一个变量,洛杉矶当地时间“2016-11-28 19:36:25”,unix时间精确到秒为1480390585。将其解析出来的代码如下:

  local, _ := time.loadlocation("america/los_angeles")
  timeformat := "2006-01-02 15:04:05"
  //func unix(sec int64, nsec int64) time {
  time1 := time.unix(1480390585, 0)                           //通过unix标准时间的秒,纳秒设置时间
  time2, _ := time.parseinlocation(timeformat, "2016-11-28 19:36:25", local) //洛杉矶时间
  fmt.println(time1.in(local).format(timeformat))
  fmt.println(time2.in(local).format(timeformat))
  chinalocal, _ := time.loadlocation("local")//运行时,该服务器必须设置为中国时区,否则最好是采用"asia/chongqing"之类具体的参数。
  fmt.println(time2.in(chinalocal).format(timeformat))
  //output:
  //2016-11-28 19:36:25
  //2016-11-28 19:36:25
  //2016-11-29 11:36:25

当然,如果输入值是字符串,且带有时区

“2016-12-04 15:39:06 +0800 cst”

则不需要采用parseinlocation方法,直接使用parse即可。

当然,其他time包中的函数还有很多,但网上已经有很多描述,就不再啰嗦。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。