之前都是写在笔记里,搬到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的一些小知识相关推荐

  1. json string 格式_GO小知识之如何做JSON美化

    经常有些小知识想分享出来,但又构不成体系,一直觉得文章形式发出不太合适.准备以 "知乎想法" 分享出来,但发现代码展示不太友好.还是发文章吧,该类分享将以 "小知识&qu ...

  2. 【C#小知识】C#中一些易混淆概念总结(三)---------结构,GC,静态成员,静态类...

    目录: [C#小知识]C#中一些易混淆概念总结 [C#小知识]C#中一些易混淆概念总结(二) ---------------------------------------分割线----------- ...

  3. 【C#小知识】C#中一些易混淆概念总结(七)---------解析抽象类,抽象方法

    目录: [C#小知识]C#中一些易混淆概念总结--------数据类型存储位置,方法调用,out和ref参数的使用 [C#小知识]C#中一些易混淆概念总结(二)--------构造函数,this关键字 ...

  4. GO小知识之实例演示 json 如何转化为 map 和 struct

    今天简单谈一些 JSON 数据处理的小知识.近期工作中,因为要把数据库数据实时更新到 elasticsearch,在实践过程中遇到了一些 JSON 数据处理的问题. 实时数据 实时数据获取是通过阿里开 ...

  5. 1 编码_TMS320F28379D之CLB解码多摩川编码器1——入手小知识(原创)

    今天,跟大家分享一下28379D的CLB解码多摩川绝对值编码器的一些入手小知识. 首先,28379是属于TI的2837x系列,D是双核版本,S是单核版本,S和D都是带CLB模块的,都可以实现位置解码, ...

  6. sam格式的结构和意义_BAM/SAM文件格式的一些小知识

    BAM/SAM文件的一些小知识 前言 如果不是在陈老师这读博,然后开始折腾BAM/SAM文件,我估计这辈子都不会了解到这么多东西吧 SAM/BAM简介 Sequence Alignment Map ( ...

  7. 安卓开发小知识 - 3

    内容来源:Android Development Tidbits // No. 3 这是第三次分享安卓开发中的一些小知识点.我们很高兴有这么多人知道了这个有趣的系列,并且对你们通过评论和邮件表达的支持 ...

  8. 蓝牙Bluetooth技术小知识

    蓝牙Bluetooth技术以及广泛的应用于各种设备,并将继续在物联网IoT领域担任重要角色.下面搜集整理了一些关于蓝牙技术的小知识,以备参考. 蓝牙Bluetooth技术始创于1994年,其名字来源于 ...

  9. jquery/css需要记录的小知识(持续补充)

    一.前言 2020年的第一篇了,奥利给! 这部分主要是汇总一些平时遇到的jquery和css小知识,作为笔记使用. 二.正文 1.jquery模拟select下拉框的选择事件,并传参数: self.s ...

最新文章

  1. 算法-------矩阵中的最长递增路径(Java版本)
  2. openstack运维实战系列(十)之nova指定compute节点和IP地址
  3. 启明云端分享| ESP32-S3支持自定义离线语音,可支持 200 条本地命令语句,无需外加 DSP 芯片
  4. linux 文件夹 含义 表示(转)
  5. Vue.js实战之Vuex的入门教程
  6. python正则匹配找到所有的浮点数_Python随笔17:Python正则表达式基础(4):贪婪匹配和最小匹配...
  7. php进阶课程,php进阶教程学习
  8. kvm 调试内核方法
  9. 【 Perl 】三种方式解决” Wide character in print “
  10. java高并发之线程池
  11. dev、test、prod、pre是什么意思?
  12. Google Chrome浏览器导入导出书签
  13. Base64的Woff2字体信息如何转成成文件
  14. 微信服务器下载图片到服务器格式损坏问题解决
  15. M个苹果放在N个盘子里,有多少种不同的放法
  16. python算闰年和平年的天数_如何判断闰年和平年的方法有哪些-百度经验
  17. 小网站云服务器配置推荐,小网站云服务器配置推荐
  18. 龙果支付 mysql_龙果开源支付系统搭建与部署
  19. 聊一聊搭建一个网站到底有几步?
  20. 红帽linux怎么截图,Linux上使用Ksnip截图

热门文章

  1. iOS 远程消息推送,原理和开发详解篇(新手推荐)
  2. asp.net 微信企业号 微企办公系统-部门人员同步
  3. 如何解决kaldi的依赖库mkl安装失败的问题
  4. orcal中降序,空值处理
  5. 图像处理-双边滤波和联合双边滤波
  6. 双边滤波原理与参数的理解+双边滤波matlab实现
  7. jumpserver安装使用
  8. SQL --- 数据的筛选与排序
  9. Presentation201606(The Sketchy Database-Learning to Retrieve Badly Drawn Bunnies)
  10. python爬取网站验证码并保存