golang时间、时区、格式的使用方法
前几天,因为需要实现海外服务端定时停机,涉及到时区的概念。网上搜索了一下,大部分都是谈time.Format中的Layout,非常不成体系,这里就简单总结一下其中的时间初始化、时区转化及格式转换。
开发中,我们对时间的使用是比较多的,其应用场景,按照使用概率,从大到小,通常是:
- 获取当前或数据库中存储的时间
- 比较两个时间点的先后
- 显示打印时间
- 时区转换
对应到go,也就是几个基本定义:
- 时间点与时间段:Time,Duration。好比MVC中的M。
- 时区:Location,在时间转换上,好比是MVC中的C。
- 格式化:Format的layout定义,好比MVC中的V。
单独就Duration没什么好谈的,使用非常简单。Time实例中的Add、Sub与其相关,非常容易上手,就不再多说。
时区
时区是时间运算非常重要的概念,特别强调与layout是两个完全不同的概念。go语言通过Location来作为时区的运行实例,同一时刻转换成为不同的时区,就需要通过不同的Location来进行。默认情况下,采用UTC(unix标准时间),而不是过去式的GMT(格林尼治标准时间)。
以下代码展示了UTC标准、北京、美国洛杉矶在同一时刻的转换:
now:=time.Now() local1,err1:=time.LoadLocation("")//等同于"UTC" iferr1!=nil{ fmt.Println(err1) } local2,err2:=time.LoadLocation("Local")//服务器设置的时区 iferr2!=nil{ fmt.Println(err2) } local3,err3:=time.LoadLocation("America/Los_Angeles") iferr3!=nil{ fmt.Println(err3) } fmt.Println(now.In(local1)) fmt.Println(now.In(local2)) fmt.Println(now.In(local3)) //output: //2016-12-0407:39:06.270473069+0000UTC //2016-12-0415:39:06.270473069+0800CST //2016-12-0323:39:06.270473069-0800PST
代码中,LoadLocation的输入参数的取值,除了该函数的源代码中可看到的”UTC”、”Local”,其余的值其实是遵照“IANATimeZone”的规则,可以解压$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-0215: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中,有非常明确的描述,粘贴一下,就不翻译了:
//ThesearepredefinedlayoutsforuseinTime.FormatandTime.Parse.
//Thereferencetimeusedinthelayoutsisthespecifictime:
//MonJan215:04:05MST2006
//whichisUnixtime1136239445.SinceMSTisGMT-0700,
//thereferencetimecanbethoughtofas
//01/0203:04:05PM‘06-0700
虽然go已经提供了10多个常用格式:
const( ANSIC="MonJan_215:04:052006" UnixDate="MonJan_215:04:05MST2006" RubyDate="MonJan0215:04:05-07002006" RFC822="02Jan0615:04MST" RFC822Z="02Jan0615:04-0700"//RFC822withnumericzone RFC850="Monday,02-Jan-0615:04:05MST" RFC1123="Mon,02Jan200615:04:05MST" RFC1123Z="Mon,02Jan200615:04:05-0700"//RFC1123withnumericzone RFC3339="2006-01-02T15:04:05Z07:00" RFC3339Nano="2006-01-02T15:04:05.999999999Z07:00" Kitchen="3:04PM" //Handytimestamps. Stamp="Jan_215:04:05" StampMilli="Jan_215:04:05.000" StampMicro="Jan_215:04:05.000000" StampNano="Jan_215:04:05.000000000" )
但个人习惯还是“2006-01-0215:04:05Mon”,之前代码稍加修改,就是这样:
formate:="2006-01-0215:04:05Mon" now:=time.Now() local1,err1:=time.LoadLocation("UTC")//输入参数"UTC",等同于"" iferr1!=nil{ fmt.Println(err1) } local2,err2:=time.LoadLocation("Local") iferr2!=nil{ fmt.Println(err2) } local3,err3:=time.LoadLocation("America/Los_Angeles") iferr3!=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-0408:06:39Sun //2016-12-0416:06:39Sun //2016-12-0400:06:39Sun
时间初始化
除了最常用的time.Now,go还提供了通过unix标准时间、字符串两种方式来初始化:
//通过字符串,默认UTC时区初始化Time funcParse(layout,valuestring)(Time,error) //通过字符串,指定时区来初始化Time funcParseInLocation(layout,valuestring,loc*Location)(Time,error) //通过unix标准时间初始化Time funcUnix(secint64,nsecint64)Time
时间初始化的时候,一定要注意原始输入值的时区。正好手里有一个变量,洛杉矶当地时间“2016-11-2819:36:25”,unix时间精确到秒为1480390585。将其解析出来的代码如下:
local,_:=time.LoadLocation("America/Los_Angeles") timeFormat:="2006-01-0215:04:05" //funcUnix(secint64,nsecint64)Time{ time1:=time.Unix(1480390585,0)//通过unix标准时间的秒,纳秒设置时间 time2,_:=time.ParseInLocation(timeFormat,"2016-11-2819: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-2819:36:25 //2016-11-2819:36:25 //2016-11-2911:36:25
当然,如果输入值是字符串,且带有时区
“2016-12-0415:39:06+0800CST”
则不需要采用ParseInLocation方法,直接使用Parse即可。
当然,其他time包中的函数还有很多,但网上已经有很多描述,就不再啰嗦。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。