Handling time is always a headache, no matter what time it is. The time format is too diverse, and it is even more difficult to deal with time zones, daylight saving time, leap seconds and other minor details. Therefore, we usually use standard libraries or time libraries provided by third parties to handle time in our programs. The dateparse we are going to introduce today focuses on a very small area of time processing - parsing strings in date time format.
Quick Use
Create the directory and initialize.
1
2
|
$ mkdir dateparse && cd dateparse
$ go mod init github.com/darjun/go-daily-lib/dateparse
|
Install the dateparse
library
1
|
go get -u github.com/araddon/dateparse
|
Use.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package main
import (
"fmt"
"log"
"github.com/araddon/dateparse"
)
func main() {
t1, err := dateparse.ParseAny("3/1/2014")
if err != nil {
log.Fatal(err)
}
fmt.Println(t1.Format("2006-01-02 15:04:05"))
t2, err := dateparse.ParseAny("mm/dd/yyyy")
if err != nil {
log.Fatal(err)
}
fmt.Println(t2.Format("2006-01-02 15:04:05"))
}
|
The ParseAny()
method takes a datetime string, parses the string, and returns a value of type time.Time
. If the passed string dateparse
is not recognized by the library, an error is returned. The above program runs the output.
1
2
3
4
|
$ go run main.go
2014-03-01 00:00:00
2021/06/24 14:52:39 Could not find format for "mm/dd/yyyy"
exit status 1
|
Note that when we write the time “3/1/2014”, it can be interpreted as either March 1, 2014 or January 3, 2014. This has a different meaning, as dateparse defaults to mm/dd/yyyy, which is March 1, 2014. We can also make such strings with different meanings fail to parse using the ParseStrict()
function.
1
2
3
4
5
6
7
|
func main() {
t, err := dateparse.ParseStrict("3/1/2014")
if err != nil {
log.Fatal(err)
}
fmt.Println(t.Format("2006-01-02 15:04:05"))
}
|
run
1
2
3
|
$ go run main.go
2021/06/24 14:57:18 This date has ambiguous mm/dd vs dd/mm type format
exit status 1
|
dateparse
supports a rich set of datetime formats, including basically all commonly used formats. It supports all the formats predefined in the standard library time.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// src/time/format.go
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 zone
RFC850 = "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 zone
RFC3339 = "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"
)
|
See dateparse README
for the full format supported.
Time Zone
dateparse
supports parsing datetime strings in specific time zones. We can get a time zone object by calling the time.LoadLocation()
method of the standard library and passing in a time zone identifier string. The time zone identifier string is something like Asia/Shanghai
, America/Chicago
, which represents a specific time zone, Shanghai for the former and Los Angeles for the latter. The dateparse.ParseIn()
method is called to pass in a timezone object to be parsed in the specified timezone. There are also two time zone objects predefined in the time
package, time.Local
for the local time zone and time.UTC
for the UTC
time zone. See IANA
for authoritative data on time zones.
1
2
3
4
5
6
7
8
|
func main() {
tz1, _ := time.LoadLocation("America/Chicago")
t1, _ := dateparse.ParseIn("2021-06-24 15:50:30", tz1)
fmt.Println(t1.Local().Format("2006-01-02 15:04:05"))
t2, _ := dateparse.ParseIn("2021-06-24 15:50:30", time.Local)
fmt.Println(t2.Local().Format("2006-01-02 15:04:05"))
}
|
run
1
2
3
|
$ go run main.go
2021-06-25 04:50:30
2021-06-24 15:50:30
|
June 24, 2021 15:30:30 in the Los Angeles time zone is equal to June 25, 2021 04:50:30 in the local time zone (Beijing time).
cli
dateparse also provides a command line tool for extremely fast viewing of date time formats. Installation.
1
|
$ go install github.com/araddon/dateparse/dateparse
|
By default it will be installed under $GOPATH
path, I used to put $GOPATH/bin
into $PATH
. So the dateparse
command can be used directly.
The dateparse
command takes a string, and an optional timezone option.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
$ dateparse --timezone="Asia/Shanghai" "2021-06-24 06:46:08"
Your Current time.Local zone is CST
Layout String: dateparse.ParseFormat() => 2006-01-02 15:04:05
Your Using time.Local set to location=Asia/Shanghai CST
+-------------+---------------------------+-------------------------------+-------------------------------------+
| method | Zone Source | Parsed | Parsed: t.In(time.UTC) |
+-------------+---------------------------+-------------------------------+-------------------------------------+
| ParseAny | time.Local = nil | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC day=4 |
| ParseAny | time.Local = timezone arg | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC day=4 |
| ParseAny | time.Local = time.UTC | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC day=4 |
| ParseIn | time.Local = nil | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
| ParseIn | time.Local = timezone arg | 2021-06-24 06:46:08 +0800 CST | 2021-06-23 22:46:08 +0000 UTC |
| ParseIn | time.Local = time.UTC | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
| ParseLocal | time.Local = nil | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
| ParseLocal | time.Local = timezone arg | 2021-06-24 06:46:08 +0800 CST | 2021-06-23 22:46:08 +0000 UTC |
| ParseLocal | time.Local = time.UTC | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
| ParseStrict | time.Local = nil | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
| ParseStrict | time.Local = timezone arg | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
| ParseStrict | time.Local = time.UTC | 2021-06-24 06:46:08 +0000 UTC | 2021-06-24 06:46:08 +0000 UTC |
+-------------+---------------------------+-------------------------------+-------------------------------------+
|
Outputs the current local time zone, a format string (which can be used to generate a datetime string in the same format) and a table. The data inside the table is the result of calling ParseAny/ParseIn/ParseLocal/ParseStrict
for different time zones respectively.
The method
column indicates the method called, the Zone Source
column indicates the value set to the local time zone, the Parsed
column is the result of calling the Format()
method on the time.Time
object returned by ParseAny()
with a datetime string, and the Parsed: t.In(time. UTC)
column converts the returned time.Time
object to UTC
time before the Format()
method is called on it.
Since ParseAny/ParseStrict
does not take into account the local time zone and parses the string under UTC
, the last two columns of these 6
rows have the same result.
In the second line of ParseIn
, set time.Local
to the time zone we set via the command line option, which I set to Asia/Shanghai
above, corresponding to an 8-hour difference in UTC
time. The same is true for ParseLocal
.
The following is part of the source code of the dateparse
command line, you can check it against.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
func main() {
parsers := map[string]parser{
"ParseAny": parseAny,
"ParseIn": parseIn,
"ParseLocal": parseLocal,
"ParseStrict": parseStrict,
}
for name, parser := range parsers {
time.Local = nil
table.AddRow(name, "time.Local = nil", parser(datestr, nil, false), parser(datestr, nil, true))
if timezone != "" {
time.Local = loc
table.AddRow(name, "time.Local = timezone arg", parser(datestr, loc, false), parser(datestr, loc, true))
}
time.Local = time.UTC
table.AddRow(name, "time.Local = time.UTC", parser(datestr, time.UTC, false), parser(datestr, time.UTC, true))
}
}
func parseIn(datestr string, loc *time.Location, utc bool) string {
t, err := dateparse.ParseIn(datestr, loc)
if err != nil {
return err.Error()
}
if utc {
return t.In(time.UTC).String()
}
return t.String()
}
|
Note that the local time zone of the output is CST, which can represent different time zones.
1
2
3
4
|
Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time UT+8:00
Cuba Standard Time UT-4:00
|
CST can represent the standard time of four countries at the same time: USA, Australia, China and Cuba.
Summary
Using dateparse it is easy to parse time objects and formats (layouts) from datetime strings. Also dateparse command line is a great little tool to quickly view and convert the time in the corresponding time zone.
Reference https://darjun.github.io/2021/06/24/godailylib/dateparse/