在Go中解析日期字符串


138

我尝试"2014-09-12T11:45:26.371Z"在Go中解析日期字符串。

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”:月超出范围

如何解析此日期字符串?


对于未来的读者,我写了一些练习日期解析的练习github.com/soniah/date_practice
Sonia Hamilton

您的布局应该完全是2006-01-02T15:04:05.000Z出于某种疯狂的
追求

Answers:


164

使用确切的布局数字描述这里和一个不错的博客帖子在这里

所以:

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

我知道。头脑陷入困境。也第一次吸引我。去只是不使用抽象语法日期时间部件(YYYY-MM-DD),但这些确切的数字(我想的时候第一次提交围棋不,根据这个。没有人知道?)。


118
布局编号?什么?为什么?啊!
Darth Egregious 2015年

29
他们在想什么!?还是吸烟?
Jishnu Prathap'Mar

14
我可能在这里发表评论有点晚了,但不要害怕用数字布局,只需使用常量,您的代码就可以了:)例如time.RFC3339
Davyd Dzhahaiev

11
对于那些没有布局编号的人,我乍一看承认它非常陌生,但是一旦您习惯了它,我认为它至少与典型的布局设备一样有意义(“我是否使用“ D”, “ d”,“ dd”,“ DD”等),并且可能更有意义。您只需要首先了解它。
threeve

5
这是出于记忆的目的,也就是说,您只需要记住1、2、3、4、5、6、7个字母即可。有一篇很棒的文章讨论此问题:medium.com/@simplyianm/…–
amigcamel

85

使用的布局确实是RickyA回答中2006-01-02T15:04:05.000Z描述的。 这不是“第一次提交go的时间”,而是一种记忆该布局的助记符方式。 参见pkg / time

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

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代表一天,对于像我这样的欧洲人来说,习惯于日-月日期格式并不容易)

正如所示“ time.parse:为什么golang不正确地分析时间? ”,该布局(使用1,2,3,4,5,6,7)必须尊重准确


是的,也吸引了澳大利亚人!MM / DD只是不适合我计算,我必须继续关注它。
西蒙·怀特海德

3
@SimonWhitehead我同意。至少,一旦我查了一下,我就知道YY,MM,DD,hh,mm,ss代表什么,我可以轻松地对其重新订购。使用Go,即使在查找后,我也需要记住1、2、3、4 ...代表什么。
VonC 2014年

1
我记得的方式是:第1步:“正确的”日期排序为年>月>日>小时>分钟>秒>等(因为混合字节序在意义上是任意的,不一致的,对于日期, endian比little-endian更可取,因为它排序友好。)这将使我们获得1(年),2(月),3(天),[...] 步骤2) Go / Google是美国人,美国人把他们的年在其日期的末尾,因此改为1(月),2(日),[n](年)。步骤3)时区位于其他所有内容之后,因为时区是附加的抽象层。
mtraceur

@mtraceur是的...我也想念web.archive.org/web/20180501100155/http://…(来自github.com/bdotdub/fuckinggodateformat)。我是说,strftimeFTW
VonC

58

按照回答,但为了节省"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


1
另外,如果您查看包常量(在上面的答案中链接),则可以使用一堆其他常用格式。如果您需要一些稍有不同的内容,请以它们为起点。

这个和几个答案建议2006-01-02T15:04:05.000Z并提到Go time.RFC3339也可以。但是time.RFC3339 = "2006-01-02T15:04:05Z07:00"。这两种格式在功能上time.Parse和功能上是否完全相同time.ParseInLocation
迈尔斯

1
没错,@ Miles,此测试确认了 play.golang.org/p/T3dW1kTeAHl
robstarbuck

24

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

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); 
}

您是要使用分号吗?
ChristoKiwi

20

这对于晚会来说是很晚了,并且并没有真正说出一种或多种形式还没有说过的话,主要是通过上面的链接,但是我想给那些关注范围较小的人提供TL; DR概述:

go格式字符串的日期和时间非常重要。这样Go便知道哪个字段是哪个字段。它们通常从左到右为1-9,如下所示:

  • 一月/一月/一月/一月/ 01 / _1(等)表示月份
  • 02 / _2适用于每月的某天
  • 15/03 / _3 / PM / P / pm / p表示小时和子午线(3pm)
  • 04 / _4分钟
  • 05 / _5秒
  • 2006/06年
  • -0700 / 07:00 / MST适用于时区
  • .999999999 / .000000000等是部分秒(我认为区别是尾随零被删除了)
  • 星期一/星期一是星期几(实际上是2006年1月2日),

因此,请勿将日期格式写为“ 01-05-15”,除非您希望使用“ Month-Second-Hour”

(再次,这基本上是上面的摘要。)


5

这可能为时已晚,但这是针对那些可能在此问题上迷迷糊糊,并且可能希望使用外部包来解析日期字符串的人们的。

我试图寻找一个库,但发现了一个:

https://github.com/araddon/dateparse

自述文件中的示例:

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())
}

2
不幸的是,日月顺序有歧义。欧洲日期格式使用第一天,第二个月使用美国时间格式。2004年3月5日这样的日期是模棱两可的。该日期以美国和欧洲格式有效,但3和5可能对应于日期和月份或相反。dateParse采用美国格式。
chmike

-1

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

%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/

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.