解析Go中的RFC-3339 / ISO-8601日期-时间字符串

我尝试在Go中解析日期字符串"2014-09-12T11:45:26.371Z"。此时间格式定义为:

代码

layout := "2014-09-12T11:45:26.371Z"
str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(layout , str)

我得到了这个错误:

解析时间“2014-11-12T11:47:39.489Z"月超出范围

我如何解析这个日期字符串?

363035 次浏览

使用描述的精确布局数字在这里和一个漂亮的博客文章在这里

所以:

layout := "2006-01-02T15:04:05.000Z"
str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(layout, str)


if err != nil {
fmt.Println(err)
}
fmt.Println(t)

给:

>> 2014-11-12 11:45:26.371 +0000 UTC
< p >我知道。不可思议。也第一次抓住了我。 Go只是没有为datetime组件使用抽象语法(YYYY-MM-DD),而是使用这些精确的数字(我想第一次去的时候不是,根据。有人知道吗?)< / p >
要使用的布局确实是在RickyA回答中描述的"2006-01-02T15:04:05.000Z" 它不是“第一次提交go的时间”,而是一种记住所述布局的助记方法 看到包裹/时间: < / p >

布局中使用的参考时间为:

Mon Jan 2 15:04:05 MST 2006

是Unix时间1136239445 由于MST为GMT-0700,所以参考时间可以认为是

 01/02 03:04:05PM '06 -0700

(1、2、3、4、5、6、7,只要你记得1代表月,2代表日,这对像我这样的欧洲人来说并不容易,因为我习惯了日-月的日期格式)

如“时间。解析:为什么golang解析时间不正确?”所示,该布局(使用1,2,3,4,5,6,7)必须遵守完全

正如回答的那样,但为了节省为布局输入"2006-01-02T15:04:05.000Z",你可以使用包的常量RFC3339

str := "2014-11-12T11:45:26.371Z"
t, err := time.Parse(time.RFC3339, str)


if err != nil {
fmt.Println(err)
}
fmt.Println(t)

https://play.golang.org/p/Dgu2ZvHwTh

这可能非常晚,但这是为那些可能无意中发现这个问题并可能想使用外部包来解析日期字符串的人准备的。

我试着找了一个图书馆,我找到了这个:

https://github.com/araddon/dateparse

来自README的例子:

package main


import (
"flag"
"fmt"
"time"


"github.com/apcera/termtables"
"github.com/araddon/dateparse"
)


var examples = []string{
"May 8, 2009 5:57:51 PM",
"Mon Jan  2 15:04:05 2006",
"Mon Jan  2 15:04:05 MST 2006",
"Mon Jan 02 15:04:05 -0700 2006",
"Monday, 02-Jan-06 15:04:05 MST",
"Mon, 02 Jan 2006 15:04:05 MST",
"Tue, 11 Jul 2017 16:28:13 +0200 (CEST)",
"Mon, 02 Jan 2006 15:04:05 -0700",
"Thu, 4 Jan 2018 17:53:36 +0000",
"Mon Aug 10 15:44:11 UTC+0100 2015",
"Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)",
"12 Feb 2006, 19:17",
"12 Feb 2006 19:17",
"03 February 2013",
"2013-Feb-03",
//   mm/dd/yy
"3/31/2014",
"03/31/2014",
"08/21/71",
"8/1/71",
"4/8/2014 22:05",
"04/08/2014 22:05",
"4/8/14 22:05",
"04/2/2014 03:00:51",
"8/8/1965 12:00:00 AM",
"8/8/1965 01:00:01 PM",
"8/8/1965 01:00 PM",
"8/8/1965 1:00 PM",
"8/8/1965 12:00 AM",
"4/02/2014 03:00:51",
"03/19/2012 10:11:59",
"03/19/2012 10:11:59.3186369",
// yyyy/mm/dd
"2014/3/31",
"2014/03/31",
"2014/4/8 22:05",
"2014/04/08 22:05",
"2014/04/2 03:00:51",
"2014/4/02 03:00:51",
"2012/03/19 10:11:59",
"2012/03/19 10:11:59.3186369",
// Chinese
"2014年04月08日",
//   yyyy-mm-ddThh
"2006-01-02T15:04:05+0000",
"2009-08-12T22:15:09-07:00",
"2009-08-12T22:15:09",
"2009-08-12T22:15:09Z",
//   yyyy-mm-dd hh:mm:ss
"2014-04-26 17:24:37.3186369",
"2012-08-03 18:31:59.257000000",
"2014-04-26 17:24:37.123",
"2013-04-01 22:43",
"2013-04-01 22:43:22",
"2014-12-16 06:20:00 UTC",
"2014-12-16 06:20:00 GMT",
"2014-04-26 05:24:37 PM",
"2014-04-26 13:13:43 +0800",
"2014-04-26 13:13:44 +09:00",
"2012-08-03 18:31:59.257000000 +0000 UTC",
"2015-09-30 18:48:56.35272715 +0000 UTC",
"2015-02-18 00:12:00 +0000 GMT",
"2015-02-18 00:12:00 +0000 UTC",
"2017-07-19 03:21:51+00:00",
"2014-04-26",
"2014-04",
"2014",
"2014-05-11 08:20:13,787",
// mm.dd.yy
"3.31.2014",
"03.31.2014",
"08.21.71",
//  yyyymmdd and similar
"20140601",
// unix seconds, ms
"1332151919",
"1384216367189",
}


var (
timezone = ""
)


func main() {
flag.StringVar(&timezone, "timezone", "UTC", "Timezone aka `America/Los_Angeles` formatted time-zone")
flag.Parse()


if timezone != "" {
// NOTE:  This is very, very important to understand
// time-parsing in go
loc, err := time.LoadLocation(timezone)
if err != nil {
panic(err.Error())
}
time.Local = loc
}


table := termtables.CreateTable()


table.AddHeaders("Input", "Parsed, and Output as %v")
for _, dateExample := range examples {
t, err := dateparse.ParseLocal(dateExample)
if err != nil {
panic(err.Error())
}
table.AddRow(dateExample, fmt.Sprintf("%v", t))
}
fmt.Println(table.Render())
}

我会建议使用时间。RFC3339常量从时间包。您可以从time包中检查其他常数。 https://golang.org/pkg/time/#pkg-constants < / p >

package main


import (
"fmt"
"time"
)


func main() {
fmt.Println("Time parsing");
dateString := "2014-11-12T11:45:26.371Z"
time1, err := time.Parse(time.RFC3339,dateString);
if err!=nil {
fmt.Println("Error while parsing date :", err);
}
fmt.Println(time1);
}

这是一个相当晚的聚会,并没有真正说任何没有以这种或那种形式说过的东西,主要是通过上面的链接,但我想给那些注意力持续时间较短的人一个TL;DR概述:

go格式字符串的日期和时间非常重要。围棋就是这样区分哪个领域是哪个领域的。一般从左到右为1-9,如下:

  • January / Jan / January / Jan / 01 / _1(等等)表示月份
  • 02 / _2代表星期几
  • 15 / 03 / _3 / PM / P / PM / P代表小时和安培;子午线(3点)
  • 04 / _4代表分钟
  • 05 / _5表示秒
  • 2006 / 06为年度
  • -0700 / 07:00 / MST为时区
  • .999999999 / .000000000等是部分秒(我认为区别是如果后面的零被删除)
  • 星期一/星期一是一周中的一天(实际上是01-02-2006),

所以,不要写“01-05-15”作为你的日期格式,除非你想要“月-秒-小时”

(…同样,这也是对上述内容的总结。)

如果您使用过其他语言中的时间/日期格式化/解析,您可能已经注意到其他语言使用特殊的占位符进行时间/日期格式化。例如ruby语言使用

%d for day
%Y for year

等。Golang并没有像上面那样使用代码,而是使用日期和时间格式占位符,看起来只像日期和时间。Go使用标准时间,即:

Mon Jan 2 15:04:05 MST 2006  (MST is GMT-0700)
or
01/02 03:04:05PM '06 -0700

如果你注意到Go使用

01 for the day of the month,
02 for the month
03 for hours,
04 for minutes
05 for second
and so on

因此,例如解析2020-01-29,布局字符串应该是06-01-02或2006-01-02。

你可以在这个链接中引用完整的占位符布局表——https://golangbyexample.com/parse-time-in-golang/

对于那些遇到这种情况的人,使用时间。RFC3339而不是"2006-01-02T15:04:05.000Z"的字符串常量。原因如下:

regDate := "2007-10-09T22:50:01.23Z"


layout1 := "2006-01-02T15:04:05.000Z"
t1, err := time.Parse(layout1, regDate)


if err != nil {
fmt.Println("Static format doesn't work")
} else {
fmt.Println(t1)
}


layout2 := time.RFC3339
t2, err := time.Parse(layout2, regDate)


if err != nil {
fmt.Println("RFC format doesn't work") // You shouldn't see this at all
} else {
fmt.Println(t2)
}

这将产生以下结果:

Static format doesn't work
2007-10-09 22:50:01.23 +0000 UTC

这里是操场上的链接