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

huangapple go评论103阅读模式
英文:

Parsing date/time strings which are not 'standard' formats

问题

如何在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文档中找不到这样的函数,我唯一的选择是使用正则表达式吗?

英文:

How do I parse non-standard date/time strings in Go. In example if I wanted to convert the string 10/15/1983 into a time.Time? The time.Parse() function supposedly allows you to specify a format.

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

This results in a panic.

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

Logically that makes sense because how is it supposed to know which is the day and which is the month.

Other languages have a function similar to the following:

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

I cannot find such a function in the Go docs, is my only choice to regex?

答案1

得分: 178

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

通过更改:

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

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

解析器将识别它。

这是在playground上修改后的代码。

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"指定。如果您参考常量列表,您可能可以组合任何您需要解析的标准格式。

例如,如果您想解析日期/时间在Common Log Format中,这是Apache用于其日志文件的格式,您可以通过将以下字符串作为layout参数传递给time.Parse()来实现。

"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")
英文:

There are some key values that the time.Parse is looking for.

By changing:

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

to

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

the parser will recognize it.

Here's the <a href="http://play.golang.org/p/tPr45KHNbF">modified code on the playground</a>.

package main

import &quot;fmt&quot;
import &quot;time&quot;

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

<br/>

You can utilize the constants list in the <a href="http://golang.org/src/pkg/time/format.go">src/pkg/time/format.go</a> file to create your own parse formats.

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

So anytime your format specifies a year, it should be done with "06" or "2006", seconds are specified by "05" or "5" and time zones are specified at "MST", "Z0700", "Z07:00", "-0700", "-07" or "-07:00". If you reference the constants list you can likely put together any standard format you'd need to parse.

For example, if you want to parse the date/time in the <a href="http://en.wikipedia.org/wiki/Common_Log_Format">Common Log Format</a>, the format Apache uses for its log files, you would do so by passing the following string to time.Parse() as the <i>layout</i> argument.

&quot;02/Jan/2006:15:04:05 -0700&quot;

"02" denotes the day of the month field, "Jan" denotes the month name field, "2006" denotes the year field, "15" denotes the hour of day field in 24 hour format, "04" denotes the minutes field, "05" denotes the seconds field and "-0700" denotes the time zone field.

That format would parse the current PST time: 31/Dec/2012:15:32:25 -0800

So the time.Parse() call would look like this:

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

答案2

得分: 8

如果您无法记住指定布局中的数字(“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)
}
英文:

If you can't remember the Numbers in the specifying layout ("2006-01-02T15:04:05.000Z"), you may use my simple date formatting library github.com/metakeule/fmtdate that uses MS Excel conventions, like Y,M,D,h and internally translates them to the number format:

package main

import (
	&quot;github.com/metakeule/fmtdate&quot;

	&quot;fmt&quot;
)

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

	fmt.Println(test)
}

答案3

得分: 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端不得不进行适应。上述包满足了这个需求。

英文:

If you are looking for a C-Style formatting function: After reviewing some of the options I have chosen https://github.com/cactus/gostrftime as it generally follows the strfmt(3) notation.

To quote the example:

import (
    &quot;fmt&quot;
    &quot;time&quot;
    &quot;github.com/cactus/gostrftime&quot;
)

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

If a date format has to be used by both C and Go and the C implementation is not to be touched there's no choice but to adapt on the Go end. The above package fulfills that need.

答案4

得分: 0

package main

import (
"fmt"
"time"
)

func main() {
var (
y, d int
m time.Month
)
fmt.Sscanf("10/15/1983", "%v/%v/%v", &m, &d, &y)
t := time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
fmt.Println(t) // 1983-10-15 00:00:00 +0000 UTC
}

英文:

If you don't want bother remembering the magic numbers, you can do this:

package main

import (
   &quot;fmt&quot;
   &quot;time&quot;
)

func main() {
   var (
      y, d int
      m time.Month
   )
   fmt.Sscanf(&quot;10/15/1983&quot;, &quot;%v/%v/%v&quot;, &amp;m, &amp;d, &amp;y)
   t := time.Date(y, m, d, 0, 0, 0, 0, time.UTC)
   fmt.Println(t) // 1983-10-15 00:00:00 +0000 UTC
}

https://golang.org/pkg/fmt#Sscanf

huangapple
  • 本文由 发表于 2013年1月1日 06:32:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/14106541.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定