golang积累-时间、时区、格式的使用

alex_023 · · 23975 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

以下文章转自自己的博客:http://blog.csdn.net/qq_26981997/article/details/53454606 , 对格式稍加整理。 前几天,因为需要实现海外服务端定时停机,涉及到时区的概念。网上搜索了一下,大部分都是谈time.Format中的Layout,非常不成体系,这里就简单总结一下其中的时间初始化、时区转化及格式转换。 开发中,我们对时间的使用是比较多的,其应用场景,按照使用概率,从大到小,通常是: 1. 获取当前或数据库中存储的时间 2. 比较两个时间点的先后 3. 显示打印时间 4. 时区转换 对应到go,也就是几个基本定义: 5. 时间点与时间段:Time,Duration。好比MVC中的M。 6. 时 区:Location,在时间转换上,好比是MVC中的C。 7. 格式化:Format的layout定义,好比MVC中的V。 单独就Duration没什么好谈的,使用非常简单。Time实例中的Add、Sub与其相关,非常容易上手,就不再多说。 ## 时区 时区是时间运算非常重要的概念,特别强调与layout是两个完全不同的概念。go语言通过Location来作为时区的运行实例,同一时刻转换成为不同的时区,就需要通过不同的Location来进行。默认情况下,采用UTC(unix标准时间),而不是过去式的GMT(格林尼治标准时间)。 以下代码展示了UTC标准时间、北京时间、美国洛杉矶时间在同一时刻的转换: ```go 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"也是个方法: ```go 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”,应该不是真的。请看下表: ![屏幕快照 2016-12-04 17.30.02.png](http://studygolang.qiniudn.com/161204/f93027ac752cd433fb19242e9ef65478.png) 也就是说,1234567,分别对应:月日时分秒 上|下午 年 时差。注意: - 月:01或Jan都可以 - 小时:03表示12小时制,15表示24小时制。 - 时差:是 -07 ,不是 07,后边可以增加“00”或“:00”,表示更进一步的分秒时差。 - 上下午:使用PM,不是AM。 - 摆放顺序:随意,甚至重复都可以。源代码包也有定义的常用的摆放方式供使用。 也许是因为06对应的“年”与go的项目启动时间差不多,也就有了网上的误传。在源代码time/time.go中,有非常明确的描述,粘贴一下,就不翻译了: ```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多个常用格式: ```Go 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”,之前代码稍加修改,就是这样: ```go 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标准时间、字符串两种方式来初始化: ```go //通过字符串,默认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。将其解析出来的代码如下: ```go 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包中的函数还有很多,但网上已经有很多描述,就不再啰嗦。

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

23975 次点击  ∙  1 赞  
加入收藏 微博
3 回复  |  直到 2023-03-07 17:02:52
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传