go time.Parse的一些小知识
之前都是写在笔记里,搬到csdn上。。。
- go的time.Parse
- 时区问题
- layout模版
- 总结
go的time.Parse
在自己写东西时,遇到了时间转换的一些小问题。 首先是 time.Parse(layout, value), go语言提供的layout模版和我个人使用都略有差别, 转换使用很不习惯。 第二就是时区问题, 服务器的时区不一定是符合国内时区的。
时区问题
时区问题可以使用time.ParseInLocation, 但是涉及到时区定义。
查看源码定义(/time/format.go)
// 参数1还是layout
// 参数2是value
// 参数3比parse多了一个 "Location"
func ParseInLocation(layout, value string, loc *Location) (Time, error) {return parse(layout, value, loc, loc)
}
发现时区Location 是个结构体, 追进去看定义(/time/zoneinfo.go文件)
//go:generate env ZONEINFO=$GOROOT/lib/time/zoneinfo.zip go run genzabbrs.go -output zoneinfo_abbrs_windows.go
// 省略部分注释
type Location struct {name stringzone []zonetx []zoneTrans// 省略部分定义
}
重点是 go generate 的这一行, 是go自带的命令, 在运行时, 将后面的内容注释解析成命令执行. (还想了解更深的请自行查找)
其实需要的是 ZONEINFO=$GOROOT/lib/time/zoneinfo.zip, 也就是可以从这个路径找到对应的时区包文件。
然后在包中发现 Asia地区 关于中国的时区只有两个, 一个是Shanghai, 另一个是Chongqing。 一开始不明白的时候傻呵呵的写了 “Asia/Beijing” 然后发现并没有什么卵用。。
oldTime := "2019-07-31T17:12:00Z"
location, error := time.LoadLocation("Asia/Chongqing")
time, _ := time.ParseInLocation(time.RFC3339, oldTime, location)
fmt.Println(time) // 2019-07-31 17:12:00 +0000 UTC
layout模版
time/format.go文件中包含所有的预定义 layout
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 zoneRFC850 = "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 zoneRFC3339 = "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年1月2日 下午3点4分5秒 周一"
目前听到的最多的声音是 “这是go语言的生日”。(目前我知道的最早的生日是2009-10-11), 但从源码中可以看到一些端倪:
从time.Parse方法进入, 会进入一个内部的方法, 通过查找layout关键词, 找到了解析的方法 nextStdChunk
func parse(layout, value string, defaultLocation, local *Location) (Time, error) {...前面省略
prefix, std, suffix := nextStdChunk(layout)
...后面省略
}
解析方法就是逐个字母遍历我们传递的layout, (类似于java中 String.charAt()),
随机打开其中的几个
case 'J': // January, Janif len(layout) >= i+3 && layout[i:i+3] == "Jan" {if len(layout) >= i+7 && layout[i:i+7] == "January" {return layout[0:i], stdLongMonth, layout[i+7:]}if !startsWithLowerCase(layout[i+3:]) {return layout[0:i], stdMonth, layout[i+3:]}}
case '3':return layout[0:i], stdHour12, layout[i+1:]
case '5':return layout[0:i], stdSecond, layout[i+1:]
case 'P': // PMif len(layout) >= i+2 && layout[i+1] == 'M' {return layout[0:i], stdPM, layout[i+2:]}
case 'Z': // Z070000, Z07:00:00, Z0700, Z07:00,if len(layout) >= i+7 && layout[i:i+7] == "Z070000" {return layout[0:i], stdISO8601SecondsTZ, layout[i+7:]}if len(layout) >= i+9 && layout[i:i+9] == "Z07:00:00" {return layout[0:i], stdISO8601ColonSecondsTZ, layout[i+9:]}if len(layout) >= i+5 && layout[i:i+5] == "Z0700" {return layout[0:i], stdISO8601TZ, layout[i+5:]}if len(layout) >= i+6 && layout[i:i+6] == "Z07:00" {return layout[0:i], stdISO8601ColonTZ, layout[i+6:]}if len(layout) >= i+3 && layout[i:i+3] == "Z07" {return layout[0:i], stdISO8601ShortTZ, layout[i+3:]}
一切都豁然开朗, 解析其实是 将固定的字母/数字/符号 作为特殊的标志,作为特殊的位置, 在结合强力的分析, 通过截取固定的位数来判断具体属于哪种layout及每个时段的表现形式。
例如
字母 J 代表的是 月份(month)
数字 3 代表的是 小时(hour)
数字5 代表的是秒
字母P/p 代表的是 PM/pm
字母Z 代表的是具体展现形式。
and so on。
可以看到, go在内部解析是将 字母和数字分割开来,并且互相不会有影响。 但如果我们随意编写时间layout, 比如"2019-07-31 12:32:12"。结果就是比较难预测的。
所有的解析字段也在time/format.go里有常量定义:
const (_ = iotastdLongMonth = iota + stdNeedDate // "January"stdMonth // "Jan"stdNumMonth // "1"stdZeroMonth // "01"stdLongWeekDay // "Monday"stdWeekDay // "Mon"stdDay // "2"stdUnderDay // "_2"stdZeroDay // "02"stdHour = iota + stdNeedClock // "15"stdHour12 // "3"stdZeroHour12 // "03"stdMinute // "4"stdZeroMinute // "04"stdSecond // "5"stdZeroSecond // "05"stdLongYear = iota + stdNeedDate // "2006"stdYear // "06"stdPM = iota + stdNeedClock // "PM"stdpm // "pm"stdTZ = iota // "MST"stdISO8601TZ // "Z0700" // prints Z for UTCstdISO8601SecondsTZ // "Z070000"stdISO8601ShortTZ // "Z07"stdISO8601ColonTZ // "Z07:00" // prints Z for UTCstdISO8601ColonSecondsTZ // "Z07:00:00"stdNumTZ // "-0700" // always numericstdNumSecondsTz // "-070000"stdNumShortTZ // "-07" // always numericstdNumColonTZ // "-07:00" // always numericstdNumColonSecondsTZ // "-07:00:00"stdFracSecond0 // ".0", ".00", ... , trailing zeros includedstdFracSecond9 // ".9", ".99", ..., trailing zeros omittedstdNeedDate = 1 << 8 // need month, day, yearstdNeedClock = 2 << 8 // need hour, minute, secondstdArgShift = 16 // extra argument in high bits, above low stdArgShiftstdMask = 1<<stdArgShift - 1 // mask out argument
)
所以在自定义layout的时候 一定要遵循这个时间规范, "2006年1月2日 下午3点4分5秒 周一"
或者一个小顺口溜(来源于studygolang.com的徐大) : “1月2日3点4分5秒6年7时区” 刚好是1234567
像我个人常用的时间表示类似于 -> “2019-08-01 13:20:05”
// java写法
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.format(date);// php写法
(new Datetime())->modify("")->format('Y-m-d H:i:s');// go写法
oldTime := "2019-07-31T17:12:00Z"
// 当然 不用时区 直接time.Parse()也是可以的
location, error := time.LoadLocation("Asia/Chongqing")
time, _ := time.ParseInLocation(time.RFC3339, oldTime, location)
time.Format("2006-01-02 15:04:05")
总结
go的这个时间解析layout的设计还是非常巧妙的, 虽然对新手仿佛不是那么友好~ 尤其一上来这个时间戳让人有点摸不到头脑。
更多的使用例子在 /time/example_test.go文件中, 也有许多注释说明。
go time.Parse的一些小知识相关推荐
- json string 格式_GO小知识之如何做JSON美化
经常有些小知识想分享出来,但又构不成体系,一直觉得文章形式发出不太合适.准备以 "知乎想法" 分享出来,但发现代码展示不太友好.还是发文章吧,该类分享将以 "小知识&qu ...
- 【C#小知识】C#中一些易混淆概念总结(三)---------结构,GC,静态成员,静态类...
目录: [C#小知识]C#中一些易混淆概念总结 [C#小知识]C#中一些易混淆概念总结(二) ---------------------------------------分割线----------- ...
- 【C#小知识】C#中一些易混淆概念总结(七)---------解析抽象类,抽象方法
目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...
- GO小知识之实例演示 json 如何转化为 map 和 struct
今天简单谈一些 JSON 数据处理的小知识.近期工作中,因为要把数据库数据实时更新到 elasticsearch,在实践过程中遇到了一些 JSON 数据处理的问题. 实时数据 实时数据获取是通过阿里开 ...
- 1 编码_TMS320F28379D之CLB解码多摩川编码器1——入手小知识(原创)
今天,跟大家分享一下28379D的CLB解码多摩川绝对值编码器的一些入手小知识. 首先,28379是属于TI的2837x系列,D是双核版本,S是单核版本,S和D都是带CLB模块的,都可以实现位置解码, ...
- sam格式的结构和意义_BAM/SAM文件格式的一些小知识
BAM/SAM文件的一些小知识 前言 如果不是在陈老师这读博,然后开始折腾BAM/SAM文件,我估计这辈子都不会了解到这么多东西吧 SAM/BAM简介 Sequence Alignment Map ( ...
- 安卓开发小知识 - 3
内容来源:Android Development Tidbits // No. 3 这是第三次分享安卓开发中的一些小知识点.我们很高兴有这么多人知道了这个有趣的系列,并且对你们通过评论和邮件表达的支持 ...
- 蓝牙Bluetooth技术小知识
蓝牙Bluetooth技术以及广泛的应用于各种设备,并将继续在物联网IoT领域担任重要角色.下面搜集整理了一些关于蓝牙技术的小知识,以备参考. 蓝牙Bluetooth技术始创于1994年,其名字来源于 ...
- jquery/css需要记录的小知识(持续补充)
一.前言 2020年的第一篇了,奥利给! 这部分主要是汇总一些平时遇到的jquery和css小知识,作为笔记使用. 二.正文 1.jquery模拟select下拉框的选择事件,并传参数: self.s ...
最新文章
- 算法-------矩阵中的最长递增路径(Java版本)
- openstack运维实战系列(十)之nova指定compute节点和IP地址
- 启明云端分享| ESP32-S3支持自定义离线语音,可支持 200 条本地命令语句,无需外加 DSP 芯片
- linux 文件夹 含义 表示(转)
- Vue.js实战之Vuex的入门教程
- python正则匹配找到所有的浮点数_Python随笔17:Python正则表达式基础(4):贪婪匹配和最小匹配...
- php进阶课程,php进阶教程学习
- kvm 调试内核方法
- 【 Perl 】三种方式解决” Wide character in print “
- java高并发之线程池
- dev、test、prod、pre是什么意思?
- Google Chrome浏览器导入导出书签
- Base64的Woff2字体信息如何转成成文件
- 微信服务器下载图片到服务器格式损坏问题解决
- M个苹果放在N个盘子里,有多少种不同的放法
- python算闰年和平年的天数_如何判断闰年和平年的方法有哪些-百度经验
- 小网站云服务器配置推荐,小网站云服务器配置推荐
- 龙果支付 mysql_龙果开源支付系统搭建与部署
- 聊一聊搭建一个网站到底有几步?
- 红帽linux怎么截图,Linux上使用Ksnip截图