解析非“标准”格式的日期/时间字符串


70

如何在Go中解析非标准的日期/时间字符串。例如,如果我想将字符串10/15/1983转换为time.Time?该time.Parse()功能应该允许您指定格式。

http://play.golang.org/p/v5DbowXt1x

package main

import "fmt"
import "time"

func main() {
    test, err := time.Parse("10/15/1983", "10/15/1983")
    if err != nil {
        panic(err)
    }

    fmt.Println(test)
}

这导致了恐慌。

panic: parsing time "10/15/1983" as "10/15/1983": cannot parse "" as "0/"

从逻辑上讲这是有道理的,因为它应该如何知道哪一天和哪一个月。

其他语言具有类似于以下功能:

parse("mm/dd/yyyy", "10/15/1983")

我在Go docs中找不到这样的功能,我是regex的唯一选择吗?


4
您可能想看看Paul Smith
Mark Hall

Answers:


164

time.Parse正在寻找一些关键值。

通过更改:

test, err := time.Parse("10/15/1983", "10/15/1983")

test, err := time.Parse("01/02/2006", "10/15/1983")

解析器将识别出它。

这是操场上修改后的代码

package main

import "fmt"
import "time"

func main() {
    test, err := time.Parse("01/02/2006", "10/15/1983")
    if err != nil {
        panic(err)
    }

    fmt.Println(test)
}


您可以利用src / pkg / time / format.go文件中的常量列表来创建自己的解析格式。

const (
    stdLongMonth      = "January"
    stdMonth          = "Jan"
    stdNumMonth       = "1"
    stdZeroMonth      = "01"
    stdLongWeekDay    = "Monday"
    stdWeekDay        = "Mon"
    stdDay            = "2"
    stdUnderDay       = "_2"
    stdZeroDay        = "02"
    stdHour           = "15"
    stdHour12         = "3"
    stdZeroHour12     = "03"
    stdMinute         = "4"
    stdZeroMinute     = "04"
    stdSecond         = "5"
    stdZeroSecond     = "05"
    stdLongYear       = "2006"
    stdYear           = "06"
    stdPM             = "PM"
    stdpm             = "pm"
    stdTZ             = "MST"
    stdISO8601TZ      = "Z0700"  // prints Z for UTC
    stdISO8601ColonTZ = "Z07:00" // prints Z for UTC
    stdNumTZ          = "-0700"  // always numeric
    stdNumShortTZ     = "-07"    // always numeric
    stdNumColonTZ     = "-07:00" // always numeric
)

因此,只要您的格式指定年份,就应该使用“ 06”或“ 2006”来完成,以“ 05”或“ 5”来指定秒,并在“ MST”,“ Z0700”,“ Z07:00”中指定时区”,“-0700”,“-07”或“ -07:00”。如果您引用常量列表,则可以将需要解析的任何标准格式组合在一起。

例如,如果要以“通用日志格式”(Apache为其日志文件使用的格式)解析日期/时间,可以通过将以下字符串传递time.Parse()layout参数来实现。

"02/Jan/2006:15:04:05 -0700"

“ 02”表示月份的日期字段,“ Jan”表示月份的名称字段,“ 2006”表示年份的字段,“ 15”表示24小时格式的一天中的小时字段,“ 04”表示分钟的字段, “ 05”表示秒字段,“-0700”表示时区字段。

该格式将解析当前的PST时间: 31/Dec/2012:15:32:25 -0800

因此,time.Parse()调用将如下所示:

test, err := time.Parse("02/Jan/2006:15:04:05 -0700", "31/Dec/2012:15:32:25 -0800")

2
您的代码有效,但是为什么呢?如果我将其更改为time.Parse("01/02/2005", "10/15/1983")失败,那么……相对于2005、2004、1990等,2006年的魔力是什么?
Nucleon

7
重新阅读文档后,我认为可以在文档中更清楚地说明这一点。我结合现实世界中的例子将使其更加清晰。在我徒劳的尝试中,我尝试了time.Parse("stdLongMonth/stdLongDay/stdLongYear", "10/15/83")= p之类的事情。
Nucleon

73
哇,Go文档可能已经提到您在日期格式中使用的数字确实很重要。
马特

嗨Nuncleon。你在那里犯了两个错误。首先,您为格式选择了错误的常量:应为stdZeroMonth / stdZeroDay / stdYear,其次,您需要使用此常量的值。因此,对于您的情况,您需要这样分析:time.Parse("01/02/06", "10/15/83")
Bogdan Nechyporenko 2014年

1
偷偷摸摸的方法!感谢您的解释!+1
Alix Axel 2014年

6

如果您不记得指定布局中的数字(“ 2006-01-02T15:04:05.000Z”),则可以使用我的简单日期格式库github.com/metakeule/fmtdate,该库使用MS Excel约定,例如Y ,M,D,h并在内部将其转换为数字格式:

package main

import (
    "github.com/metakeule/fmtdate"

    "fmt"
)

func main() {
    test, err := fmtdate.Parse("MM/DD/YYYY", "10/15/1983")
    if err != nil {
        panic(err)
    }

    fmt.Println(test)
}

1
对于不记得的人,1,2,3,4,5,6,7(01/02 03:04:05 PM '06 -07)?至少像strftime格式字符串之类的东西支持更多的东西,您的电子表格格式甚至没有12小时的上午/下午支持,因此以多种方式向后退。
Dave C

3
@DaveC我们德国人不会在上午/下午考虑,所以15到3是一个转变,您还必须记住以下顺序:日,月,小时/下午,分钟,秒,年,时区。今年的状况很奇怪。但是,我总是不得不查找它,而我并不是唯一的一个。...对于不熟悉go时间格式的人来说,excel格式显然是一种格式,不能与实际日期混淆。
metakeule

1
@DaveC我已经更新了库以支持时区和AM / PM。缺少什么?
metakeule

2

如果您正在寻找C样式格式功能:在查看了一些选项之后,我选择了https://github.com/cactus/gostrftime,因为它通常遵循strfmt(3)表示法。

引用示例:

import (
    "fmt"
    "time"
    "github.com/cactus/gostrftime"
)

func main() {
    now := time.Now()
    fmt.Println(gostrftime.Format("%Y-%m-%d", now))
}

如果C和Go都必须使用日期格式,并且不触碰C的实现,则别无选择,只能适应Go端。上面的软件包满足了这一需求。

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.