├── .gitignore ├── go.mod ├── .github └── workflows │ ├── lint.yaml │ ├── test.yaml │ └── releaser.yml ├── .goreleaser.yml ├── LICENSE ├── go.sum ├── dateparse ├── main.go └── README.md ├── bench_test.go ├── example └── main.go ├── README.md └── parseany_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.pprof 2 | *.test 3 | dist 4 | vendor 5 | dateparse/dateparse 6 | example/example 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/itlightning/dateparse 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4 7 | github.com/stretchr/testify v1.10.0 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/mattn/go-runewidth v0.0.16 // indirect 13 | github.com/pmezard/go-difflib v1.0.0 // indirect 14 | github.com/rivo/uniseg v0.4.7 // indirect 15 | gopkg.in/yaml.v3 v3.0.1 // indirect 16 | ) 17 | -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- 1 | name: golangci-lint 2 | on: 3 | push: 4 | tags: 5 | - v* 6 | branches: 7 | - main 8 | pull_request: 9 | jobs: 10 | golangci: 11 | name: lint 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Cache-Go 16 | uses: actions/cache@v4 17 | with: 18 | path: | 19 | ~/go/pkg/mod # Module download cache 20 | ~/.cache/go-build # Build cache (Linux) 21 | ~/Library/Caches/go-build # Build cache (Mac) 22 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 23 | restore-keys: | 24 | ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 25 | - name: golangci-lint 26 | uses: golangci/golangci-lint-action@v7 27 | with: 28 | version: latest 29 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | on: [push, pull_request] 2 | name: Test 3 | jobs: 4 | test: 5 | strategy: 6 | matrix: 7 | go-version: [1.20.x] 8 | os: [ubuntu-latest] 9 | runs-on: ${{ matrix.os }} 10 | steps: 11 | - name: Install Go 12 | uses: actions/setup-go@v5 13 | with: 14 | go-version: ${{ matrix.go-version }} 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | - name: Cache-Go 18 | uses: actions/cache@v4 19 | with: 20 | path: | 21 | ~/go/pkg/mod # Module download cache 22 | ~/.cache/go-build # Build cache (Linux) 23 | ~/Library/Caches/go-build # Build cache (Mac) 24 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 25 | restore-keys: | 26 | ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 27 | - name: Test 28 | run: go test ./... 29 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | project_name: dateparse 2 | builds: 3 | - 4 | id: "dateparse" 5 | binary: "dateparse" 6 | dir: dateparse 7 | - 8 | id: "example" 9 | binary: "example" 10 | dir: example 11 | archives: 12 | - 13 | format_overrides: 14 | - goos: windows 15 | format: zip 16 | checksum: 17 | name_template: 'checksums.txt' 18 | snapshot: 19 | name_template: "{{ .Tag }}-next" 20 | changelog: 21 | use: github-native 22 | sort: asc 23 | filters: 24 | include: 25 | - "^feat:" 26 | exclude: 27 | - '^docs:' 28 | - '^test:' 29 | nfpms: 30 | - 31 | vendor: dateparse 32 | homepage: https://github.com/itlightning/dateparse 33 | maintainer: IT Lightning, LLC 34 | description: NA 35 | formats: 36 | - apk 37 | - deb 38 | - rpm 39 | release: 1 40 | section: default 41 | priority: extra 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 Aaron Raddon 4 | Copyright (c) 2023-2024 IT Lightning, LLC 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yml: -------------------------------------------------------------------------------- 1 | name: releaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' 7 | 8 | jobs: 9 | goreleaser: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Set up Go 13 | uses: actions/setup-go@v5 14 | with: 15 | go-version: 1.20.x 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | - name: Cache-Go 21 | uses: actions/cache@v4 22 | with: 23 | path: | 24 | ~/go/pkg/mod # Module download cache 25 | ~/.cache/go-build # Build cache (Linux) 26 | ~/Library/Caches/go-build # Build cache (Mac) 27 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 28 | restore-keys: | 29 | ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 30 | - name: Test 31 | run: go test ./... 32 | - name: Run GoReleaser 33 | uses: goreleaser/goreleaser-action@v6 34 | with: 35 | distribution: goreleaser 36 | version: latest 37 | args: release --clean 38 | env: 39 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 40 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 4 | github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 8 | github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 9 | github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 10 | github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4 h1:8qmTC5ByIXO3GP/IzBkxcZ/99VITvnIETDhdFz/om7A= 11 | github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg= 12 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 13 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 14 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 15 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 16 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 17 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 18 | -------------------------------------------------------------------------------- /dateparse/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "os" 7 | "time" 8 | 9 | "github.com/itlightning/dateparse" 10 | "github.com/scylladb/termtables" 11 | ) 12 | 13 | var ( 14 | timezone = "" 15 | datestr = "" 16 | retryAmbiguousDateWithSwap = false 17 | preferDayFirst = false 18 | parserOptions = []dateparse.ParserOption{} 19 | ) 20 | 21 | func buildParserOptions() { 22 | parserOptions = []dateparse.ParserOption{} 23 | if retryAmbiguousDateWithSwap { 24 | parserOptions = append(parserOptions, dateparse.RetryAmbiguousDateWithSwap(true)) 25 | } 26 | if preferDayFirst { 27 | parserOptions = append(parserOptions, dateparse.PreferMonthFirst(false)) 28 | } 29 | } 30 | 31 | func main() { 32 | flag.StringVar(&timezone, "timezone", "", "Timezone aka `America/Los_Angeles` formatted time-zone") 33 | flag.BoolVar(&retryAmbiguousDateWithSwap, "retry-ambiguous", false, "Retry ambiguous date/time formats (day-first vs month-first)") 34 | flag.BoolVar(&preferDayFirst, "prefer-day-first", false, "Prefer day-first date format") 35 | flag.Parse() 36 | 37 | if len(flag.Args()) == 0 { 38 | fmt.Println(`Must pass a time, and optional location: 39 | 40 | ./dateparse "2009-08-12T22:15:09.99Z" 41 | 42 | ./dateparse --timezone="America/Denver" "2017-07-19 03:21:51+00:00" 43 | ./dateparse --prefer-day-first "28.09.2024" 44 | ./dateparse --retry-ambiguous "28.09.2024" 45 | `) 46 | return 47 | } 48 | 49 | buildParserOptions() 50 | 51 | datestr = flag.Args()[0] 52 | 53 | layout, err := dateparse.ParseFormat(datestr, parserOptions...) 54 | if err != nil { 55 | fatal(err) 56 | } 57 | 58 | zonename, _ := time.Now().In(time.Local).Zone() 59 | fmt.Printf("\nYour Current time.Local zone is %v\n", zonename) 60 | fmt.Printf("\nLayout String: dateparse.ParseFormat() => %v\n", layout) 61 | var loc *time.Location 62 | if timezone != "" { 63 | // NOTE: This is very, very important to understand 64 | // time-parsing in go 65 | l, err := time.LoadLocation(timezone) 66 | if err != nil { 67 | fatal(err) 68 | } 69 | loc = l 70 | zonename, _ := time.Now().In(l).Zone() 71 | fmt.Printf("\nYour Using time.Local set to location=%s %v \n", timezone, zonename) 72 | } 73 | fmt.Printf("\n") 74 | 75 | table := termtables.CreateTable() 76 | 77 | table.AddHeaders("method", "Zone Source", "Parsed", "Parsed: t.In(time.UTC)") 78 | 79 | parsers := map[string]parser{ 80 | "ParseAny": parseAny, 81 | "ParseIn": parseIn, 82 | "ParseLocal": parseLocal, 83 | "ParseStrict": parseStrict, 84 | } 85 | 86 | for name, parser := range parsers { 87 | time.Local = nil 88 | table.AddRow(name, "time.Local = nil", parser(datestr, nil, false), parser(datestr, nil, true)) 89 | if timezone != "" { 90 | time.Local = loc 91 | table.AddRow(name, "time.Local = timezone arg", parser(datestr, loc, false), parser(datestr, loc, true)) 92 | } 93 | time.Local = time.UTC 94 | table.AddRow(name, "time.Local = time.UTC", parser(datestr, time.UTC, false), parser(datestr, time.UTC, true)) 95 | } 96 | 97 | fmt.Println(table.Render()) 98 | } 99 | 100 | type parser func(datestr string, loc *time.Location, utc bool) string 101 | 102 | func parseLocal(datestr string, loc *time.Location, utc bool) string { 103 | time.Local = loc 104 | t, err := dateparse.ParseLocal(datestr, parserOptions...) 105 | if err != nil { 106 | return err.Error() 107 | } 108 | if utc { 109 | return t.In(time.UTC).String() 110 | } 111 | return t.String() 112 | } 113 | 114 | func parseIn(datestr string, loc *time.Location, utc bool) string { 115 | t, err := dateparse.ParseIn(datestr, loc, parserOptions...) 116 | if err != nil { 117 | return err.Error() 118 | } 119 | if utc { 120 | return t.In(time.UTC).String() 121 | } 122 | return t.String() 123 | } 124 | 125 | func parseAny(datestr string, loc *time.Location, utc bool) string { 126 | t, err := dateparse.ParseAny(datestr, parserOptions...) 127 | if err != nil { 128 | return err.Error() 129 | } 130 | if utc { 131 | return fmt.Sprintf("%s day=%d", t.In(time.UTC), t.In(time.UTC).Weekday()) 132 | } 133 | return t.String() 134 | } 135 | 136 | func parseStrict(datestr string, loc *time.Location, utc bool) string { 137 | t, err := dateparse.ParseStrict(datestr, parserOptions...) 138 | if err != nil { 139 | return err.Error() 140 | } 141 | if utc { 142 | return t.In(time.UTC).String() 143 | } 144 | return t.String() 145 | } 146 | 147 | func fatal(err error) { 148 | fmt.Printf("fatal: %s\n", err) 149 | os.Exit(1) 150 | } 151 | -------------------------------------------------------------------------------- /bench_test.go: -------------------------------------------------------------------------------- 1 | package dateparse 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | /* 10 | go test -bench Parse 11 | 12 | // Aarons Laptop Lenovo 900 Feb 2018 13 | BenchmarkShotgunParse-4 50000 30045 ns/op 13136 B/op 169 allocs/op 14 | BenchmarkParseAny-4 200000 8627 ns/op 144 B/op 3 allocs/op 15 | 16 | // ifreddyrondon Laptop MacBook Pro (Retina, Mid 2012) March 2018 17 | BenchmarkShotgunParse-8 50000 33940 ns/op 13136 B/op 169 allocs/op 18 | BenchmarkParseAny-8 200000 10146 ns/op 912 B/op 29 allocs/op 19 | BenchmarkParseDateString-8 10000 123077 ns/op 208 B/op 13 allocs/op 20 | 21 | // Klondike Dragon Dec 2023 22 | cpu: 12th Gen Intel(R) Core(TM) i7-1255U 23 | BenchmarkShotgunParse-12 62788 18113 ns/op 19448 B/op 474 allocs/op 24 | BenchmarkParseAny-12 347020 3455 ns/op 48 B/op 2 allocs/op 25 | BenchmarkBigShotgunParse-12 1226 951271 ns/op 1214937 B/op 27245 allocs/op 26 | BenchmarkBigParseAny-12 4234 267893 ns/op 27492 B/op 961 allocs/op 27 | BenchmarkBigParseIn-12 4032 280900 ns/op 30422 B/op 1033 allocs/op 28 | BenchmarkBigParseRetryAmbiguous-12 4453 282475 ns/op 29558 B/op 1030 allocs/op 29 | BenchmarkShotgunParseErrors-12 19240 62641 ns/op 67080 B/op 1679 allocs/op 30 | BenchmarkParseAnyErrors-12 185677 6179 ns/op 752 B/op 23 allocs/op 31 | BenchmarkBigParseAnyErrors-12 26688 44885 ns/op 480 B/op 94 allocs/op 32 | BenchmarkParseAmbiguous-12 1590302 752.9 ns/op 296 B/op 7 allocs/op 33 | BenchmarkParseWeekdayAndFullMonth-12 2141109 555.0 ns/op 16 B/op 2 allocs/op 34 | */ 35 | func BenchmarkShotgunParse(b *testing.B) { 36 | b.ReportAllocs() 37 | for i := 0; i < b.N; i++ { 38 | for _, dateStr := range testDates { 39 | // This is the non dateparse traditional approach 40 | _, _ = parseShotgunStyle(dateStr) 41 | } 42 | } 43 | } 44 | 45 | func BenchmarkParseAny(b *testing.B) { 46 | b.ReportAllocs() 47 | for i := 0; i < b.N; i++ { 48 | for _, dateStr := range testDates { 49 | _, _ = ParseAny(dateStr) 50 | } 51 | } 52 | } 53 | 54 | func BenchmarkBigShotgunParse(b *testing.B) { 55 | b.ReportAllocs() 56 | for i := 0; i < b.N; i++ { 57 | for _, t := range testInputs { 58 | // This is the non dateparse traditional approach 59 | _, _ = parseShotgunStyle(t.in) 60 | } 61 | } 62 | } 63 | 64 | func BenchmarkBigParseAny(b *testing.B) { 65 | b.ReportAllocs() 66 | for i := 0; i < b.N; i++ { 67 | for _, t := range testInputs { 68 | _, _ = ParseAny(t.in) 69 | } 70 | } 71 | } 72 | 73 | func BenchmarkBigParseIn(b *testing.B) { 74 | b.ReportAllocs() 75 | loc, _ := time.LoadLocation("America/New_York") 76 | for i := 0; i < b.N; i++ { 77 | for _, t := range testInputs { 78 | _, _ = ParseIn(t.in, loc) 79 | } 80 | } 81 | } 82 | 83 | func BenchmarkBigParseRetryAmbiguous(b *testing.B) { 84 | b.ReportAllocs() 85 | opts := []ParserOption{RetryAmbiguousDateWithSwap(true)} 86 | b.ResetTimer() 87 | for i := 0; i < b.N; i++ { 88 | for _, t := range testInputs { 89 | _, _ = ParseAny(t.in, opts...) 90 | } 91 | } 92 | } 93 | 94 | func BenchmarkShotgunParseErrors(b *testing.B) { 95 | b.ReportAllocs() 96 | for i := 0; i < b.N; i++ { 97 | for _, t := range testParseErrors { 98 | // This is the non dateparse traditional approach 99 | _, _ = parseShotgunStyle(t.in) 100 | } 101 | } 102 | } 103 | 104 | func BenchmarkParseAnyErrors(b *testing.B) { 105 | b.ReportAllocs() 106 | opts := []ParserOption{SimpleErrorMessages(true)} 107 | b.ResetTimer() 108 | for i := 0; i < b.N; i++ { 109 | for _, t := range testParseErrors { 110 | _, _ = ParseAny(t.in, opts...) 111 | } 112 | } 113 | } 114 | 115 | func BenchmarkBigParseAnyErrors(b *testing.B) { 116 | b.ReportAllocs() 117 | 118 | opts := []ParserOption{SimpleErrorMessages(true)} 119 | // manufacture a bunch of different tests with random errors put in them 120 | var testBigErrorInputs []string 121 | for index, t := range testInputs { 122 | b := []byte(t.in) 123 | spread := 4 + (index % 4) 124 | startingIndex := spread % len(b) 125 | for i := startingIndex; i < len(b); i += spread { 126 | b[i] = '?' 127 | } 128 | testBigErrorInputs = append(testBigErrorInputs, string(b)) 129 | } 130 | b.ResetTimer() 131 | 132 | for i := 0; i < b.N; i++ { 133 | for _, in := range testBigErrorInputs { 134 | _, err := ParseAny(in, opts...) 135 | if err == nil { 136 | panic(fmt.Sprintf("expected parsing to fail: %s", in)) 137 | } 138 | } 139 | } 140 | } 141 | 142 | func BenchmarkParseAmbiguous(b *testing.B) { 143 | b.ReportAllocs() 144 | opts := []ParserOption{RetryAmbiguousDateWithSwap(true)} 145 | b.ResetTimer() 146 | for i := 0; i < b.N; i++ { 147 | MustParse("13/02/2014 04:08:09 +0000 UTC", opts...) 148 | } 149 | } 150 | 151 | func BenchmarkParseWeekdayAndFullMonth(b *testing.B) { 152 | b.ReportAllocs() 153 | for i := 0; i < b.N; i++ { 154 | MustParse("Monday 02 December 2006 03:04:05 PM UTC") 155 | } 156 | } 157 | 158 | /* 159 | func BenchmarkParseDateString(b *testing.B) { 160 | b.ReportAllocs() 161 | for i := 0; i < b.N; i++ { 162 | for _, dateStr := range testDates { 163 | timeutils.ParseDateString(dateStr) 164 | } 165 | } 166 | } 167 | */ 168 | 169 | var ( 170 | testDates = []string{ 171 | "2012/03/19 10:11:59", 172 | "2012/03/19 10:11:59.3186369", 173 | "2009-08-12T22:15:09-07:00", 174 | "2014-04-26 17:24:37.3186369", 175 | "2012-08-03 18:31:59.257000000", 176 | "2013-04-01 22:43:22", 177 | "2014-04-26 17:24:37.123", 178 | "2014-12-16 06:20:00 UTC", 179 | "1384216367189", 180 | "1332151919", 181 | "2014-05-11 08:20:13,787", 182 | "2014-04-26 05:24:37 PM", 183 | "2014-04-26", 184 | } 185 | 186 | ErrDateFormat = fmt.Errorf("invalid date format") 187 | 188 | timeFormats = []string{ 189 | // ISO 8601ish formats 190 | time.RFC3339Nano, 191 | time.RFC3339, 192 | 193 | // Unusual formats, prefer formats with timezones 194 | time.RFC1123Z, 195 | time.RFC1123, 196 | time.RFC822Z, 197 | time.RFC822, 198 | time.UnixDate, 199 | time.RubyDate, 200 | time.ANSIC, 201 | 202 | // Hilariously, Go doesn't have a const for it's own time layout. 203 | // See: https://code.google.com/p/go/issues/detail?id=6587 204 | "2006-01-02 15:04:05.999999999 -0700 MST", 205 | 206 | // No timezone information 207 | "2006-01-02T15:04:05.999999999", 208 | "2006-01-02T15:04:05", 209 | "2006-01-02 15:04:05.999999999", 210 | "2006-01-02 15:04:05", 211 | } 212 | ) 213 | 214 | func parseShotgunStyle(raw string) (time.Time, error) { 215 | 216 | for _, format := range timeFormats { 217 | t, err := time.Parse(format, raw) 218 | if err == nil { 219 | // Parsed successfully 220 | return t, nil 221 | } 222 | } 223 | return time.Time{}, ErrDateFormat 224 | } 225 | -------------------------------------------------------------------------------- /dateparse/README.md: -------------------------------------------------------------------------------- 1 | DateParse CLI 2 | ---------------------- 3 | 4 | Simple CLI to test out dateparse. 5 | 6 | 7 | ```sh 8 | 9 | # Since this date string has no timezone/offset it's more affected by 10 | # which method you use to parse 11 | 12 | $ dateparse --timezone="America/Denver" "2017-07-19 03:21:00" 13 | 14 | Your Current time.Local zone is PDT 15 | 16 | Layout String: dateparse.ParseFormat() => 2006-01-02 15:04:05 17 | 18 | Your Using time.Local set to location=America/Denver MDT 19 | 20 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 21 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 22 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 23 | | ParseAny | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 24 | | ParseAny | time.Local = timezone arg | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 25 | | ParseAny | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 26 | | ParseIn | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 27 | | ParseIn | time.Local = timezone arg | 2017-07-19 03:21:00 -0600 MDT | 2017-07-19 09:21:00 +0000 UTC | 28 | | ParseIn | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 29 | | ParseLocal | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 30 | | ParseLocal | time.Local = timezone arg | 2017-07-19 03:21:00 -0600 MDT | 2017-07-19 09:21:00 +0000 UTC | 31 | | ParseLocal | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 32 | | ParseStrict | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 33 | | ParseStrict | time.Local = timezone arg | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 34 | | ParseStrict | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 35 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 36 | 37 | 38 | # Note on this one that the outputed zone is always UTC/0 offset as opposed to above 39 | 40 | $ dateparse --timezone="America/Denver" "2017-07-19 03:21:51+00:00" 41 | 42 | Your Current time.Local zone is PDT 43 | 44 | Layout String: dateparse.ParseFormat() => 2006-01-02 15:04:05-07:00 45 | 46 | Your Using time.Local set to location=America/Denver MDT 47 | 48 | +-------------+---------------------------+---------------------------------+-------------------------------------+ 49 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 50 | +-------------+---------------------------+---------------------------------+-------------------------------------+ 51 | | ParseAny | time.Local = nil | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC day=3 | 52 | | ParseAny | time.Local = timezone arg | 2017-07-19 03:21:51 +0000 +0000 | 2017-07-19 03:21:51 +0000 UTC day=3 | 53 | | ParseAny | time.Local = time.UTC | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC day=3 | 54 | | ParseIn | time.Local = nil | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC | 55 | | ParseIn | time.Local = timezone arg | 2017-07-19 03:21:51 +0000 +0000 | 2017-07-19 03:21:51 +0000 UTC | 56 | | ParseIn | time.Local = time.UTC | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC | 57 | | ParseLocal | time.Local = nil | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC | 58 | | ParseLocal | time.Local = timezone arg | 2017-07-19 03:21:51 +0000 +0000 | 2017-07-19 03:21:51 +0000 UTC | 59 | | ParseLocal | time.Local = time.UTC | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC | 60 | | ParseStrict | time.Local = nil | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC | 61 | | ParseStrict | time.Local = timezone arg | 2017-07-19 03:21:51 +0000 +0000 | 2017-07-19 03:21:51 +0000 UTC | 62 | | ParseStrict | time.Local = time.UTC | 2017-07-19 03:21:51 +0000 UTC | 2017-07-19 03:21:51 +0000 UTC | 63 | +-------------+---------------------------+---------------------------------+-------------------------------------+ 64 | 65 | 66 | $ dateparse --timezone="America/Denver" "Monday, 19-Jul-17 03:21:00 MDT" 67 | 68 | Your Current time.Local zone is PDT 69 | 70 | Layout String: dateparse.ParseFormat() => 02-Jan-06 15:04:05 MDT 71 | 72 | Your Using time.Local set to location=America/Denver MDT 73 | 74 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 75 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 76 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 77 | | ParseStrict | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 78 | | ParseStrict | time.Local = timezone arg | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 79 | | ParseStrict | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 80 | | ParseAny | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 81 | | ParseAny | time.Local = timezone arg | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 82 | | ParseAny | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 83 | | ParseIn | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 84 | | ParseIn | time.Local = timezone arg | 2017-07-19 03:21:00 -0600 MDT | 2017-07-19 09:21:00 +0000 UTC | 85 | | ParseIn | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 86 | | ParseLocal | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 87 | | ParseLocal | time.Local = timezone arg | 2017-07-19 03:21:00 -0600 MDT | 2017-07-19 09:21:00 +0000 UTC | 88 | | ParseLocal | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 89 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 90 | 91 | 92 | 93 | # pass in a wrong timezone "MST" (should be MDT) 94 | $ dateparse --timezone="America/Denver" "Monday, 19-Jul-17 03:21:00 MST" 95 | 96 | Your Current time.Local zone is PDT 97 | 98 | Layout String: dateparse.ParseFormat() => 02-Jan-06 15:04:05 MST 99 | 100 | Your Using time.Local set to location=America/Denver MDT 101 | 102 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 103 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 104 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 105 | | ParseAny | time.Local = nil | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC day=3 | 106 | | ParseAny | time.Local = timezone arg | 2017-07-19 04:21:00 -0600 MDT | 2017-07-19 10:21:00 +0000 UTC day=3 | 107 | | ParseAny | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC day=3 | 108 | | ParseIn | time.Local = nil | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC | 109 | | ParseIn | time.Local = timezone arg | 2017-07-19 04:21:00 -0600 MDT | 2017-07-19 10:21:00 +0000 UTC | 110 | | ParseIn | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC | 111 | | ParseLocal | time.Local = nil | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC | 112 | | ParseLocal | time.Local = timezone arg | 2017-07-19 04:21:00 -0600 MDT | 2017-07-19 10:21:00 +0000 UTC | 113 | | ParseLocal | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC | 114 | | ParseStrict | time.Local = nil | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC | 115 | | ParseStrict | time.Local = timezone arg | 2017-07-19 04:21:00 -0600 MDT | 2017-07-19 10:21:00 +0000 UTC | 116 | | ParseStrict | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 MST | 2017-07-19 03:21:00 +0000 UTC | 117 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 118 | 119 | 120 | 121 | # note, we are using America/New_York which doesn't recognize MDT so essentially ignores it 122 | $ dateparse --timezone="America/New_York" "Monday, 19-Jul-17 03:21:00 MDT" 123 | 124 | Your Current time.Local zone is PDT 125 | 126 | Layout String: dateparse.ParseFormat() => 02-Jan-06 15:04:05 MDT 127 | 128 | Your Using time.Local set to location=America/New_York EDT 129 | 130 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 131 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 132 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 133 | | ParseAny | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 134 | | ParseAny | time.Local = timezone arg | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 135 | | ParseAny | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC day=3 | 136 | | ParseIn | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 137 | | ParseIn | time.Local = timezone arg | 2017-07-19 03:21:00 -0400 EDT | 2017-07-19 07:21:00 +0000 UTC | 138 | | ParseIn | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 139 | | ParseLocal | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 140 | | ParseLocal | time.Local = timezone arg | 2017-07-19 03:21:00 -0400 EDT | 2017-07-19 07:21:00 +0000 UTC | 141 | | ParseLocal | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 142 | | ParseStrict | time.Local = nil | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 143 | | ParseStrict | time.Local = timezone arg | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 144 | | ParseStrict | time.Local = time.UTC | 2017-07-19 03:21:00 +0000 UTC | 2017-07-19 03:21:00 +0000 UTC | 145 | +-------------+---------------------------+-------------------------------+-------------------------------------+ 146 | 147 | $ dateparse --timezone="America/New_York" "03/03/2017" 148 | 149 | Your Current time.Local zone is PDT 150 | 151 | Layout String: dateparse.ParseFormat() => 01/02/2006 152 | 153 | Your Using time.Local set to location=America/New_York EDT 154 | 155 | +-------------+---------------------------+----------------------------------------------------+----------------------------------------------------+ 156 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 157 | +-------------+---------------------------+----------------------------------------------------+----------------------------------------------------+ 158 | | ParseIn | time.Local = nil | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC | 159 | | ParseIn | time.Local = timezone arg | 2017-03-03 00:00:00 -0500 EST | 2017-03-03 05:00:00 +0000 UTC | 160 | | ParseIn | time.Local = time.UTC | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC | 161 | | ParseLocal | time.Local = nil | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC | 162 | | ParseLocal | time.Local = timezone arg | 2017-03-03 00:00:00 -0500 EST | 2017-03-03 05:00:00 +0000 UTC | 163 | | ParseLocal | time.Local = time.UTC | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC | 164 | | ParseStrict | time.Local = nil | This date has ambiguous mm/dd vs dd/mm type format | This date has ambiguous mm/dd vs dd/mm type format | 165 | | ParseStrict | time.Local = timezone arg | This date has ambiguous mm/dd vs dd/mm type format | This date has ambiguous mm/dd vs dd/mm type format | 166 | | ParseStrict | time.Local = time.UTC | This date has ambiguous mm/dd vs dd/mm type format | This date has ambiguous mm/dd vs dd/mm type format | 167 | | ParseAny | time.Local = nil | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC day=5 | 168 | | ParseAny | time.Local = timezone arg | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC day=5 | 169 | | ParseAny | time.Local = time.UTC | 2017-03-03 00:00:00 +0000 UTC | 2017-03-03 00:00:00 +0000 UTC day=5 | 170 | +-------------+---------------------------+----------------------------------------------------+----------------------------------------------------+ 171 | 172 | # Automatically retry date formats that are ambiguous mm/dd vs dd/mm 173 | $ ./dateparse --retry-ambiguous "28.09.2024" 174 | 175 | Your Current time.Local zone is MDT 176 | 177 | Layout String: dateparse.ParseFormat() => 02.01.2006 178 | 179 | +-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+ 180 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 181 | +-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+ 182 | | ParseIn | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 183 | | ParseIn | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 184 | | ParseLocal | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 185 | | ParseLocal | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 186 | | ParseStrict | time.Local = nil | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format | 187 | | ParseStrict | time.Local = time.UTC | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format | 188 | | ParseAny | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 | 189 | | ParseAny | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 | 190 | +-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+ 191 | 192 | # Force dates to be interpreted as day-first instead of month-first 193 | $ ./dateparse --prefer-day-first "28.09.2024" 194 | 195 | Your Current time.Local zone is MDT 196 | 197 | Layout String: dateparse.ParseFormat() => 02.01.2006 198 | 199 | +-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+ 200 | | method | Zone Source | Parsed | Parsed: t.In(time.UTC) | 201 | +-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+ 202 | | ParseAny | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 | 203 | | ParseAny | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC day=6 | 204 | | ParseIn | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 205 | | ParseIn | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 206 | | ParseLocal | time.Local = nil | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 207 | | ParseLocal | time.Local = time.UTC | 2024-09-28 00:00:00 +0000 UTC | 2024-09-28 00:00:00 +0000 UTC | 208 | | ParseStrict | time.Local = nil | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format | 209 | | ParseStrict | time.Local = time.UTC | this date has ambiguous mm/dd vs dd/mm type format | this date has ambiguous mm/dd vs dd/mm type format | 210 | +-------------+-----------------------+----------------------------------------------------+----------------------------------------------------+ 211 | 212 | ``` -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "time" 7 | 8 | "github.com/itlightning/dateparse" 9 | "github.com/scylladb/termtables" 10 | ) 11 | 12 | var examples = []string{ 13 | // mon day year (time) 14 | "May 8, 2009 5:57:51 PM", 15 | "oct 7, 1970", 16 | "oct 7, '70", 17 | "oct. 7, 1970", 18 | "oct. 7, 70", 19 | "October 7, 1970", 20 | "October 7th, 1970", 21 | "Sept. 7, 1970 11:15:26pm", 22 | "Sep 7 2009 11:15:26.123 PM PST", 23 | "September 3rd, 2009 11:15:26.123456789pm", 24 | "September 17 2012 10:09am", 25 | "September 17, 2012, 10:10:09", 26 | "Sep 17, 2012 at 10:02am (EST)", 27 | // (PST-08 will have an offset of -0800, and a zone name of "PST") 28 | "September 17, 2012 at 10:09am PST-08", 29 | // (UTC-0700 has the same offset as -0700, and the returned zone name will be empty) 30 | "September 17 2012 5:00pm UTC-0700", 31 | "September 17 2012 5:00pm GMT-0700", 32 | // (weekday) day mon year (time) 33 | "7 oct 70", 34 | "7 Oct 1970", 35 | "7 September 1970 23:15", 36 | "7 September 1970 11:15:26pm", 37 | "03 February 2013", 38 | "12 Feb 2006, 19:17", 39 | "12 Feb 2006 19:17", 40 | "14 May 2019 19:11:40.164", 41 | "4th Sep 2012", 42 | "1st February 2018 13:58:24", 43 | "Mon, 02 Jan 2006 15:04:05 MST", // RFC1123 44 | "Mon, 02 Jan 2006 15:04:05 -0700", 45 | "Tue, 11 Jul 2017 16:28:13 +0200 (CEST)", 46 | "Mon 30 Sep 2018 09:09:09 PM UTC", 47 | "Sun, 07 Jun 2020 00:00:00 +0100", 48 | "Wed, 8 Feb 2023 19:00:46 +1100 (AEDT)", 49 | // ANSIC and UnixDate - weekday month day time year 50 | "Mon Jan 2 15:04:05 2006", 51 | "Mon Jan 2 15:04:05 MST 2006", 52 | "Monday Jan 02 15:04:05 -0700 2006", 53 | "Mon Jan 2 15:04:05.103786 2006", 54 | // RubyDate - weekday month day time offset year 55 | "Mon Jan 02 15:04:05 -0700 2006", 56 | // ANSIC_GLIBC - weekday day month year time 57 | "Mon 02 Jan 2006 03:04:05 PM UTC", 58 | "Monday 02 Jan 2006 03:04:05 PM MST", 59 | // weekday month day time timezone-offset year 60 | "Mon Aug 10 15:44:11 UTC+0000 2015", 61 | // git log default date format 62 | "Thu Apr 7 15:13:13 2005 -0700", 63 | // variants of git log default date format 64 | "Thu Apr 7 15:13:13 2005 -07:00", 65 | "Thu Apr 7 15:13:13 2005 -07:00 PST", 66 | "Thu Apr 7 15:13:13 2005 -07:00 PST (Pacific Standard Time)", 67 | "Thu Apr 7 15:13:13 -0700 2005", 68 | "Thu Apr 7 15:13:13 -07:00 2005", 69 | "Thu Apr 7 15:13:13 -0700 PST 2005", 70 | "Thu Apr 7 15:13:13 -07:00 PST 2005", 71 | "Thu Apr 7 15:13:13 PST 2005", 72 | // Variants of the above with a (full time zone description) 73 | "Fri Jul 3 2015 06:04:07 PST-0700 (Pacific Daylight Time)", 74 | "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", 75 | "Sun, 3 Jan 2021 00:12:23 +0800 (GMT+08:00)", 76 | // year month day 77 | "2013 May 2", 78 | "2013 May 02 11:37:55", 79 | // dd/Mon/year alpha Months 80 | "06/Jan/2008 15:04:05 -0700", 81 | "06/January/2008 15:04:05 -0700", 82 | "06/Jan/2008:15:04:05 -0700", // ngnix-log 83 | "06/January/2008:08:11:17 -0700", 84 | // mm/dd/year (see also PreferMonthFirst and RetryAmbiguousDateWithSwap options) 85 | "3/31/2014", 86 | "03/31/2014", 87 | "08/21/71", 88 | "8/1/71", 89 | "4/8/2014 22:05", 90 | "04/08/2014 22:05", 91 | "04/08/2014, 22:05", 92 | "4/8/14 22:05", 93 | "04/2/2014 03:00:51", 94 | "8/8/1965 1:00 PM", 95 | "8/8/1965 01:00 PM", 96 | "8/8/1965 12:00 AM", 97 | "8/8/1965 12:00:00AM", 98 | "8/8/1965 01:00:01 PM", 99 | "8/8/1965 01:00:01PM -0700", 100 | "8/8/1965 13:00:01 -0700 PST", 101 | "8/8/1965 01:00:01 PM -0700 PST", 102 | "8/8/1965 01:00:01 PM -07:00 PST (Pacific Standard Time)", 103 | "4/02/2014 03:00:51", 104 | "03/19/2012 10:11:59", 105 | "03/19/2012 10:11:59.3186369", 106 | // mon/dd/year 107 | "Oct/ 7/1970", 108 | "Oct/03/1970 22:33:44", 109 | "February/03/1970 11:33:44.555 PM PST", 110 | // yyyy/mm/dd 111 | "2014/3/31", 112 | "2014/03/31", 113 | "2014/4/8 22:05", 114 | "2014/04/08 22:05", 115 | "2014/04/2 03:00:51", 116 | "2014/4/02 03:00:51", 117 | "2012/03/19 10:11:59", 118 | "2012/03/19 10:11:59.3186369", 119 | // weekday, day-mon-yy time 120 | "Fri, 03-Jul-15 08:08:08 CEST", 121 | "Monday, 02-Jan-06 15:04:05 MST", // RFC850 122 | "Monday, 02 Jan 2006 15:04:05 -0600", 123 | "02-Jan-06 15:04:05 MST", 124 | // RFC3339 - yyyy-mm-ddThh 125 | "2006-01-02T15:04:05+0000", 126 | "2009-08-12T22:15:09-07:00", 127 | "2009-08-12T22:15:09", 128 | "2009-08-12T22:15:09.988", 129 | "2009-08-12T22:15:09Z", 130 | "2009-08-12T22:15:09.52Z", 131 | "2017-07-19T03:21:51:897+0100", 132 | "2019-05-29T08:41-04", // no seconds, 2 digit TZ offset 133 | // yyyy-mm-dd hh:mm:ss 134 | "2014-04-26 17:24:37.3186369", 135 | "2012-08-03 18:31:59.257000000", 136 | "2014-04-26 17:24:37.123", 137 | "2014-04-01 12:01am", 138 | "2014-04-01 12:01:59.765 AM", 139 | "2014-04-01 12:01:59,765", 140 | "2014-04-01 22:43", 141 | "2014-04-01 22:43:22", 142 | "2014-12-16 06:20:00 UTC", 143 | "2014-12-16 06:20:00 GMT", 144 | "2014-04-26 05:24:37 PM", 145 | "2014-04-26 13:13:43 +0800", 146 | "2014-04-26 13:13:43 +0800 +08", 147 | "2014-04-26 13:13:44 +09:00", 148 | "2012-08-03 18:31:59.257000000 +0000 UTC", 149 | "2015-09-30 18:48:56.35272715 +0000 UTC", 150 | "2015-02-18 00:12:00 +0000 GMT", // golang native format 151 | "2015-02-18 00:12:00 +0000 UTC", 152 | "2015-02-08 03:02:00 +0300 MSK m=+0.000000001", 153 | "2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001", 154 | "2017-07-19 03:21:51+00:00", 155 | "2017-04-03 22:32:14.322 CET", 156 | "2017-04-03 22:32:14,322 CET", 157 | "2017-04-03 22:32:14:322 CET", 158 | "2018-09-30 08:09:13.123PM PMDT", // PMDT time zone 159 | "2018-09-30 08:09:13.123 am AMT", // AMT time zone 160 | "2014-04-26", 161 | "2014-04", 162 | "2014", 163 | // yyyy-mm-dd(offset) 164 | "2020-07-20+08:00", 165 | "2020-07-20+0800", 166 | // year-mon-dd 167 | "2013-Feb-03", 168 | "2013-February-03 09:07:08.123", 169 | // dd-mon-year 170 | "03-Feb-13", 171 | "03-Feb-2013", 172 | "07-Feb-2004 09:07:07 +0200", 173 | "07-February-2004 09:07:07 +0200", 174 | // dd-mm-year (this format (common in Europe) always puts the day first, regardless of PreferMonthFirst) 175 | "28-02-02", 176 | "28-02-02 15:16:17", 177 | "28-02-2002", 178 | "28-02-2002 15:16:17", 179 | // mm.dd.yy (see also PreferMonthFirst and RetryAmbiguousDateWithSwap options) 180 | "3.31.2014", 181 | "03.31.14", 182 | "03.31.2014", 183 | "03.31.2014 10:11:59 MST", 184 | "03.31.2014 10:11:59.3186369Z", 185 | // year.mm.dd 186 | "2014.03", 187 | "2014.03.30", 188 | "2014.03.30 08:33pm", 189 | "2014.03.30T08:33:44.555 PM -0700 MST", 190 | "2014.03.30-0600", 191 | // yyyy:mm:dd 192 | "2014:3:31", 193 | "2014:03:31", 194 | "2014:4:8 22:05", 195 | "2014:04:08 22:05", 196 | "2014:04:2 03:00:51", 197 | "2014:4:02 03:00:51", 198 | "2012:03:19 10:11:59", 199 | "2012:03:19 10:11:59.3186369", 200 | // mm:dd:yyyy (see also PreferMonthFirst and RetryAmbiguousDateWithSwap options) 201 | "08:03:2012", 202 | "08:04:2012 18:31:59+00:00", 203 | // yyyymmdd and similar 204 | "20140601", 205 | "20140722105203", 206 | "20140722105203.364", 207 | // Chinese 208 | "2014年4月25日", 209 | "2014年04月08日", 210 | "2014年04月08日 19:17:22 -0700", 211 | // RabbitMQ log format 212 | "8-Mar-2018::14:09:27", 213 | "08-03-2018::02:09:29 PM", 214 | // yymmdd hh:mm:yy mysql log 215 | // 080313 05:21:55 mysqld started 216 | "171113 14:14:20", 217 | "190910 11:51:49", 218 | // unix seconds, ms, micro, nano 219 | "1332151919", 220 | "1384216367189", 221 | "1384216367111222", 222 | "1384216367111222333", 223 | // syslog RFC3164 (and non-conformant variants) 224 | "Apr 9 12:37:24", 225 | "Apr 9 12:37:24-10", 226 | "Apr 9 12:37:24-1000", 227 | "Apr 9 12:37:24 UTC-10", 228 | "Apr 9 12:37:24 MST", 229 | "Apr 9 12:37:24 MST-07:00", 230 | "Apr 9 12:37:24 TZ-10", 231 | "Apr 9 12:37:24 TZ+02:00", 232 | "Apr 9 12:37:24+10", 233 | "Apr 9 12:37:24+10:00", 234 | "Apr 9 12:37:24 CEST", 235 | "Apr 9 12:37:24 CEST+0200", 236 | "Apr 9 12:37:24 2025", 237 | "Apr 9 12:37:24 2025 +02:00", 238 | "Apr 9 2025 12:37:24", 239 | "Apr 9 2025 12:37:24 -0700", 240 | // syslog RFC5424 (and non-conformant variants) 241 | "2025-04-09T12:37:24Z", 242 | "2025-04-09T12:37:24.123Z", 243 | "2025-04-09T12:37:24.123456Z", 244 | "2025-04-09T12:37:24-10:00", 245 | "2025-04-09T12:37:24.123 +0200", 246 | "2025-04-09T12:37:24.123456 -0700 MDT", 247 | } 248 | 249 | var ( 250 | timezone = "" 251 | ) 252 | 253 | func main() { 254 | flag.StringVar(&timezone, "timezone", "UTC", "Timezone aka `America/Los_Angeles` formatted time-zone") 255 | flag.Parse() 256 | 257 | if timezone != "" { 258 | // NOTE: This is very, very important to understand 259 | // time-parsing in go 260 | loc, err := time.LoadLocation(timezone) 261 | if err != nil { 262 | panic(err.Error()) 263 | } 264 | time.Local = loc 265 | } 266 | 267 | table := termtables.CreateTable() 268 | 269 | table.AddHeaders("Input", "Parsed, and Output as %v") 270 | for _, dateExample := range examples { 271 | t, err := dateparse.ParseLocal(dateExample) 272 | if err != nil { 273 | panic(err.Error()) 274 | } 275 | table.AddRow(dateExample, fmt.Sprintf("%v", t)) 276 | } 277 | fmt.Println(table.Render()) 278 | } 279 | 280 | /* 281 | +------------------------------------------------------------+-----------------------------------------+ 282 | | Input | Parsed, and Output as %v | 283 | +------------------------------------------------------------+-----------------------------------------+ 284 | | May 8, 2009 5:57:51 PM | 2009-05-08 17:57:51 +0000 UTC | 285 | | oct 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | 286 | | oct 7, '70 | 1970-10-07 00:00:00 +0000 UTC | 287 | | oct. 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | 288 | | oct. 7, 70 | 1970-10-07 00:00:00 +0000 UTC | 289 | | October 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | 290 | | October 7th, 1970 | 1970-10-07 00:00:00 +0000 UTC | 291 | | Sept. 7, 1970 11:15:26pm | 1970-09-07 23:15:26 +0000 UTC | 292 | | Sep 7 2009 11:15:26.123 PM PST | 2009-09-07 23:15:26.123 +0000 PST | 293 | | September 3rd, 2009 11:15:26.123456789pm | 2009-09-03 23:15:26.123456789 +0000 UTC | 294 | | September 17 2012 10:09am | 2012-09-17 10:09:00 +0000 UTC | 295 | | September 17, 2012, 10:10:09 | 2012-09-17 10:10:09 +0000 UTC | 296 | | Sep 17, 2012 at 10:02am (EST) | 2012-09-17 10:02:00 +0000 EST | 297 | | September 17, 2012 at 10:09am PST-08 | 2012-09-17 10:09:00 -0800 PST | 298 | | September 17 2012 5:00pm UTC-0700 | 2012-09-17 17:00:00 -0700 -0700 | 299 | | September 17 2012 5:00pm GMT-0700 | 2012-09-17 17:00:00 -0700 -0700 | 300 | | 7 oct 70 | 1970-10-07 00:00:00 +0000 UTC | 301 | | 7 Oct 1970 | 1970-10-07 00:00:00 +0000 UTC | 302 | | 7 September 1970 23:15 | 1970-09-07 23:15:00 +0000 UTC | 303 | | 7 September 1970 11:15:26pm | 1970-09-07 23:15:26 +0000 UTC | 304 | | 03 February 2013 | 2013-02-03 00:00:00 +0000 UTC | 305 | | 12 Feb 2006, 19:17 | 2006-02-12 19:17:00 +0000 UTC | 306 | | 12 Feb 2006 19:17 | 2006-02-12 19:17:00 +0000 UTC | 307 | | 14 May 2019 19:11:40.164 | 2019-05-14 19:11:40.164 +0000 UTC | 308 | | 4th Sep 2012 | 2012-09-04 00:00:00 +0000 UTC | 309 | | 1st February 2018 13:58:24 | 2018-02-01 13:58:24 +0000 UTC | 310 | | Mon, 02 Jan 2006 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | 311 | | Mon, 02 Jan 2006 15:04:05 -0700 | 2006-01-02 15:04:05 -0700 -0700 | 312 | | Tue, 11 Jul 2017 16:28:13 +0200 (CEST) | 2017-07-11 16:28:13 +0200 +0200 | 313 | | Mon 30 Sep 2018 09:09:09 PM UTC | 2018-09-30 21:09:09 +0000 UTC | 314 | | Sun, 07 Jun 2020 00:00:00 +0100 | 2020-06-07 00:00:00 +0100 +0100 | 315 | | Wed, 8 Feb 2023 19:00:46 +1100 (AEDT) | 2023-02-08 19:00:46 +1100 +1100 | 316 | | Mon Jan 2 15:04:05 2006 | 2006-01-02 15:04:05 +0000 UTC | 317 | | Mon Jan 2 15:04:05 MST 2006 | 2006-01-02 15:04:05 +0000 MST | 318 | | Monday Jan 02 15:04:05 -0700 2006 | 2006-01-02 15:04:05 -0700 -0700 | 319 | | Mon Jan 2 15:04:05.103786 2006 | 2006-01-02 15:04:05.103786 +0000 UTC | 320 | | Mon Jan 02 15:04:05 -0700 2006 | 2006-01-02 15:04:05 -0700 -0700 | 321 | | Mon 02 Jan 2006 03:04:05 PM UTC | 2006-01-02 15:04:05 +0000 UTC | 322 | | Monday 02 Jan 2006 03:04:05 PM MST | 2006-01-02 15:04:05 +0000 MST | 323 | | Mon Aug 10 15:44:11 UTC+0000 2015 | 2015-08-10 15:44:11 +0000 UTC | 324 | | Thu Apr 7 15:13:13 2005 -0700 | 2005-04-07 15:13:13 -0700 -0700 | 325 | | Thu Apr 7 15:13:13 2005 -07:00 | 2005-04-07 15:13:13 -0700 -0700 | 326 | | Thu Apr 7 15:13:13 2005 -07:00 PST | 2005-04-07 15:13:13 -0700 PST | 327 | | Thu Apr 7 15:13:13 2005 -07:00 PST (Pacific Standard Time) | 2005-04-07 15:13:13 -0700 PST | 328 | | Thu Apr 7 15:13:13 -0700 2005 | 2005-04-07 15:13:13 -0700 -0700 | 329 | | Thu Apr 7 15:13:13 -07:00 2005 | 2005-04-07 15:13:13 -0700 -0700 | 330 | | Thu Apr 7 15:13:13 -0700 PST 2005 | 2005-04-07 15:13:13 -0700 PST | 331 | | Thu Apr 7 15:13:13 -07:00 PST 2005 | 2005-04-07 15:13:13 -0700 PST | 332 | | Thu Apr 7 15:13:13 PST 2005 | 2005-04-07 15:13:13 +0000 PST | 333 | | Fri Jul 3 2015 06:04:07 PST-0700 (Pacific Daylight Time) | 2015-07-03 06:04:07 -0700 PST | 334 | | Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) | 2015-07-03 18:04:07 +0100 +0100 | 335 | | Sun, 3 Jan 2021 00:12:23 +0800 (GMT+08:00) | 2021-01-03 00:12:23 +0800 +0800 | 336 | | 2013 May 2 | 2013-05-02 00:00:00 +0000 UTC | 337 | | 2013 May 02 11:37:55 | 2013-05-02 11:37:55 +0000 UTC | 338 | | 06/Jan/2008 15:04:05 -0700 | 2008-01-06 15:04:05 -0700 -0700 | 339 | | 06/January/2008 15:04:05 -0700 | 2008-01-06 15:04:05 -0700 -0700 | 340 | | 06/Jan/2008:15:04:05 -0700 | 2008-01-06 15:04:05 -0700 -0700 | 341 | | 06/January/2008:08:11:17 -0700 | 2008-01-06 08:11:17 -0700 -0700 | 342 | | 3/31/2014 | 2014-03-31 00:00:00 +0000 UTC | 343 | | 03/31/2014 | 2014-03-31 00:00:00 +0000 UTC | 344 | | 08/21/71 | 1971-08-21 00:00:00 +0000 UTC | 345 | | 8/1/71 | 1971-08-01 00:00:00 +0000 UTC | 346 | | 4/8/2014 22:05 | 2014-04-08 22:05:00 +0000 UTC | 347 | | 04/08/2014 22:05 | 2014-04-08 22:05:00 +0000 UTC | 348 | | 04/08/2014, 22:05 | 2014-04-08 22:05:00 +0000 UTC | 349 | | 4/8/14 22:05 | 2014-04-08 22:05:00 +0000 UTC | 350 | | 04/2/2014 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 351 | | 8/8/1965 1:00 PM | 1965-08-08 13:00:00 +0000 UTC | 352 | | 8/8/1965 01:00 PM | 1965-08-08 13:00:00 +0000 UTC | 353 | | 8/8/1965 12:00 AM | 1965-08-08 00:00:00 +0000 UTC | 354 | | 8/8/1965 12:00:00AM | 1965-08-08 00:00:00 +0000 UTC | 355 | | 8/8/1965 01:00:01 PM | 1965-08-08 13:00:01 +0000 UTC | 356 | | 8/8/1965 01:00:01PM -0700 | 1965-08-08 13:00:01 -0700 -0700 | 357 | | 8/8/1965 13:00:01 -0700 PST | 1965-08-08 13:00:01 -0700 PST | 358 | | 8/8/1965 01:00:01 PM -0700 PST | 1965-08-08 13:00:01 -0700 PST | 359 | | 8/8/1965 01:00:01 PM -07:00 PST (Pacific Standard Time) | 1965-08-08 13:00:01 -0700 PST | 360 | | 4/02/2014 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 361 | | 03/19/2012 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | 362 | | 03/19/2012 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | 363 | | Oct/ 7/1970 | 1970-10-07 00:00:00 +0000 UTC | 364 | | Oct/03/1970 22:33:44 | 1970-10-03 22:33:44 +0000 UTC | 365 | | February/03/1970 11:33:44.555 PM PST | 1970-02-03 23:33:44.555 +0000 PST | 366 | | 2014/3/31 | 2014-03-31 00:00:00 +0000 UTC | 367 | | 2014/03/31 | 2014-03-31 00:00:00 +0000 UTC | 368 | | 2014/4/8 22:05 | 2014-04-08 22:05:00 +0000 UTC | 369 | | 2014/04/08 22:05 | 2014-04-08 22:05:00 +0000 UTC | 370 | | 2014/04/2 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 371 | | 2014/4/02 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 372 | | 2012/03/19 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | 373 | | 2012/03/19 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | 374 | | Fri, 03-Jul-15 08:08:08 CEST | 2015-07-03 08:08:08 +0000 CEST | 375 | | Monday, 02-Jan-06 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | 376 | | Monday, 02 Jan 2006 15:04:05 -0600 | 2006-01-02 15:04:05 -0600 -0600 | 377 | | 02-Jan-06 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | 378 | | 2006-01-02T15:04:05+0000 | 2006-01-02 15:04:05 +0000 UTC | 379 | | 2009-08-12T22:15:09-07:00 | 2009-08-12 22:15:09 -0700 -0700 | 380 | | 2009-08-12T22:15:09 | 2009-08-12 22:15:09 +0000 UTC | 381 | | 2009-08-12T22:15:09.988 | 2009-08-12 22:15:09.988 +0000 UTC | 382 | | 2009-08-12T22:15:09Z | 2009-08-12 22:15:09 +0000 UTC | 383 | | 2009-08-12T22:15:09.52Z | 2009-08-12 22:15:09.52 +0000 UTC | 384 | | 2017-07-19T03:21:51:897+0100 | 2017-07-19 03:21:51.897 +0100 +0100 | 385 | | 2019-05-29T08:41-04 | 2019-05-29 08:41:00 -0400 -0400 | 386 | | 2014-04-26 17:24:37.3186369 | 2014-04-26 17:24:37.3186369 +0000 UTC | 387 | | 2012-08-03 18:31:59.257000000 | 2012-08-03 18:31:59.257 +0000 UTC | 388 | | 2014-04-26 17:24:37.123 | 2014-04-26 17:24:37.123 +0000 UTC | 389 | | 2014-04-01 12:01am | 2014-04-01 00:01:00 +0000 UTC | 390 | | 2014-04-01 12:01:59.765 AM | 2014-04-01 00:01:59.765 +0000 UTC | 391 | | 2014-04-01 12:01:59,765 | 2014-04-01 12:01:59.765 +0000 UTC | 392 | | 2014-04-01 22:43 | 2014-04-01 22:43:00 +0000 UTC | 393 | | 2014-04-01 22:43:22 | 2014-04-01 22:43:22 +0000 UTC | 394 | | 2014-12-16 06:20:00 UTC | 2014-12-16 06:20:00 +0000 UTC | 395 | | 2014-12-16 06:20:00 GMT | 2014-12-16 06:20:00 +0000 GMT | 396 | | 2014-04-26 05:24:37 PM | 2014-04-26 17:24:37 +0000 UTC | 397 | | 2014-04-26 13:13:43 +0800 | 2014-04-26 13:13:43 +0800 +0800 | 398 | | 2014-04-26 13:13:43 +0800 +08 | 2014-04-26 13:13:43 +0800 +0800 | 399 | | 2014-04-26 13:13:44 +09:00 | 2014-04-26 13:13:44 +0900 +0900 | 400 | | 2012-08-03 18:31:59.257000000 +0000 UTC | 2012-08-03 18:31:59.257 +0000 UTC | 401 | | 2015-09-30 18:48:56.35272715 +0000 UTC | 2015-09-30 18:48:56.35272715 +0000 UTC | 402 | | 2015-02-18 00:12:00 +0000 GMT | 2015-02-18 00:12:00 +0000 GMT | 403 | | 2015-02-18 00:12:00 +0000 UTC | 2015-02-18 00:12:00 +0000 UTC | 404 | | 2015-02-08 03:02:00 +0300 MSK m=+0.000000001 | 2015-02-08 03:02:00 +0300 MSK | 405 | | 2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001 | 2015-02-08 03:02:00.001 +0300 MSK | 406 | | 2017-07-19 03:21:51+00:00 | 2017-07-19 03:21:51 +0000 UTC | 407 | | 2017-04-03 22:32:14.322 CET | 2017-04-03 22:32:14.322 +0000 CET | 408 | | 2017-04-03 22:32:14,322 CET | 2017-04-03 22:32:14.322 +0000 CET | 409 | | 2017-04-03 22:32:14:322 CET | 2017-04-03 22:32:14.322 +0000 CET | 410 | | 2018-09-30 08:09:13.123PM PMDT | 2018-09-30 20:09:13.123 +0000 PMDT | 411 | | 2018-09-30 08:09:13.123 am AMT | 2018-09-30 08:09:13.123 +0000 AMT | 412 | | 2014-04-26 | 2014-04-26 00:00:00 +0000 UTC | 413 | | 2014-04 | 2014-04-01 00:00:00 +0000 UTC | 414 | | 2014 | 2014-01-01 00:00:00 +0000 UTC | 415 | | 2020-07-20+08:00 | 2020-07-20 00:00:00 +0800 +0800 | 416 | | 2020-07-20+0800 | 2020-07-20 00:00:00 +0800 +0800 | 417 | | 2013-Feb-03 | 2013-02-03 00:00:00 +0000 UTC | 418 | | 2013-February-03 09:07:08.123 | 2013-02-03 09:07:08.123 +0000 UTC | 419 | | 03-Feb-13 | 2013-02-03 00:00:00 +0000 UTC | 420 | | 03-Feb-2013 | 2013-02-03 00:00:00 +0000 UTC | 421 | | 07-Feb-2004 09:07:07 +0200 | 2004-02-07 09:07:07 +0200 +0200 | 422 | | 07-February-2004 09:07:07 +0200 | 2004-02-07 09:07:07 +0200 +0200 | 423 | | 28-02-02 | 2002-02-28 00:00:00 +0000 UTC | 424 | | 28-02-02 15:16:17 | 2002-02-28 15:16:17 +0000 UTC | 425 | | 28-02-2002 | 2002-02-28 00:00:00 +0000 UTC | 426 | | 28-02-2002 15:16:17 | 2002-02-28 15:16:17 +0000 UTC | 427 | | 3.31.2014 | 2014-03-31 00:00:00 +0000 UTC | 428 | | 03.31.14 | 2014-03-31 00:00:00 +0000 UTC | 429 | | 03.31.2014 | 2014-03-31 00:00:00 +0000 UTC | 430 | | 03.31.2014 10:11:59 MST | 2014-03-31 10:11:59 +0000 MST | 431 | | 03.31.2014 10:11:59.3186369Z | 2014-03-31 10:11:59.3186369 +0000 UTC | 432 | | 2014.03 | 2014-03-01 00:00:00 +0000 UTC | 433 | | 2014.03.30 | 2014-03-30 00:00:00 +0000 UTC | 434 | | 2014.03.30 08:33pm | 2014-03-30 20:33:00 +0000 UTC | 435 | | 2014.03.30T08:33:44.555 PM -0700 MST | 2014-03-30 20:33:44.555 -0700 MST | 436 | | 2014.03.30-0600 | 2014-03-30 00:00:00 -0600 -0600 | 437 | | 2014:3:31 | 2014-03-31 00:00:00 +0000 UTC | 438 | | 2014:03:31 | 2014-03-31 00:00:00 +0000 UTC | 439 | | 2014:4:8 22:05 | 2014-04-08 22:05:00 +0000 UTC | 440 | | 2014:04:08 22:05 | 2014-04-08 22:05:00 +0000 UTC | 441 | | 2014:04:2 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 442 | | 2014:4:02 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 443 | | 2012:03:19 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | 444 | | 2012:03:19 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | 445 | | 08:03:2012 | 2012-08-03 00:00:00 +0000 UTC | 446 | | 08:04:2012 18:31:59+00:00 | 2012-08-04 18:31:59 +0000 UTC | 447 | | 20140601 | 2014-06-01 00:00:00 +0000 UTC | 448 | | 20140722105203 | 2014-07-22 10:52:03 +0000 UTC | 449 | | 20140722105203.364 | 2014-07-22 10:52:03.364 +0000 UTC | 450 | | 2014年4月25日 | 2014-04-25 00:00:00 +0000 UTC | 451 | | 2014年04月08日 | 2014-04-08 00:00:00 +0000 UTC | 452 | | 2014年04月08日 19:17:22 -0700 | 2014-04-08 19:17:22 -0700 -0700 | 453 | | 8-Mar-2018::14:09:27 | 2018-03-08 14:09:27 +0000 UTC | 454 | | 08-03-2018::02:09:29 PM | 2018-03-08 14:09:29 +0000 UTC | 455 | | 171113 14:14:20 | 2017-11-13 14:14:20 +0000 UTC | 456 | | 190910 11:51:49 | 2019-09-10 11:51:49 +0000 UTC | 457 | | 1332151919 | 2012-03-19 10:11:59 +0000 UTC | 458 | | 1384216367189 | 2013-11-12 00:32:47.189 +0000 UTC | 459 | | 1384216367111222 | 2013-11-12 00:32:47.111222 +0000 UTC | 460 | | 1384216367111222333 | 2013-11-12 00:32:47.111222333 +0000 UTC | 461 | +------------------------------------------------------------+-----------------------------------------+ 462 | */ 463 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Go Date Parser 2 | --------------------------- 3 | [![GoDoc](https://godoc.org/github.com/itlightning/dateparse?status.svg)](http://godoc.org/github.com/itlightning/dateparse) 4 | ![Test Status](https://github.com/itlightning/dateparse/actions/workflows/test.yaml/badge.svg) 5 | [![Go ReportCard](https://goreportcard.com/badge/itlightning/dateparse)](https://goreportcard.com/report/itlightning/dateparse) 6 | 7 | Parse date/time strings without knowing the format in advance. Supports 100+ formats. Validates comprehensively to avoid false positives. Very fast (~single-pass state-machine based approach). See [bench_test.go](https://github.com/itlightning/dateparse/blob/main/bench_test.go) for performance comparison. See the critical note below about timezones. 8 | 9 | ⚡ Maintained by [SparkLogs](https://sparklogs.com/), a cloud-first logging platform that's uniquely powerful, super-easy (schemaless, point-and-shoot ingestion), and affordable. It automatically extracts and classifies structured data out of your unstructured log messages. Enjoy visual pattern-analysis and robust SQL-like search. It's unique architecture means you can log more and pay less. Check it out and give us feedback! SparkLogs is developed by [IT Lightning](https://itlightning.com/). ⚡ 10 | 11 | 🐛💡 Find a bug or have an idea with this package? [Issues](https://github.com/itlightning/dateparse/issues) and pull requests are welcome. 12 | 13 | 14 | History and Contributors 15 | ---------------------------------- 16 | 17 | This is an actively maintained fork of the excellent [original dateparse package](https://github.com/araddon/dateparse) by [@araddon](https://github.com/araddon). 18 | This fork [incorporates](https://github.com/araddon/dateparse/pull/159) many bugfixes from the community, and adds comprehensive validation and extensive performance optimizations. 19 | A special thanks to [@araddon](https://github.com/araddon), other contributors to the original project, as well as those who contributed fixes that got incorporated into this version: 20 | [@arran4](https://github.com/arran4), [@bizy01](https://github.com/bizy01), [@BrianLeishman](https://github.com/BrianLeishman), [@dferstay](https://github.com/dferstay), [@jiangxin](https://github.com/jiangxin), [@jmdacruz](https://github.com/jmdacruz), [@krhubert](https://github.com/krhubert), [@mehanizm](https://github.com/mehanizm), [@xwjdsh](https://github.com/xwjdsh), and [@zifengyu](https://github.com/zifengyu). 21 | 22 | 23 | Ambiguous Date Formats 24 | ---------------------------------- 25 | 26 | **MM/DD/YYYY VS DD/MM/YYYY** Right now this uses mm/dd/yyyy *when* ambiguous. If this is not desired behavior, use `ParseStrict` which will fail on ambiguous date strings. This behavior can be adjusted using the `PreferMonthFirst` parser option. Some ambiguous formats can fail (e.g., trying to parse 31/03/2023 as the default month-first format `MM/DD/YYYY`), but can be automatically retried with `RetryAmbiguousDateWithSwap`. 27 | 28 | ```go 29 | 30 | // Normal parse. Equivalent Timezone rules as time.Parse() 31 | t, err := dateparse.ParseAny("3/1/2014") 32 | 33 | // Parse Strict, error on ambigous mm/dd vs dd/mm dates 34 | t, err := dateparse.ParseStrict("3/1/2014") 35 | > returns error 36 | 37 | // Return a string that represents the layout to parse the given date-time. 38 | // For certain highly complex date formats, ParseFormat's return value may 39 | // not be accurate (if this is the case, the returned format string will be a 40 | // different length, than the input). In these cases, ParseAny will still be 41 | // able to successfully parse the format, but this return value will fail to 42 | // parse. For example, anything that starts with a full weekday will fail. 43 | layout, err := dateparse.ParseFormat("May 8, 2009 5:57:51 PM") 44 | > "Jan 2, 2006 3:04:05 PM" 45 | 46 | ``` 47 | 48 | 49 | Performance Considerations 50 | ---------------------------------- 51 | 52 | Internally a memory pool is used to minimize allocation overhead. If you could 53 | be frequently parsing text that does not match any format, consider turning on 54 | the the `SimpleErrorMessages` option. This will make error messages have no 55 | contextual details, but will reduce allocation overhead 13x and will be 4x 56 | faster (most of the time is spent in generating a complex error message if the 57 | option is off (default)). 58 | 59 | Timezone Considerations 60 | ---------------------------------- 61 | 62 | The location that your server is configured to affects the results! See example or https://play.golang.org/p/IDHRalIyXh and last paragraph here https://golang.org/pkg/time/#Parse. 63 | 64 | Important points to understand: 65 | * If you are parsing a date string that does *not* reference a timezone, if you use `Parse` it will assume UTC, or for `ParseIn` it will use the specified location. 66 | * If you are parsing a date string that *does* reference a timezone and *does* specify an explicit offset (e.g., `2012-08-03 13:31:59 -0600 MST`), then it will return a time object with a location that represents a fixed timezone that has the given offset and name (it will not validate that the timezone abbreviation specified in the date string is a potential valid match for the given offset). 67 | * This can lead to some potentially unexpected results, for example consider the date string `2012-08-03 18:31:59.000+00:00 PST` -- this string has an explicit offset of `+00:00` (UTC), and so the returned time will have a location with a zero offset (18:31:59.000 UTC) even though the name of the fixed time zone associated with the returned time is `PST`. Essentially, it will always prioritize an explicit offset as accurate over an explicit 68 | * If you are parsing a date string that *does* reference a timezone but *without* an explicit offset (e.g., `2012-08-03 14:32:59 MST`), then it will only recognize and map the timezone name and add an offset if you are using `ParseIn` and specify a location that knows about the given time zone abbreviation (e.g., in this example, you would need to pass the `America/Denver` location and it will recognize the `MST` and `MDT` time zone names) 69 | * If a time zone abbreviation is recognized based on the passed location, then it will use the appropriate offset, and make any appropriate adjustment for daylight saving time (e.g., in the above example, the parsed time would actually contain a zone name of `MDT` because the date is within the range when daylight savings time is active). 70 | * If a time zone abbreviation is *not* recognized for the passed location, then it will create a fake time zone with a *zero* offset but with the specified name. This requires further processing if you are trying to actually get the correct absolute time in the UTC time zone. 71 | * If you receive a parsed time that has a zero offset but a non-UTC timezone name, then you should use a method to map the (sometimes ambiguous) timezone name (e.g., `"EEG"`) into a location name (e.g., `"Africa/Cairo"` or `"Europe/Bucharest"`), and then reconstruct a new time object with the same date/time/nanosecond but with the properly mapped location. (Do not use the `time.In` method to convert it to the new location, as this will treat the original time as if it was in UTC with a zero offset -- you need to reconstruct the time as if it was constructed with the proper location in the first place.) 72 | 73 | cli tool for testing dateformats 74 | ---------------------------------- 75 | 76 | [Date Parse CLI](https://github.com/itlightning/dateparse/tree/main/dateparse) 77 | 78 | Running the tests 79 | ---------------------------------- 80 | 81 | Make sure for your Linux distribution you've installed the relevant package that includes older timezone name links (e.g., `US/Pacific`). For example, on Ubuntu: 82 | 83 | ```bash 84 | sudo apt install tzdata-legacy 85 | ``` 86 | 87 | Extended example 88 | ------------------- 89 | 90 | https://github.com/itlightning/dateparse/blob/main/example/main.go 91 | 92 | ```go 93 | package main 94 | 95 | import ( 96 | "flag" 97 | "fmt" 98 | "time" 99 | 100 | "github.com/itlightning/dateparse" 101 | "github.com/scylladb/termtables" 102 | ) 103 | 104 | var examples = []string{ 105 | // mon day year (time) 106 | "May 8, 2009 5:57:51 PM", 107 | "oct 7, 1970", 108 | "oct 7, '70", 109 | "oct. 7, 1970", 110 | "oct. 7, 70", 111 | "October 7, 1970", 112 | "October 7th, 1970", 113 | "Sept. 7, 1970 11:15:26pm", 114 | "Sep 7 2009 11:15:26.123 PM PST", 115 | "September 3rd, 2009 11:15:26.123456789pm", 116 | "September 17 2012 10:09am", 117 | "September 17, 2012, 10:10:09", 118 | "Sep 17, 2012 at 10:02am (EST)", 119 | // (PST-08 will have an offset of -0800, and a zone name of "PST") 120 | "September 17, 2012 at 10:09am PST-08", 121 | // (UTC-0700 has the same offset as -0700, and the returned zone name will be empty) 122 | "September 17 2012 5:00pm UTC-0700", 123 | "September 17 2012 5:00pm GMT-0700", 124 | // (weekday) day mon year (time) 125 | "7 oct 70", 126 | "7 Oct 1970", 127 | "7 September 1970 23:15", 128 | "7 September 1970 11:15:26pm", 129 | "03 February 2013", 130 | "12 Feb 2006, 19:17", 131 | "12 Feb 2006 19:17", 132 | "14 May 2019 19:11:40.164", 133 | "4th Sep 2012", 134 | "1st February 2018 13:58:24", 135 | "Mon, 02 Jan 2006 15:04:05 MST", // RFC1123 136 | "Mon, 02 Jan 2006 15:04:05 -0700", 137 | "Tue, 11 Jul 2017 16:28:13 +0200 (CEST)", 138 | "Mon 30 Sep 2018 09:09:09 PM UTC", 139 | "Sun, 07 Jun 2020 00:00:00 +0100", 140 | "Wed, 8 Feb 2023 19:00:46 +1100 (AEDT)", 141 | // ANSIC and UnixDate - weekday month day time year 142 | "Mon Jan 2 15:04:05 2006", 143 | "Mon Jan 2 15:04:05 MST 2006", 144 | "Monday Jan 02 15:04:05 -0700 2006", 145 | "Mon Jan 2 15:04:05.103786 2006", 146 | // RubyDate - weekday month day time offset year 147 | "Mon Jan 02 15:04:05 -0700 2006", 148 | // ANSIC_GLIBC - weekday day month year time 149 | "Mon 02 Jan 2006 03:04:05 PM UTC", 150 | "Monday 02 Jan 2006 03:04:05 PM MST", 151 | // weekday month day time timezone-offset year 152 | "Mon Aug 10 15:44:11 UTC+0000 2015", 153 | // git log default date format 154 | "Thu Apr 7 15:13:13 2005 -0700", 155 | // variants of git log default date format 156 | "Thu Apr 7 15:13:13 2005 -07:00", 157 | "Thu Apr 7 15:13:13 2005 -07:00 PST", 158 | "Thu Apr 7 15:13:13 2005 -07:00 PST (Pacific Standard Time)", 159 | "Thu Apr 7 15:13:13 -0700 2005", 160 | "Thu Apr 7 15:13:13 -07:00 2005", 161 | "Thu Apr 7 15:13:13 -0700 PST 2005", 162 | "Thu Apr 7 15:13:13 -07:00 PST 2005", 163 | "Thu Apr 7 15:13:13 PST 2005", 164 | // Variants of the above with a (full time zone description) 165 | "Fri Jul 3 2015 06:04:07 PST-0700 (Pacific Daylight Time)", 166 | "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", 167 | "Sun, 3 Jan 2021 00:12:23 +0800 (GMT+08:00)", 168 | // year month day 169 | "2013 May 2", 170 | "2013 May 02 11:37:55", 171 | // dd/Mon/year alpha Months 172 | "06/Jan/2008 15:04:05 -0700", 173 | "06/January/2008 15:04:05 -0700", 174 | "06/Jan/2008:15:04:05 -0700", // ngnix-log 175 | "06/January/2008:08:11:17 -0700", 176 | // mm/dd/year (see also PreferMonthFirst and RetryAmbiguousDateWithSwap options) 177 | "3/31/2014", 178 | "03/31/2014", 179 | "08/21/71", 180 | "8/1/71", 181 | "4/8/2014 22:05", 182 | "04/08/2014 22:05", 183 | "04/08/2014, 22:05", 184 | "4/8/14 22:05", 185 | "04/2/2014 03:00:51", 186 | "8/8/1965 1:00 PM", 187 | "8/8/1965 01:00 PM", 188 | "8/8/1965 12:00 AM", 189 | "8/8/1965 12:00:00AM", 190 | "8/8/1965 01:00:01 PM", 191 | "8/8/1965 01:00:01PM -0700", 192 | "8/8/1965 13:00:01 -0700 PST", 193 | "8/8/1965 01:00:01 PM -0700 PST", 194 | "8/8/1965 01:00:01 PM -07:00 PST (Pacific Standard Time)", 195 | "4/02/2014 03:00:51", 196 | "03/19/2012 10:11:59", 197 | "03/19/2012 10:11:59.3186369", 198 | // mon/dd/year 199 | "Oct/ 7/1970", 200 | "Oct/03/1970 22:33:44", 201 | "February/03/1970 11:33:44.555 PM PST", 202 | // yyyy/mm/dd 203 | "2014/3/31", 204 | "2014/03/31", 205 | "2014/4/8 22:05", 206 | "2014/04/08 22:05", 207 | "2014/04/2 03:00:51", 208 | "2014/4/02 03:00:51", 209 | "2012/03/19 10:11:59", 210 | "2012/03/19 10:11:59.3186369", 211 | // weekday, day-mon-yy time 212 | "Fri, 03-Jul-15 08:08:08 CEST", 213 | "Monday, 02-Jan-06 15:04:05 MST", // RFC850 214 | "Monday, 02 Jan 2006 15:04:05 -0600", 215 | "02-Jan-06 15:04:05 MST", 216 | // RFC3339 - yyyy-mm-ddThh 217 | "2006-01-02T15:04:05+0000", 218 | "2009-08-12T22:15:09-07:00", 219 | "2009-08-12T22:15:09", 220 | "2009-08-12T22:15:09.988", 221 | "2009-08-12T22:15:09Z", 222 | "2009-08-12T22:15:09.52Z", 223 | "2017-07-19T03:21:51:897+0100", 224 | "2019-05-29T08:41-04", // no seconds, 2 digit TZ offset 225 | // yyyy-mm-dd hh:mm:ss 226 | "2014-04-26 17:24:37.3186369", 227 | "2012-08-03 18:31:59.257000000", 228 | "2014-04-26 17:24:37.123", 229 | "2014-04-01 12:01am", 230 | "2014-04-01 12:01:59.765 AM", 231 | "2014-04-01 12:01:59,765", 232 | "2014-04-01 22:43", 233 | "2014-04-01 22:43:22", 234 | "2014-12-16 06:20:00 UTC", 235 | "2014-12-16 06:20:00 GMT", 236 | "2014-04-26 05:24:37 PM", 237 | "2014-04-26 13:13:43 +0800", 238 | "2014-04-26 13:13:43 +0800 +08", 239 | "2014-04-26 13:13:44 +09:00", 240 | "2012-08-03 18:31:59.257000000 +0000 UTC", 241 | "2015-09-30 18:48:56.35272715 +0000 UTC", 242 | "2015-02-18 00:12:00 +0000 GMT", // golang native format 243 | "2015-02-18 00:12:00 +0000 UTC", 244 | "2015-02-08 03:02:00 +0300 MSK m=+0.000000001", 245 | "2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001", 246 | "2017-07-19 03:21:51+00:00", 247 | "2017-04-03 22:32:14.322 CET", 248 | "2017-04-03 22:32:14,322 CET", 249 | "2017-04-03 22:32:14:322 CET", 250 | "2018-09-30 08:09:13.123PM PMDT", // PMDT time zone 251 | "2018-09-30 08:09:13.123 am AMT", // AMT time zone 252 | "2014-04-26", 253 | "2014-04", 254 | "2014", 255 | // yyyy-mm-dd(offset) 256 | "2020-07-20+08:00", 257 | "2020-07-20+0800", 258 | // year-mon-dd 259 | "2013-Feb-03", 260 | "2013-February-03 09:07:08.123", 261 | // dd-mon-year 262 | "03-Feb-13", 263 | "03-Feb-2013", 264 | "07-Feb-2004 09:07:07 +0200", 265 | "07-February-2004 09:07:07 +0200", 266 | // dd-mm-year (this format (common in Europe) always puts the day first, regardless of PreferMonthFirst) 267 | "28-02-02", 268 | "28-02-02 15:16:17", 269 | "28-02-2002", 270 | "28-02-2002 15:16:17", 271 | // mm.dd.yy (see also PreferMonthFirst and RetryAmbiguousDateWithSwap options) 272 | "3.31.2014", 273 | "03.31.14", 274 | "03.31.2014", 275 | "03.31.2014 10:11:59 MST", 276 | "03.31.2014 10:11:59.3186369Z", 277 | // year.mm.dd 278 | "2014.03", 279 | "2014.03.30", 280 | "2014.03.30 08:33pm", 281 | "2014.03.30T08:33:44.555 PM -0700 MST", 282 | "2014.03.30-0600", 283 | // yyyy:mm:dd 284 | "2014:3:31", 285 | "2014:03:31", 286 | "2014:4:8 22:05", 287 | "2014:04:08 22:05", 288 | "2014:04:2 03:00:51", 289 | "2014:4:02 03:00:51", 290 | "2012:03:19 10:11:59", 291 | "2012:03:19 10:11:59.3186369", 292 | // mm:dd:yyyy (see also PreferMonthFirst and RetryAmbiguousDateWithSwap options) 293 | "08:03:2012", 294 | "08:04:2012 18:31:59+00:00", 295 | // yyyymmdd and similar 296 | "20140601", 297 | "20140722105203", 298 | "20140722105203.364", 299 | // Chinese 300 | "2014年4月25日", 301 | "2014年04月08日", 302 | "2014年04月08日 19:17:22 -0700", 303 | // RabbitMQ log format 304 | "8-Mar-2018::14:09:27", 305 | "08-03-2018::02:09:29 PM", 306 | // yymmdd hh:mm:yy mysql log 307 | // 080313 05:21:55 mysqld started 308 | "171113 14:14:20", 309 | "190910 11:51:49", 310 | // unix seconds, ms, micro, nano 311 | "1332151919", 312 | "1384216367189", 313 | "1384216367111222", 314 | "1384216367111222333", 315 | // syslog RFC3164 (and non-conformant variants) 316 | "Apr 9 12:37:24", 317 | "Apr 9 12:37:24-10", 318 | "Apr 9 12:37:24-1000", 319 | "Apr 9 12:37:24 UTC-10", 320 | "Apr 9 12:37:24 MST", 321 | "Apr 9 12:37:24 MST-07:00", 322 | "Apr 9 12:37:24 TZ-10", 323 | "Apr 9 12:37:24 TZ+02:00", 324 | "Apr 9 12:37:24+10", 325 | "Apr 9 12:37:24+10:00", 326 | "Apr 9 12:37:24 CEST", 327 | "Apr 9 12:37:24 CEST+0200", 328 | "Apr 9 12:37:24 2025", 329 | "Apr 9 12:37:24 2025 +02:00", 330 | "Apr 9 2025 12:37:24", 331 | "Apr 9 2025 12:37:24 -0700", 332 | // syslog RFC5424 (and non-conformant variants) 333 | "2025-04-09T12:37:24Z", 334 | "2025-04-09T12:37:24.123Z", 335 | "2025-04-09T12:37:24.123456Z", 336 | "2025-04-09T12:37:24-10:00", 337 | "2025-04-09T12:37:24.123 +0200", 338 | "2025-04-09T12:37:24.123456 -0700 MDT", 339 | } 340 | 341 | var ( 342 | timezone = "" 343 | ) 344 | 345 | func main() { 346 | flag.StringVar(&timezone, "timezone", "UTC", "Timezone aka `America/Los_Angeles` formatted time-zone") 347 | flag.Parse() 348 | 349 | if timezone != "" { 350 | // NOTE: This is very, very important to understand 351 | // time-parsing in go 352 | loc, err := time.LoadLocation(timezone) 353 | if err != nil { 354 | panic(err.Error()) 355 | } 356 | time.Local = loc 357 | } 358 | 359 | table := termtables.CreateTable() 360 | 361 | table.AddHeaders("Input", "Parsed, and Output as %v") 362 | for _, dateExample := range examples { 363 | t, err := dateparse.ParseLocal(dateExample) 364 | if err != nil { 365 | panic(err.Error()) 366 | } 367 | table.AddRow(dateExample, fmt.Sprintf("%v", t)) 368 | } 369 | fmt.Println(table.Render()) 370 | } 371 | 372 | /* 373 | +------------------------------------------------------------+-----------------------------------------+ 374 | | Input | Parsed, and Output as %v | 375 | +------------------------------------------------------------+-----------------------------------------+ 376 | | May 8, 2009 5:57:51 PM | 2009-05-08 17:57:51 +0000 UTC | 377 | | oct 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | 378 | | oct 7, '70 | 1970-10-07 00:00:00 +0000 UTC | 379 | | oct. 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | 380 | | oct. 7, 70 | 1970-10-07 00:00:00 +0000 UTC | 381 | | October 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | 382 | | October 7th, 1970 | 1970-10-07 00:00:00 +0000 UTC | 383 | | Sept. 7, 1970 11:15:26pm | 1970-09-07 23:15:26 +0000 UTC | 384 | | Sep 7 2009 11:15:26.123 PM PST | 2009-09-07 23:15:26.123 +0000 PST | 385 | | September 3rd, 2009 11:15:26.123456789pm | 2009-09-03 23:15:26.123456789 +0000 UTC | 386 | | September 17 2012 10:09am | 2012-09-17 10:09:00 +0000 UTC | 387 | | September 17, 2012, 10:10:09 | 2012-09-17 10:10:09 +0000 UTC | 388 | | Sep 17, 2012 at 10:02am (EST) | 2012-09-17 10:02:00 +0000 EST | 389 | | September 17, 2012 at 10:09am PST-08 | 2012-09-17 10:09:00 -0800 PST | 390 | | September 17 2012 5:00pm UTC-0700 | 2012-09-17 17:00:00 -0700 -0700 | 391 | | September 17 2012 5:00pm GMT-0700 | 2012-09-17 17:00:00 -0700 -0700 | 392 | | 7 oct 70 | 1970-10-07 00:00:00 +0000 UTC | 393 | | 7 Oct 1970 | 1970-10-07 00:00:00 +0000 UTC | 394 | | 7 September 1970 23:15 | 1970-09-07 23:15:00 +0000 UTC | 395 | | 7 September 1970 11:15:26pm | 1970-09-07 23:15:26 +0000 UTC | 396 | | 03 February 2013 | 2013-02-03 00:00:00 +0000 UTC | 397 | | 12 Feb 2006, 19:17 | 2006-02-12 19:17:00 +0000 UTC | 398 | | 12 Feb 2006 19:17 | 2006-02-12 19:17:00 +0000 UTC | 399 | | 14 May 2019 19:11:40.164 | 2019-05-14 19:11:40.164 +0000 UTC | 400 | | 4th Sep 2012 | 2012-09-04 00:00:00 +0000 UTC | 401 | | 1st February 2018 13:58:24 | 2018-02-01 13:58:24 +0000 UTC | 402 | | Mon, 02 Jan 2006 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | 403 | | Mon, 02 Jan 2006 15:04:05 -0700 | 2006-01-02 15:04:05 -0700 -0700 | 404 | | Tue, 11 Jul 2017 16:28:13 +0200 (CEST) | 2017-07-11 16:28:13 +0200 CEST | 405 | | Mon 30 Sep 2018 09:09:09 PM UTC | 2018-09-30 21:09:09 +0000 UTC | 406 | | Sun, 07 Jun 2020 00:00:00 +0100 | 2020-06-07 00:00:00 +0100 +0100 | 407 | | Wed, 8 Feb 2023 19:00:46 +1100 (AEDT) | 2023-02-08 19:00:46 +1100 AEDT | 408 | | Mon Jan 2 15:04:05 2006 | 2006-01-02 15:04:05 +0000 UTC | 409 | | Mon Jan 2 15:04:05 MST 2006 | 2006-01-02 15:04:05 +0000 MST | 410 | | Monday Jan 02 15:04:05 -0700 2006 | 2006-01-02 15:04:05 -0700 -0700 | 411 | | Mon Jan 2 15:04:05.103786 2006 | 2006-01-02 15:04:05.103786 +0000 UTC | 412 | | Mon Jan 02 15:04:05 -0700 2006 | 2006-01-02 15:04:05 -0700 -0700 | 413 | | Mon 02 Jan 2006 03:04:05 PM UTC | 2006-01-02 15:04:05 +0000 UTC | 414 | | Monday 02 Jan 2006 03:04:05 PM MST | 2006-01-02 15:04:05 +0000 MST | 415 | | Mon Aug 10 15:44:11 UTC+0000 2015 | 2015-08-10 15:44:11 +0000 UTC | 416 | | Thu Apr 7 15:13:13 2005 -0700 | 2005-04-07 15:13:13 -0700 -0700 | 417 | | Thu Apr 7 15:13:13 2005 -07:00 | 2005-04-07 15:13:13 -0700 -0700 | 418 | | Thu Apr 7 15:13:13 2005 -07:00 PST | 2005-04-07 15:13:13 -0700 PST | 419 | | Thu Apr 7 15:13:13 2005 -07:00 PST (Pacific Standard Time) | 2005-04-07 15:13:13 -0700 PST | 420 | | Thu Apr 7 15:13:13 -0700 2005 | 2005-04-07 15:13:13 -0700 -0700 | 421 | | Thu Apr 7 15:13:13 -07:00 2005 | 2005-04-07 15:13:13 -0700 -0700 | 422 | | Thu Apr 7 15:13:13 -0700 PST 2005 | 2005-04-07 15:13:13 -0700 PST | 423 | | Thu Apr 7 15:13:13 -07:00 PST 2005 | 2005-04-07 15:13:13 -0700 PST | 424 | | Thu Apr 7 15:13:13 PST 2005 | 2005-04-07 15:13:13 +0000 PST | 425 | | Fri Jul 3 2015 06:04:07 PST-0700 (Pacific Daylight Time) | 2015-07-03 06:04:07 -0700 PST | 426 | | Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) | 2015-07-03 18:04:07 +0100 +0100 | 427 | | Sun, 3 Jan 2021 00:12:23 +0800 (GMT+08:00) | 2021-01-03 00:12:23 +0800 +0800 | 428 | | 2013 May 2 | 2013-05-02 00:00:00 +0000 UTC | 429 | | 2013 May 02 11:37:55 | 2013-05-02 11:37:55 +0000 UTC | 430 | | 06/Jan/2008 15:04:05 -0700 | 2008-01-06 15:04:05 -0700 -0700 | 431 | | 06/January/2008 15:04:05 -0700 | 2008-01-06 15:04:05 -0700 -0700 | 432 | | 06/Jan/2008:15:04:05 -0700 | 2008-01-06 15:04:05 -0700 -0700 | 433 | | 06/January/2008:08:11:17 -0700 | 2008-01-06 08:11:17 -0700 -0700 | 434 | | 3/31/2014 | 2014-03-31 00:00:00 +0000 UTC | 435 | | 03/31/2014 | 2014-03-31 00:00:00 +0000 UTC | 436 | | 08/21/71 | 1971-08-21 00:00:00 +0000 UTC | 437 | | 8/1/71 | 1971-08-01 00:00:00 +0000 UTC | 438 | | 4/8/2014 22:05 | 2014-04-08 22:05:00 +0000 UTC | 439 | | 04/08/2014 22:05 | 2014-04-08 22:05:00 +0000 UTC | 440 | | 04/08/2014, 22:05 | 2014-04-08 22:05:00 +0000 UTC | 441 | | 4/8/14 22:05 | 2014-04-08 22:05:00 +0000 UTC | 442 | | 04/2/2014 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 443 | | 8/8/1965 1:00 PM | 1965-08-08 13:00:00 +0000 UTC | 444 | | 8/8/1965 01:00 PM | 1965-08-08 13:00:00 +0000 UTC | 445 | | 8/8/1965 12:00 AM | 1965-08-08 00:00:00 +0000 UTC | 446 | | 8/8/1965 12:00:00AM | 1965-08-08 00:00:00 +0000 UTC | 447 | | 8/8/1965 01:00:01 PM | 1965-08-08 13:00:01 +0000 UTC | 448 | | 8/8/1965 01:00:01PM -0700 | 1965-08-08 13:00:01 -0700 -0700 | 449 | | 8/8/1965 13:00:01 -0700 PST | 1965-08-08 13:00:01 -0700 PST | 450 | | 8/8/1965 01:00:01 PM -0700 PST | 1965-08-08 13:00:01 -0700 PST | 451 | | 8/8/1965 01:00:01 PM -07:00 PST (Pacific Standard Time) | 1965-08-08 13:00:01 -0700 PST | 452 | | 4/02/2014 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 453 | | 03/19/2012 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | 454 | | 03/19/2012 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | 455 | | Oct/ 7/1970 | 1970-10-07 00:00:00 +0000 UTC | 456 | | Oct/03/1970 22:33:44 | 1970-10-03 22:33:44 +0000 UTC | 457 | | February/03/1970 11:33:44.555 PM PST | 1970-02-03 23:33:44.555 +0000 PST | 458 | | 2014/3/31 | 2014-03-31 00:00:00 +0000 UTC | 459 | | 2014/03/31 | 2014-03-31 00:00:00 +0000 UTC | 460 | | 2014/4/8 22:05 | 2014-04-08 22:05:00 +0000 UTC | 461 | | 2014/04/08 22:05 | 2014-04-08 22:05:00 +0000 UTC | 462 | | 2014/04/2 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 463 | | 2014/4/02 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 464 | | 2012/03/19 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | 465 | | 2012/03/19 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | 466 | | Fri, 03-Jul-15 08:08:08 CEST | 2015-07-03 08:08:08 +0000 CEST | 467 | | Monday, 02-Jan-06 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | 468 | | Monday, 02 Jan 2006 15:04:05 -0600 | 2006-01-02 15:04:05 -0600 -0600 | 469 | | 02-Jan-06 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | 470 | | 2006-01-02T15:04:05+0000 | 2006-01-02 15:04:05 +0000 UTC | 471 | | 2009-08-12T22:15:09-07:00 | 2009-08-12 22:15:09 -0700 -0700 | 472 | | 2009-08-12T22:15:09 | 2009-08-12 22:15:09 +0000 UTC | 473 | | 2009-08-12T22:15:09.988 | 2009-08-12 22:15:09.988 +0000 UTC | 474 | | 2009-08-12T22:15:09Z | 2009-08-12 22:15:09 +0000 UTC | 475 | | 2009-08-12T22:15:09.52Z | 2009-08-12 22:15:09.52 +0000 UTC | 476 | | 2017-07-19T03:21:51:897+0100 | 2017-07-19 03:21:51.897 +0100 +0100 | 477 | | 2019-05-29T08:41-04 | 2019-05-29 08:41:00 -0400 -0400 | 478 | | 2014-04-26 17:24:37.3186369 | 2014-04-26 17:24:37.3186369 +0000 UTC | 479 | | 2012-08-03 18:31:59.257000000 | 2012-08-03 18:31:59.257 +0000 UTC | 480 | | 2014-04-26 17:24:37.123 | 2014-04-26 17:24:37.123 +0000 UTC | 481 | | 2014-04-01 12:01am | 2014-04-01 00:01:00 +0000 UTC | 482 | | 2014-04-01 12:01:59.765 AM | 2014-04-01 00:01:59.765 +0000 UTC | 483 | | 2014-04-01 12:01:59,765 | 2014-04-01 12:01:59.765 +0000 UTC | 484 | | 2014-04-01 22:43 | 2014-04-01 22:43:00 +0000 UTC | 485 | | 2014-04-01 22:43:22 | 2014-04-01 22:43:22 +0000 UTC | 486 | | 2014-12-16 06:20:00 UTC | 2014-12-16 06:20:00 +0000 UTC | 487 | | 2014-12-16 06:20:00 GMT | 2014-12-16 06:20:00 +0000 GMT | 488 | | 2014-04-26 05:24:37 PM | 2014-04-26 17:24:37 +0000 UTC | 489 | | 2014-04-26 13:13:43 +0800 | 2014-04-26 13:13:43 +0800 +0800 | 490 | | 2014-04-26 13:13:43 +0800 +08 | 2014-04-26 13:13:43 +0800 +0800 | 491 | | 2014-04-26 13:13:44 +09:00 | 2014-04-26 13:13:44 +0900 +0900 | 492 | | 2012-08-03 18:31:59.257000000 +0000 UTC | 2012-08-03 18:31:59.257 +0000 UTC | 493 | | 2015-09-30 18:48:56.35272715 +0000 UTC | 2015-09-30 18:48:56.35272715 +0000 UTC | 494 | | 2015-02-18 00:12:00 +0000 GMT | 2015-02-18 00:12:00 +0000 GMT | 495 | | 2015-02-18 00:12:00 +0000 UTC | 2015-02-18 00:12:00 +0000 UTC | 496 | | 2015-02-08 03:02:00 +0300 MSK m=+0.000000001 | 2015-02-08 03:02:00 +0300 MSK | 497 | | 2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001 | 2015-02-08 03:02:00.001 +0300 MSK | 498 | | 2017-07-19 03:21:51+00:00 | 2017-07-19 03:21:51 +0000 UTC | 499 | | 2017-04-03 22:32:14.322 CET | 2017-04-03 22:32:14.322 +0000 CET | 500 | | 2017-04-03 22:32:14,322 CET | 2017-04-03 22:32:14.322 +0000 CET | 501 | | 2017-04-03 22:32:14:322 CET | 2017-04-03 22:32:14.322 +0000 CET | 502 | | 2018-09-30 08:09:13.123PM PMDT | 2018-09-30 20:09:13.123 +0000 PMDT | 503 | | 2018-09-30 08:09:13.123 am AMT | 2018-09-30 08:09:13.123 +0000 AMT | 504 | | 2014-04-26 | 2014-04-26 00:00:00 +0000 UTC | 505 | | 2014-04 | 2014-04-01 00:00:00 +0000 UTC | 506 | | 2014 | 2014-01-01 00:00:00 +0000 UTC | 507 | | 2020-07-20+08:00 | 2020-07-20 00:00:00 +0800 +0800 | 508 | | 2020-07-20+0800 | 2020-07-20 00:00:00 +0800 +0800 | 509 | | 2013-Feb-03 | 2013-02-03 00:00:00 +0000 UTC | 510 | | 2013-February-03 09:07:08.123 | 2013-02-03 09:07:08.123 +0000 UTC | 511 | | 03-Feb-13 | 2013-02-03 00:00:00 +0000 UTC | 512 | | 03-Feb-2013 | 2013-02-03 00:00:00 +0000 UTC | 513 | | 07-Feb-2004 09:07:07 +0200 | 2004-02-07 09:07:07 +0200 +0200 | 514 | | 07-February-2004 09:07:07 +0200 | 2004-02-07 09:07:07 +0200 +0200 | 515 | | 28-02-02 | 2002-02-28 00:00:00 +0000 UTC | 516 | | 28-02-02 15:16:17 | 2002-02-28 15:16:17 +0000 UTC | 517 | | 28-02-2002 | 2002-02-28 00:00:00 +0000 UTC | 518 | | 28-02-2002 15:16:17 | 2002-02-28 15:16:17 +0000 UTC | 519 | | 3.31.2014 | 2014-03-31 00:00:00 +0000 UTC | 520 | | 03.31.14 | 2014-03-31 00:00:00 +0000 UTC | 521 | | 03.31.2014 | 2014-03-31 00:00:00 +0000 UTC | 522 | | 03.31.2014 10:11:59 MST | 2014-03-31 10:11:59 +0000 MST | 523 | | 03.31.2014 10:11:59.3186369Z | 2014-03-31 10:11:59.3186369 +0000 UTC | 524 | | 2014.03 | 2014-03-01 00:00:00 +0000 UTC | 525 | | 2014.03.30 | 2014-03-30 00:00:00 +0000 UTC | 526 | | 2014.03.30 08:33pm | 2014-03-30 20:33:00 +0000 UTC | 527 | | 2014.03.30T08:33:44.555 PM -0700 MST | 2014-03-30 20:33:44.555 -0700 MST | 528 | | 2014.03.30-0600 | 2014-03-30 00:00:00 -0600 -0600 | 529 | | 2014:3:31 | 2014-03-31 00:00:00 +0000 UTC | 530 | | 2014:03:31 | 2014-03-31 00:00:00 +0000 UTC | 531 | | 2014:4:8 22:05 | 2014-04-08 22:05:00 +0000 UTC | 532 | | 2014:04:08 22:05 | 2014-04-08 22:05:00 +0000 UTC | 533 | | 2014:04:2 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 534 | | 2014:4:02 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | 535 | | 2012:03:19 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | 536 | | 2012:03:19 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | 537 | | 08:03:2012 | 2012-08-03 00:00:00 +0000 UTC | 538 | | 08:04:2012 18:31:59+00:00 | 2012-08-04 18:31:59 +0000 UTC | 539 | | 20140601 | 2014-06-01 00:00:00 +0000 UTC | 540 | | 20140722105203 | 2014-07-22 10:52:03 +0000 UTC | 541 | | 20140722105203.364 | 2014-07-22 10:52:03.364 +0000 UTC | 542 | | 2014年4月25日 | 2014-04-25 00:00:00 +0000 UTC | 543 | | 2014年04月08日 | 2014-04-08 00:00:00 +0000 UTC | 544 | | 2014年04月08日 19:17:22 -0700 | 2014-04-08 19:17:22 -0700 -0700 | 545 | | 8-Mar-2018::14:09:27 | 2018-03-08 14:09:27 +0000 UTC | 546 | | 08-03-2018::02:09:29 PM | 2018-03-08 14:09:29 +0000 UTC | 547 | | 171113 14:14:20 | 2017-11-13 14:14:20 +0000 UTC | 548 | | 190910 11:51:49 | 2019-09-10 11:51:49 +0000 UTC | 549 | | 1332151919 | 2012-03-19 10:11:59 +0000 UTC | 550 | | 1384216367189 | 2013-11-12 00:32:47.189 +0000 UTC | 551 | | 1384216367111222 | 2013-11-12 00:32:47.111222 +0000 UTC | 552 | | 1384216367111222333 | 2013-11-12 00:32:47.111222333 +0000 UTC | 553 | | Apr 9 12:37:24 | 0000-04-09 12:37:24 +0000 UTC | 554 | | Apr 9 12:37:24-10 | 0000-04-09 12:37:24 -1000 -1000 | 555 | | Apr 9 12:37:24-1000 | 0000-04-09 12:37:24 -1000 -1000 | 556 | | Apr 9 12:37:24 UTC-10 | 0000-04-09 12:37:24 -1000 -1000 | 557 | | Apr 9 12:37:24 MST | 0000-04-09 12:37:24 +0000 MST | 558 | | Apr 9 12:37:24 MST-07:00 | 0000-04-09 12:37:24 -0700 MST | 559 | | Apr 9 12:37:24 TZ-10 | 0000-04-09 12:37:24 -1000 -1000 | 560 | | Apr 9 12:37:24 TZ+02:00 | 0000-04-09 12:37:24 +0200 +0200 | 561 | | Apr 9 12:37:24+10 | 0000-04-09 12:37:24 +1000 +1000 | 562 | | Apr 9 12:37:24+10:00 | 0000-04-09 12:37:24 +1000 +1000 | 563 | | Apr 9 12:37:24 CEST | 0000-04-09 12:37:24 +0000 CEST | 564 | | Apr 9 12:37:24 CEST+0200 | 0000-04-09 12:37:24 +0200 CEST | 565 | | Apr 9 12:37:24 2025 | 2025-04-09 12:37:24 +0000 UTC | 566 | | Apr 9 12:37:24 2025 +02:00 | 2025-04-09 12:37:24 +0200 +0200 | 567 | | Apr 9 2025 12:37:24 | 2025-04-09 12:37:24 +0000 UTC | 568 | | Apr 9 2025 12:37:24 -0700 | 2025-04-09 12:37:24 -0700 -0700 | 569 | | 2025-04-09T12:37:24Z | 2025-04-09 12:37:24 +0000 UTC | 570 | | 2025-04-09T12:37:24.123Z | 2025-04-09 12:37:24.123 +0000 UTC | 571 | | 2025-04-09T12:37:24.123456Z | 2025-04-09 12:37:24.123456 +0000 UTC | 572 | | 2025-04-09T12:37:24-10:00 | 2025-04-09 12:37:24 -1000 -1000 | 573 | | 2025-04-09T12:37:24.123 +0200 | 2025-04-09 12:37:24.123 +0200 +0200 | 574 | | 2025-04-09T12:37:24.123456 -0700 MDT | 2025-04-09 12:37:24.123456 -0700 MDT | 575 | +------------------------------------------------------------+-----------------------------------------+ 576 | */ 577 | 578 | ``` 579 | -------------------------------------------------------------------------------- /parseany_test.go: -------------------------------------------------------------------------------- 1 | package dateparse 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func TestOne(t *testing.T) { 12 | ts := MustParse("2020-07-20+08:00") 13 | assert.Equal(t, "2020-07-19 16:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 14 | } 15 | 16 | type dateTest struct { 17 | in, out, loc, zname string 18 | err bool 19 | preferDayFirst bool 20 | retryAmbiguous bool 21 | expectAmbiguous bool 22 | allowWeekdayPrefix bool 23 | } 24 | 25 | var testInputs = []dateTest{ 26 | {in: "oct 7, 1970", out: "1970-10-07 00:00:00 +0000 UTC"}, 27 | {in: "oct 7, 1970 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 28 | {in: "oct 7, '70", out: "1970-10-07 00:00:00 +0000 UTC"}, 29 | {in: "oct 7, '70 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 30 | {in: "Oct 7, '70", out: "1970-10-07 00:00:00 +0000 UTC"}, 31 | {in: "Oct 7, '70 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 32 | {in: "Oct. 7, '70", out: "1970-10-07 00:00:00 +0000 UTC"}, 33 | {in: "Oct. 7, '70 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 34 | {in: "oct. 7, '70", out: "1970-10-07 00:00:00 +0000 UTC"}, 35 | {in: "oct. 7, '70 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 36 | {in: "oct. 7, 1970", out: "1970-10-07 00:00:00 +0000 UTC"}, 37 | {in: "oct. 7, 1970 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 38 | {in: "Sept. 7, '70", out: "1970-09-07 00:00:00 +0000 UTC"}, 39 | {in: "Sept. 7, '70 11:15:26pm", out: "1970-09-07 23:15:26 +0000 UTC"}, 40 | {in: "sept. 7, 1970", out: "1970-09-07 00:00:00 +0000 UTC"}, 41 | {in: "sept. 7, 1970 11:15:26pm", out: "1970-09-07 23:15:26 +0000 UTC"}, 42 | {in: "Feb 8, 2009 5:57:51 AM", out: "2009-02-08 05:57:51 +0000 UTC"}, 43 | {in: "May 8, 2009 5:57:51 PM", out: "2009-05-08 17:57:51 +0000 UTC"}, 44 | {in: "May 8, 2009 5:57:1 PM", out: "2009-05-08 17:57:01 +0000 UTC"}, 45 | {in: "May 8, 2009 5:7:51 PM", out: "2009-05-08 17:07:51 +0000 UTC"}, 46 | {in: "May 8, 2009, 5:7:51 PM", out: "2009-05-08 17:07:51 +0000 UTC"}, 47 | {in: "June 8 2009", out: "2009-06-08 00:00:00 +0000 UTC"}, 48 | {in: "June 8, 2009", out: "2009-06-08 00:00:00 +0000 UTC"}, 49 | {in: "February 8th 2009", out: "2009-02-08 00:00:00 +0000 UTC"}, 50 | {in: "February 8th, 2009", out: "2009-02-08 00:00:00 +0000 UTC"}, 51 | {in: "September 3rd 2009", out: "2009-09-03 00:00:00 +0000 UTC"}, 52 | {in: "September 3rd, 2009", out: "2009-09-03 00:00:00 +0000 UTC"}, 53 | {in: "June 8 2009 11:15:26pm", out: "2009-06-08 23:15:26 +0000 UTC"}, 54 | {in: "June 8, 2009 11:15:26pm", out: "2009-06-08 23:15:26 +0000 UTC"}, 55 | {in: "February 8th 2009 11:15:26pm", out: "2009-02-08 23:15:26 +0000 UTC"}, 56 | {in: "February 8th, 2009 11:15:26pm", out: "2009-02-08 23:15:26 +0000 UTC"}, 57 | {in: "September 3rd 2009 11:15:26pm", out: "2009-09-03 23:15:26 +0000 UTC"}, 58 | {in: "September 3rd, 2009 11:15:26pm", out: "2009-09-03 23:15:26 +0000 UTC"}, 59 | {in: "7 oct 70", out: "1970-10-07 00:00:00 +0000 UTC"}, 60 | {in: "7 oct 70 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 61 | {in: "7 oct 1970", out: "1970-10-07 00:00:00 +0000 UTC"}, 62 | {in: "7 oct 1970 11:15:26pm", out: "1970-10-07 23:15:26 +0000 UTC"}, 63 | {in: "7 May 1970", out: "1970-05-07 00:00:00 +0000 UTC"}, 64 | {in: "7 May 1970 11:15:26pm", out: "1970-05-07 23:15:26 +0000 UTC"}, 65 | {in: "7 Sep 1970", out: "1970-09-07 00:00:00 +0000 UTC"}, 66 | {in: "7 Sep 1970 11:15:26pm", out: "1970-09-07 23:15:26 +0000 UTC"}, 67 | {in: "7 June 1970", out: "1970-06-07 00:00:00 +0000 UTC"}, 68 | {in: "7 June 1970 11:15:26pm", out: "1970-06-07 23:15:26 +0000 UTC"}, 69 | {in: "7 September 1970", out: "1970-09-07 00:00:00 +0000 UTC"}, 70 | {in: "7 September 1970 11:15:26pm", out: "1970-09-07 23:15:26 +0000 UTC"}, 71 | // ANSIC = "Mon Jan _2 15:04:05 2006" 72 | {in: "Mon Jan 2 15:04:05 2006", out: "2006-01-02 15:04:05 +0000 UTC"}, 73 | {in: "Thu May 8 17:57:51 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, 74 | {in: "Thu May 8 17:57:51 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, 75 | {in: "Monday Jan 2 15:04:05 2006", out: "2006-01-02 15:04:05 +0000 UTC"}, 76 | {in: "Thursday May 8 17:57:51 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, 77 | {in: "Thursday May 8 17:57:51 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, 78 | // ANSIC_GLIBC = "Mon 02 Jan 2006 03:04:05 PM UTC" 79 | {in: "Mon 02 Jan 2006 03:04:05 PM UTC", out: "2006-01-02 15:04:05 +0000 UTC", zname: "UTC"}, 80 | {in: "Mon 02 Jan 2006 03:04:05 PM CEST", out: "2006-01-02 15:04:05 +0000 UTC", zname: "CEST"}, 81 | {in: "Mon 30 Sep 2018 09:09:09 PM UTC", out: "2018-09-30 21:09:09 +0000 UTC", zname: "UTC"}, 82 | {in: "Mon 30 Sep 2018 09:09:09 PM CEST", out: "2018-09-30 21:09:09 +0000 UTC", zname: "CEST"}, 83 | {in: "Mon 02 Jan 2006", out: "2006-01-02 00:00:00 +0000 UTC"}, 84 | {in: "Monday 02 Jan 2006 03:04:05 PM UTC", out: "2006-01-02 15:04:05 +0000 UTC", zname: "UTC"}, 85 | {in: "SUNDAY, July 05 2015", out: "2015-07-05 00:00:00 +0000 UTC", zname: "UTC"}, 86 | // RubyDate = "Mon Jan 02 15:04:05 -0700 2006" 87 | {in: "Mon Jan 02 15:04:05 -0700 2006", out: "2006-01-02 22:04:05 +0000 UTC"}, 88 | {in: "Thu May 08 11:57:51 -0700 2009", out: "2009-05-08 18:57:51 +0000 UTC"}, 89 | {in: "Thursday May 08 11:57:51 -0700 2009", out: "2009-05-08 18:57:51 +0000 UTC"}, 90 | // UnixDate = "Mon Jan _2 15:04:05 MST 2006" 91 | {in: "Mon Jan 2 15:04:05 MST 2006", out: "2006-01-02 15:04:05 +0000 UTC", zname: "MST"}, 92 | {in: "Thu May 8 17:57:51 MST 2009", out: "2009-05-08 17:57:51 +0000 UTC", zname: "MST"}, 93 | {in: "Thu May 8 17:57:51 PST 2009", out: "2009-05-08 17:57:51 +0000 UTC", zname: "PST"}, 94 | {in: "Thu May 08 17:57:51 PST 2009", out: "2009-05-08 17:57:51 +0000 UTC", zname: "PST"}, 95 | {in: "Thu May 08 17:57:51 CEST 2009", out: "2009-05-08 17:57:51 +0000 UTC", zname: "CEST"}, 96 | {in: "Thu May 08 17:57:51 CEST 2009", out: "2009-05-08 15:57:51 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 97 | {in: "Thu May 08 05:05:07 PST 2009", out: "2009-05-08 05:05:07 +0000 UTC", zname: "PST"}, 98 | {in: "Thu May 08 5:5:7 PST 2009", out: "2009-05-08 05:05:07 +0000 UTC", zname: "PST"}, 99 | {in: "Thursday May 08 05:05:07 PST 2009", out: "2009-05-08 05:05:07 +0000 UTC", zname: "PST"}, 100 | // Day Month dd time 101 | {in: "Mon Aug 10 15:44:11 UTC+0000 2015", out: "2015-08-10 15:44:11 +0000 UTC", zname: "UTC"}, 102 | {in: "Mon Aug 10 15:44:11 PST-0700 2015", out: "2015-08-10 22:44:11 +0000 UTC", zname: "PST"}, 103 | {in: "Mon Aug 10 15:44:11 CEST+0200 2015", out: "2015-08-10 13:44:11 +0000 UTC", zname: "CEST"}, 104 | {in: "Mon Aug 1 15:44:11 CEST+0200 2015", out: "2015-08-01 13:44:11 +0000 UTC", zname: "CEST"}, 105 | {in: "Mon Aug 1 5:44:11 CEST+0200 2015", out: "2015-08-01 03:44:11 +0000 UTC", zname: "CEST"}, 106 | // ?? 107 | {in: "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", out: "2015-07-03 17:04:07 +0000 UTC"}, 108 | {in: "Fri Jul 03 2015 18:04:07 GMT+01:00 (GMT Daylight Time)", out: "2015-07-03 17:04:07 +0000 UTC"}, 109 | {in: "Fri Jul 3 2015 06:04:07 GMT+0100 (GMT Daylight Time)", out: "2015-07-03 05:04:07 +0000 UTC"}, 110 | {in: "Fri Jul 03 2015 18:04:07 UTC+0100 (GMT Daylight Time)", out: "2015-07-03 17:04:07 +0000 UTC"}, 111 | {in: "Fri Jul 3 2015 06:04:07 UTC+0100 (GMT Daylight Time)", out: "2015-07-03 05:04:07 +0000 UTC"}, 112 | {in: "Fri Jul 3 2015 06:04:07 PST-0700 (Pacific Daylight Time)", out: "2015-07-03 13:04:07 +0000 UTC", zname: "PST"}, 113 | {in: "Fri Jul 3 2015 06:04:07 PST-07:00 (Pacific Daylight Time)", out: "2015-07-03 13:04:07 +0000 UTC", zname: "PST"}, 114 | {in: "Fri Jul 3 2015 06:04:07 CEST-0700 (Central European Summer Time)", out: "2015-07-03 13:04:07 +0000 UTC", zname: "CEST"}, 115 | {in: "Fri Jul 03 2015 18:04:07 GMT (GMT Daylight Time)", out: "2015-07-03 18:04:07 +0000 UTC", zname: "GMT"}, 116 | {in: "Fri Jul 3 2015 06:04:07 +0100 (GMT Daylight Time)", out: "2015-07-03 05:04:07 +0000 UTC"}, 117 | {in: "Fri Jul 03 2015 18:04:07 UTC (GMT Daylight Time)", out: "2015-07-03 18:04:07 +0000 UTC"}, 118 | {in: "Fri Jul 3 2015 06:04:07 +01:00 (GMT Daylight Time)", out: "2015-07-03 05:04:07 +0000 UTC"}, 119 | {in: "Fri Jul 3 2015 06:04:07 PST (Pacific Daylight Time)", out: "2015-07-03 06:04:07 +0000 UTC", zname: "PST"}, 120 | {in: "Fri Jul 3 2015 06:04:07 -07:00 (Pacific Daylight Time)", out: "2015-07-03 13:04:07 +0000 UTC"}, 121 | {in: "Fri Jul 3 2015", out: "2015-07-03 00:00:00 +0000 UTC"}, 122 | {in: "Fri Jul 3 2015 11:15:26pm", out: "2015-07-03 23:15:26 +0000 UTC"}, 123 | // Month dd, yyyy at time 124 | {in: "January 17, 2012 at 18:17:16", out: "2012-01-17 18:17:16 +0000 UTC"}, 125 | {in: "February 17, 2012 at 18:17:16", out: "2012-02-17 18:17:16 +0000 UTC"}, 126 | {in: "march 17, 2012 at 18:17:16", out: "2012-03-17 18:17:16 +0000 UTC"}, 127 | {in: "APRIL 17, 2012 at 18:17:16", out: "2012-04-17 18:17:16 +0000 UTC"}, 128 | {in: "May 17, 2012 at 18:17:16", out: "2012-05-17 18:17:16 +0000 UTC"}, 129 | {in: "June 17, 2012 at 18:17:16", out: "2012-06-17 18:17:16 +0000 UTC"}, 130 | {in: "July 17, 2012 at 18:17:16", out: "2012-07-17 18:17:16 +0000 UTC"}, 131 | {in: "august 17, 2012 at 18:17:16", out: "2012-08-17 18:17:16 +0000 UTC"}, 132 | {in: "September 17, 2012 at 18:17:16", out: "2012-09-17 18:17:16 +0000 UTC"}, 133 | {in: "OCTober 17, 2012 at 18:17:16", out: "2012-10-17 18:17:16 +0000 UTC"}, 134 | {in: "noVEMBER 17, 2012 at 18:17:16", out: "2012-11-17 18:17:16 +0000 UTC"}, 135 | {in: "December 17, 2012 at 18:17:16", out: "2012-12-17 18:17:16 +0000 UTC"}, 136 | {in: "September 17 2012 at 5:00pm UTC-05", out: "2012-09-17 22:00:00 +0000 UTC", zname: ""}, // empty zone name, special case of UTC+NNNN 137 | {in: "September 17, 2012 at 5:00pm UTC-05", out: "2012-09-17 22:00:00 +0000 UTC", zname: ""}, // empty zone name, special case of UTC+NNNN 138 | {in: "September 17, 2012 at 10:09am PST-08", out: "2012-09-17 18:09:00 +0000 UTC", zname: "PST"}, 139 | {in: "September 17, 2012 at 10:09am CEST+02", out: "2012-09-17 08:09:00 +0000 UTC", zname: "CEST"}, 140 | {in: "September 17, 2012, 10:10:09", out: "2012-09-17 10:10:09 +0000 UTC"}, 141 | {in: "May 17 2012 at 10:09am PST-08", out: "2012-05-17 18:09:00 +0000 UTC", zname: "PST"}, 142 | {in: "May 17, 2012 at 10:09am PST-08", out: "2012-05-17 18:09:00 +0000 UTC", zname: "PST"}, 143 | {in: "May 17, 2012 AT 10:09am PST-08", out: "2012-05-17 18:09:00 +0000 UTC", zname: "PST"}, 144 | {in: "May 17, 2012 AT 10:09am CEST+02", out: "2012-05-17 08:09:00 +0000 UTC", zname: "CEST"}, 145 | // Month dd, yyyy time 146 | {in: "September 17, 2012 5:00pm UTC-05", out: "2012-09-17 22:00:00 +0000 UTC", zname: ""}, 147 | {in: "September 17, 2012 10:09am PST-08", out: "2012-09-17 18:09:00 +0000 UTC", zname: "PST"}, 148 | {in: "September 17, 2012 10:09am CEST+02", out: "2012-09-17 08:09:00 +0000 UTC", zname: "CEST"}, 149 | {in: "September 17, 2012 09:01:00", out: "2012-09-17 09:01:00 +0000 UTC"}, 150 | // Month dd yyyy time 151 | {in: "September 17 2012 5:00pm UTC-05", out: "2012-09-17 22:00:00 +0000 UTC", zname: ""}, 152 | {in: "September 17 2012 5:00pm UTC-0500", out: "2012-09-17 22:00:00 +0000 UTC", zname: ""}, 153 | {in: "September 17 2012 10:09am PST-08", out: "2012-09-17 18:09:00 +0000 UTC", zname: "PST"}, 154 | {in: "September 17 2012 10:09am CEST+02", out: "2012-09-17 08:09:00 +0000 UTC", zname: "CEST"}, 155 | {in: "September 17 2012 5:00PM UTC-05", out: "2012-09-17 22:00:00 +0000 UTC", zname: ""}, 156 | {in: "September 17 2012 10:09AM PST-08", out: "2012-09-17 18:09:00 +0000 UTC", zname: "PST"}, 157 | {in: "September 17 2012 10:09AM CEST+02", out: "2012-09-17 08:09:00 +0000 UTC", zname: "CEST"}, 158 | {in: "September 17 2012 09:01:00", out: "2012-09-17 09:01:00 +0000 UTC"}, 159 | {in: "May 17, 2012 10:10:09", out: "2012-05-17 10:10:09 +0000 UTC"}, 160 | {in: "July 30 2022 08:33:53 AM PST", out: "2022-07-30 08:33:53 +0000 UTC", zname: "PST"}, 161 | {in: "July 30 2022 08:33:53 AM CEST", out: "2022-07-30 08:33:53 +0000 UTC", zname: "CEST"}, 162 | {in: "July 30 2022 08:33:53 PM PST", out: "2022-07-30 20:33:53 +0000 UTC", zname: "PST"}, 163 | {in: "July 30 2022 08:33:53 PM CEST", out: "2022-07-30 20:33:53 +0000 UTC", zname: "CEST"}, 164 | // Month dd, yyyy 165 | {in: "September 17, 2012", out: "2012-09-17 00:00:00 +0000 UTC"}, 166 | {in: "May 7, 2012", out: "2012-05-07 00:00:00 +0000 UTC"}, 167 | {in: "June 7, 2012", out: "2012-06-07 00:00:00 +0000 UTC"}, 168 | {in: "June 7 2012", out: "2012-06-07 00:00:00 +0000 UTC"}, 169 | // Month dd[th,nd,st,rd] yyyy 170 | {in: "September 17th, 2012", out: "2012-09-17 00:00:00 +0000 UTC"}, 171 | {in: "September 17th 2012", out: "2012-09-17 00:00:00 +0000 UTC"}, 172 | {in: "September 7th, 2012", out: "2012-09-07 00:00:00 +0000 UTC"}, 173 | {in: "September 7th 2012", out: "2012-09-07 00:00:00 +0000 UTC"}, 174 | {in: "September 7tH 2012", out: "2012-09-07 00:00:00 +0000 UTC"}, 175 | {in: "May 1st 2012", out: "2012-05-01 00:00:00 +0000 UTC"}, 176 | {in: "May 1st, 2012", out: "2012-05-01 00:00:00 +0000 UTC"}, 177 | {in: "May 21st 2012", out: "2012-05-21 00:00:00 +0000 UTC"}, 178 | {in: "May 21st, 2012", out: "2012-05-21 00:00:00 +0000 UTC"}, 179 | {in: "May 23rd 2012", out: "2012-05-23 00:00:00 +0000 UTC"}, 180 | {in: "May 23rd, 2012", out: "2012-05-23 00:00:00 +0000 UTC"}, 181 | {in: "June 2nd, 2012", out: "2012-06-02 00:00:00 +0000 UTC"}, 182 | {in: "June 2nd 2012", out: "2012-06-02 00:00:00 +0000 UTC"}, 183 | {in: "June 22nd, 2012", out: "2012-06-22 00:00:00 +0000 UTC"}, 184 | {in: "June 22nd 2012", out: "2012-06-22 00:00:00 +0000 UTC"}, 185 | {in: "September 17th, 2012 11:15:26pm", out: "2012-09-17 23:15:26 +0000 UTC"}, 186 | {in: "September 17th 2012 11:15:26pm", out: "2012-09-17 23:15:26 +0000 UTC"}, 187 | {in: "September 7th, 2012 11:15:26pm", out: "2012-09-07 23:15:26 +0000 UTC"}, 188 | {in: "September 7th 2012 11:15:26pm", out: "2012-09-07 23:15:26 +0000 UTC"}, 189 | {in: "September 7tH 2012 11:15:26pm", out: "2012-09-07 23:15:26 +0000 UTC"}, 190 | {in: "May 1st 2012 11:15:26pm", out: "2012-05-01 23:15:26 +0000 UTC"}, 191 | {in: "May 1st, 2012 11:15:26pm", out: "2012-05-01 23:15:26 +0000 UTC"}, 192 | {in: "May 21st 2012 11:15:26pm", out: "2012-05-21 23:15:26 +0000 UTC"}, 193 | {in: "May 21st, 2012 11:15:26pm", out: "2012-05-21 23:15:26 +0000 UTC"}, 194 | {in: "May 23rd 2012 11:15:26pm", out: "2012-05-23 23:15:26 +0000 UTC"}, 195 | {in: "May 23rd, 2012 11:15:26pm", out: "2012-05-23 23:15:26 +0000 UTC"}, 196 | {in: "June 2nd, 2012 11:15:26pm", out: "2012-06-02 23:15:26 +0000 UTC"}, 197 | {in: "June 2nd 2012 11:15:26pm", out: "2012-06-02 23:15:26 +0000 UTC"}, 198 | {in: "June 22nd, 2012 11:15:26pm", out: "2012-06-22 23:15:26 +0000 UTC"}, 199 | {in: "June 22nd 2012 11:15:26pm", out: "2012-06-22 23:15:26 +0000 UTC"}, 200 | // Incorporate PR https://github.com/araddon/dateparse/pull/128 to fix https://github.com/araddon/dateparse/issues/127 201 | // dd[th,nd,st,rd] Month yyyy 202 | {in: "1st September 2012", out: "2012-09-01 00:00:00 +0000 UTC"}, 203 | {in: "2nd September 2012", out: "2012-09-02 00:00:00 +0000 UTC"}, 204 | {in: "3rd September 2012", out: "2012-09-03 00:00:00 +0000 UTC"}, 205 | {in: "4th Sep 2012", out: "2012-09-04 00:00:00 +0000 UTC"}, 206 | {in: "2nd January 2018", out: "2018-01-02 00:00:00 +0000 UTC"}, 207 | {in: "3rd Feb 2018 13:58:24", out: "2018-02-03 13:58:24 +0000 UTC"}, 208 | {in: "1st February 2018 13:58:24", out: "2018-02-01 13:58:24 +0000 UTC"}, 209 | // RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST" 210 | {in: "Fri, 03 Jul 2015 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 211 | {in: "Fri, 03 Jul 2015 08:08:08 CET", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CET"}, 212 | {in: "Fri, 03 Jul 2015 08:08:08 PST", out: "2015-07-03 16:08:08 +0000 UTC", loc: "America/Los_Angeles", zname: "PDT"}, 213 | {in: "Fri, 03 Jul 2015 08:08:08 PST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "PST"}, 214 | {in: "Fri, 03 Jul 2015 08:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 215 | {in: "Fri, 3 Jul 2015 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 216 | {in: "Fri, 3 Jul 2015 08:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 217 | {in: "Fri, 03 Jul 2015 8:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 218 | {in: "Fri, 03 Jul 2015 8:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 219 | {in: "Fri, 03 Jul 2015 8:8:8 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 220 | {in: "Fri, 03 Jul 2015 8:8:8 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 221 | // ? 222 | {in: "Thu, 03 Jul 2017 08:08:04 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, 223 | {in: "Thu, 03 Jul 2017 08:08:04 -0100", out: "2017-07-03 09:08:04 +0000 UTC"}, 224 | {in: "Thu, 3 Jul 2017 08:08:04 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, 225 | {in: "Thu, 03 Jul 2017 8:08:04 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, 226 | {in: "Thu, 03 Jul 2017 8:8:4 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, 227 | // 228 | {in: "Tue, 11 Jul 2017 04:08:03 +0200 (CEST)", out: "2017-07-11 02:08:03 +0000 UTC", zname: "CEST"}, 229 | {in: "Tue, 5 Jul 2017 04:08:03 -0700 (MST)", out: "2017-07-05 11:08:03 +0000 UTC", zname: "MST"}, 230 | {in: "Tue, 11 Jul 2017 04:08:03 +0200 (CEST)", out: "2017-07-11 02:08:03 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 231 | {in: "Tue, 11 Jul 2017 04:08:03 (CEST)", out: "2017-07-11 04:08:03 +0000 UTC", zname: "CEST"}, 232 | {in: "Tue, 5 Jul 2017 04:08:03 (MST)", out: "2017-07-05 04:08:03 +0000 UTC", zname: "MST"}, 233 | // day, dd-Mon-yy hh:mm:zz TZ 234 | {in: "Fri, 03-Jul-15 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 235 | {in: "Fri, 03-Jul-15 08:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 236 | {in: "Fri, 03-Jul-15 08:08:08 PST", out: "2015-07-03 16:08:08 +0000 UTC", loc: "America/Los_Angeles", zname: "PDT"}, 237 | {in: "Fri, 03-Jul-2015", out: "2015-07-03 00:00:00 +0000 UTC"}, 238 | {in: "Fri, 03-Jul-2015 08:08:08 PST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "PST"}, 239 | {in: "Fri, 03-Jul-2015 08:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 240 | {in: "Fri, 3-Jul-15 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 241 | {in: "Fri, 3-Jul-15 08:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 242 | {in: "Fri, 03-Jul-15 8:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 243 | {in: "Fri, 03-Jul-15 8:08:08 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 244 | {in: "Fri, 03-Jul-15 8:8:8 MST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "MST"}, 245 | {in: "Fri, 03-Jul-15 8:8:8 CEST", out: "2015-07-03 08:08:08 +0000 UTC", zname: "CEST"}, 246 | // day, dd-Mon-yy hh:mm:zz TZ (text) https://github.com/araddon/dateparse/issues/116 247 | {in: "Sun, 3 Jan 2021 00:12:23 +0800 (GMT+08:00)", out: "2021-01-02 16:12:23 +0000 UTC"}, 248 | {in: "Sun, 3 Jan 2021 00:12:23 +0800 (UTC+08:00)", out: "2021-01-02 16:12:23 +0000 UTC"}, 249 | // RFC850 = "Monday, 02-Jan-06 15:04:05 MST" 250 | {in: "Wednesday, 07-May-09 08:00:43 MST", out: "2009-05-07 08:00:43 +0000 UTC", zname: "MST"}, 251 | {in: "Wednesday, 07-May-09 08:00:43 CEST", out: "2009-05-07 08:00:43 +0000 UTC", zname: "CEST"}, 252 | {in: "Wednesday, 28-Feb-18 09:01:00 MST", out: "2018-02-28 09:01:00 +0000 UTC", zname: "MST"}, 253 | {in: "Wednesday, 28-Feb-18 09:01:00 MST", out: "2018-02-28 16:01:00 +0000 UTC", loc: "America/Denver", zname: "MST"}, 254 | {in: "Wednesday, 28-Feb-18 09:01:00 CEST", out: "2018-02-28 09:01:00 +0000 UTC", zname: "CEST"}, 255 | // with offset then with variations on non-zero filled stuff 256 | {in: "Monday, 02 Jan 2006 15:04:05 +0100", out: "2006-01-02 14:04:05 +0000 UTC"}, 257 | {in: "Wednesday, 28 Feb 2018 09:01:00 -0300", out: "2018-02-28 12:01:00 +0000 UTC"}, 258 | {in: "Wednesday, 2 Feb 2018 09:01:00 -0300", out: "2018-02-02 12:01:00 +0000 UTC"}, 259 | {in: "Wednesday, 2 Feb 2018 9:01:00 -0300", out: "2018-02-02 12:01:00 +0000 UTC"}, 260 | {in: "Wednesday, 2 Feb 2018 09:1:00 -0300", out: "2018-02-02 12:01:00 +0000 UTC"}, 261 | // dd mon yyyy 12 Feb 2006, 19:17:08 262 | {in: "07 Feb 2004, 09:07", out: "2004-02-07 09:07:00 +0000 UTC"}, 263 | {in: "07 Feb 2004, 09:07:07", out: "2004-02-07 09:07:07 +0000 UTC"}, 264 | {in: "7 Feb 2004, 09:07:07", out: "2004-02-07 09:07:07 +0000 UTC"}, 265 | {in: "07 Feb 2004, 9:7:7", out: "2004-02-07 09:07:07 +0000 UTC"}, 266 | // dd Mon yyyy hh:mm:ss 267 | {in: "07 Feb 2004 09:07:08", out: "2004-02-07 09:07:08 +0000 UTC"}, 268 | {in: "07 Feb 2004 09:07", out: "2004-02-07 09:07:00 +0000 UTC"}, 269 | {in: "7 Feb 2004 9:7:8", out: "2004-02-07 09:07:08 +0000 UTC"}, 270 | {in: "07 Feb 2004 09:07:08.123", out: "2004-02-07 09:07:08.123 +0000 UTC"}, 271 | // dd-mon-yyyy 12 Feb 2006, 19:17:08 GMT 272 | {in: "07 Feb 2004, 09:07:07 GMT", out: "2004-02-07 09:07:07 +0000 UTC", zname: "GMT"}, 273 | {in: "07 Feb 2004, 09:07:07 CEST", out: "2004-02-07 09:07:07 +0000 UTC", zname: "CEST"}, 274 | // dd-mon-yyyy 12 Feb 2006, 19:17:08 +0100 275 | {in: "07 Feb 2004, 09:07:07 +0100", out: "2004-02-07 08:07:07 +0000 UTC"}, 276 | // dd-mon-yyyy 12-Feb-2006 19:17:08 277 | {in: "07-Feb-2004 09:07:07 +0100", out: "2004-02-07 08:07:07 +0000 UTC"}, 278 | // dd-mon-yy 12-Feb-2006 19:17:08 279 | {in: "07-Feb-04 09:07:07 +0100", out: "2004-02-07 08:07:07 +0000 UTC"}, 280 | // yyyy-mon-dd 2013-Feb-03 281 | {in: "2013-Feb-03", out: "2013-02-03 00:00:00 +0000 UTC"}, 282 | {in: "2013-Feb-03 09:07:08pm", out: "2013-02-03 21:07:08 +0000 UTC"}, 283 | {in: "2013-February-03", out: "2013-02-03 00:00:00 +0000 UTC"}, 284 | {in: "2013-February-03 09:07:08.123", out: "2013-02-03 09:07:08.123 +0000 UTC"}, 285 | // 03 February 2013 286 | {in: "13 Feb 2013", out: "2013-02-13 00:00:00 +0000 UTC"}, 287 | {in: "03 February 2013", out: "2013-02-03 00:00:00 +0000 UTC"}, 288 | {in: "03 February 2013 09:07:08pm", out: "2013-02-03 21:07:08 +0000 UTC"}, 289 | {in: "3 February 2013", out: "2013-02-03 00:00:00 +0000 UTC"}, 290 | {in: "3 February 2013 09:07:08pm", out: "2013-02-03 21:07:08 +0000 UTC"}, 291 | // Chinese 2014年04月18日 - https://github.com/araddon/dateparse/pull/132 292 | {in: "2014年04月08日", out: "2014-04-08 00:00:00 +0000 UTC"}, 293 | {in: "2014年4月8日", out: "2014-04-08 00:00:00 +0000 UTC"}, 294 | {in: "2014年04月08日 19:17:22", out: "2014-04-08 19:17:22 +0000 UTC"}, 295 | {in: "2014年04月08日 19:17:22 MDT", out: "2014-04-08 19:17:22 +0000 UTC", zname: "MDT"}, 296 | {in: "2014年04月08日 19:17:22 -0700", out: "2014-04-09 02:17:22 +0000 UTC"}, 297 | {in: "2014年4月8日 19:17:22", out: "2014-04-08 19:17:22 +0000 UTC"}, 298 | {in: "2014年4月8日 19:17:22 MDT", out: "2014-04-08 19:17:22 +0000 UTC", zname: "MDT"}, 299 | {in: "2014年4月8日 19:17:22 MDT-0700", out: "2014-04-09 02:17:22 +0000 UTC", zname: "MDT"}, 300 | {in: "2014年4月8日 10:17pm", out: "2014-04-08 22:17:00 +0000 UTC"}, 301 | // TODO: support Chinese AM (上午) and PM (下午) indicators 302 | // mm/dd/yyyy 303 | {in: "03/31/2014", out: "2014-03-31 00:00:00 +0000 UTC"}, 304 | {in: "3/31/2014", out: "2014-03-31 00:00:00 +0000 UTC"}, 305 | {in: "3/5/2014", out: "2014-03-05 00:00:00 +0000 UTC"}, 306 | // mm/dd/yy 307 | {in: "08/08/71", out: "1971-08-08 00:00:00 +0000 UTC"}, 308 | {in: "8/8/71", out: "1971-08-08 00:00:00 +0000 UTC"}, 309 | // mm/dd/yy hh:mm:ss 310 | {in: "04/02/2014 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 311 | {in: "4/2/2014 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 312 | {in: "04/02/2014 4:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 313 | {in: "04/02/2014 4:8:9", out: "2014-04-02 04:08:09 +0000 UTC"}, 314 | {in: "04/02/2014 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, 315 | {in: "04/02/2014 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, 316 | {in: "04/02/2014 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 317 | {in: "04/02/2014 04:08:09.12312", out: "2014-04-02 04:08:09.12312 +0000 UTC"}, 318 | {in: "04/02/2014 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, 319 | // mm:dd:yy hh:mm:ss 320 | {in: "04:02:2014 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 321 | {in: "4:2:2014 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 322 | {in: "04:02:2014 4:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 323 | {in: "04:02:2014 4:8:9", out: "2014-04-02 04:08:09 +0000 UTC"}, 324 | {in: "04:02:2014 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, 325 | {in: "04:02:2014 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, 326 | {in: "04:02:2014 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 327 | {in: "04:02:2014 04:08:09.12312", out: "2014-04-02 04:08:09.12312 +0000 UTC"}, 328 | {in: "04:02:2014 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, 329 | {in: "04:01:2014 04:08:09", out: "2014-01-04 04:08:09 +0000 UTC", preferDayFirst: true}, 330 | // mm/dd/yy hh:mm:ss AM 331 | {in: "04/02/2014 04:08:09am", out: "2014-04-02 04:08:09 +0000 UTC"}, 332 | {in: "04/02/2014 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, 333 | {in: "04/02/2014 04:08:09AM PST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "PST"}, 334 | {in: "04/02/2014 04:08:09 AM PST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "PST"}, 335 | {in: "04/02/2014 04:08:09 AM (PST)", out: "2014-04-02 04:08:09 +0000 UTC", zname: "PST"}, 336 | {in: "04/02/2014 04:08:09AM CEST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "CEST"}, 337 | {in: "04/02/2014 04:08:09 AM CEST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "CEST"}, 338 | {in: "04/02/2014 04:08:09 AM (CEST)", out: "2014-04-02 04:08:09 +0000 UTC", zname: "CEST"}, 339 | {in: "04/02/2014 04:08:09pm", out: "2014-04-02 16:08:09 +0000 UTC"}, 340 | {in: "04/02/2014 04:08:09 PM", out: "2014-04-02 16:08:09 +0000 UTC"}, 341 | {in: "04/02/2014 04:08:09PM PST", out: "2014-04-02 16:08:09 +0000 UTC", zname: "PST"}, 342 | {in: "04/02/2014 04:08:09 PM PST", out: "2014-04-02 16:08:09 +0000 UTC", zname: "PST"}, 343 | {in: "04/02/2014 04:08:09 PM (PST)", out: "2014-04-02 16:08:09 +0000 UTC", zname: "PST"}, 344 | {in: "04/02/2014 04:08:09pm CEST", out: "2014-04-02 16:08:09 +0000 UTC", zname: "CEST"}, 345 | {in: "04/02/2014 04:08:09 PM CEST", out: "2014-04-02 16:08:09 +0000 UTC", zname: "CEST"}, 346 | {in: "04/02/2014 04:08:09 PM (CEST)", out: "2014-04-02 16:08:09 +0000 UTC", zname: "CEST"}, 347 | {in: "04/02/2014 04:08am", out: "2014-04-02 04:08:00 +0000 UTC"}, 348 | {in: "04/02/2014 04:08 AM", out: "2014-04-02 04:08:00 +0000 UTC"}, 349 | {in: "04/02/2014 04:08pm", out: "2014-04-02 16:08:00 +0000 UTC"}, 350 | {in: "04/02/2014 04:08 PM", out: "2014-04-02 16:08:00 +0000 UTC"}, 351 | {in: "04/02/2014 4:8AM", out: "2014-04-02 04:08:00 +0000 UTC"}, 352 | {in: "04/02/2014 4:8 AM", out: "2014-04-02 04:08:00 +0000 UTC"}, 353 | {in: "04/02/2014 4:8pm", out: "2014-04-02 16:08:00 +0000 UTC"}, 354 | {in: "04/02/2014 4:8 PM", out: "2014-04-02 16:08:00 +0000 UTC"}, 355 | {in: "04/02/2014 04:08:09.123am", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 356 | {in: "04/02/2014 04:08:09.123 AM", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 357 | {in: "04/02/2014 04:08:09.123PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, 358 | {in: "04/02/2014 04:08:09.123 PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, 359 | {in: "04/02/2014 04:08:09pm-0700", out: "2014-04-02 23:08:09 +0000 UTC"}, 360 | {in: "04/02/2014 04:08:09PM-0700 PST", out: "2014-04-02 23:08:09 +0000 UTC", zname: "PST"}, 361 | {in: "04/02/2014 04:08:09pm-0700 PST (Pacific Standard Time)", out: "2014-04-02 23:08:09 +0000 UTC", zname: "PST"}, 362 | {in: "04/02/2014 04:08:09pm-0700 (Pacific Standard Time)", out: "2014-04-02 23:08:09 +0000 UTC"}, 363 | {in: "04/02/2014 04:08:09am+02:00", out: "2014-04-02 02:08:09 +0000 UTC"}, 364 | {in: "04/02/2014 04:08:09AM+02:00 CET", out: "2014-04-02 02:08:09 +0000 UTC", zname: "CET"}, 365 | {in: "04/02/2014 04:08:09am+02:00 CET (Central European Time)", out: "2014-04-02 02:08:09 +0000 UTC", zname: "CET"}, 366 | {in: "04/02/2014 04:08:09am+02:00 (Central European Time)", out: "2014-04-02 02:08:09 +0000 UTC"}, 367 | // yyyy/mm/dd 368 | {in: "2014/04/02", out: "2014-04-02 00:00:00 +0000 UTC"}, 369 | {in: "2014/03/31", out: "2014-03-31 00:00:00 +0000 UTC"}, 370 | {in: "2014/4/2", out: "2014-04-02 00:00:00 +0000 UTC"}, 371 | // yyyy/mm/dd hh:mm:ss AM 372 | {in: "2014/04/02 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, 373 | {in: "2014/03/31 04:08", out: "2014-03-31 04:08:00 +0000 UTC"}, 374 | {in: "2014/4/2 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, 375 | {in: "2014/04/02 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, 376 | {in: "2014/04/02 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 377 | {in: "2014/03/31 04:08:09", out: "2014-03-31 04:08:09 +0000 UTC"}, 378 | {in: "2014/4/2 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 379 | {in: "2014/04/02 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 380 | {in: "2014/04/02 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, 381 | {in: "2014/04/02 04:08:09am", out: "2014-04-02 04:08:09 +0000 UTC"}, 382 | {in: "2014/04/02 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, 383 | {in: "2014/03/31 04:08:09am", out: "2014-03-31 04:08:09 +0000 UTC"}, 384 | {in: "2014/03/31 04:08:09 AM", out: "2014-03-31 04:08:09 +0000 UTC"}, 385 | {in: "2014/4/2 04:08:09AM", out: "2014-04-02 04:08:09 +0000 UTC"}, 386 | {in: "2014/4/2 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, 387 | {in: "2014/04/02 04:08:09.123am", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 388 | {in: "2014/04/02 04:08:09.123 AM", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 389 | {in: "2014/04/02 04:08:09.123am PST", out: "2014-04-02 04:08:09.123 +0000 UTC", zname: "PST"}, 390 | {in: "2014/04/02 04:08:09.123 AM PST", out: "2014-04-02 04:08:09.123 +0000 UTC", zname: "PST"}, 391 | {in: "2014/04/02 04:08:09.123AM CEST", out: "2014-04-02 04:08:09.123 +0000 UTC", zname: "CEST"}, 392 | {in: "2014/04/02 04:08:09.123 AM CEST", out: "2014-04-02 04:08:09.123 +0000 UTC", zname: "CEST"}, 393 | {in: "2014/04/02 04:08:09.123pm", out: "2014-04-02 16:08:09.123 +0000 UTC"}, 394 | {in: "2014/04/02 04:08:09.123 PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, 395 | {in: "2014/04/02 04:08:09.123PM PST", out: "2014-04-02 16:08:09.123 +0000 UTC", zname: "PST"}, 396 | {in: "2014/04/02 04:08:09.123 PM PST", out: "2014-04-02 16:08:09.123 +0000 UTC", zname: "PST"}, 397 | {in: "2014/04/02 04:08:09.123PM CEST", out: "2014-04-02 16:08:09.123 +0000 UTC", zname: "CEST"}, 398 | {in: "2014/04/02 04:08:09.123 PM CEST", out: "2014-04-02 16:08:09.123 +0000 UTC", zname: "CEST"}, 399 | // dd/mon/yyyy:hh:mm:ss tz nginx-log? https://github.com/araddon/dateparse/issues/118 400 | // 112.195.209.90 - - [20/Feb/2018:12:12:14 +0800] "GET / HTTP/1.1" 200 190 "-" "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36" "-" 401 | {in: "06/May/2008:08:11:17 -0700", out: "2008-05-06 15:11:17 +0000 UTC"}, 402 | {in: "30/May/2008:08:11:17 -0700", out: "2008-05-30 15:11:17 +0000 UTC"}, 403 | {in: "30/October/2008:08:11:17 -0700", out: "2008-10-30 15:11:17 +0000 UTC"}, 404 | // dd/mon/yyyy hh:mm:ss tz 405 | {in: "06/May/2008", out: "2008-05-06 00:00:00 +0000 UTC"}, 406 | {in: "06/May/2008 08:11:17 -0700", out: "2008-05-06 15:11:17 +0000 UTC"}, 407 | {in: "30/May/2008 08:11:17 -0700", out: "2008-05-30 15:11:17 +0000 UTC"}, 408 | {in: "30/September/2008 08:11:17 -0700", out: "2008-09-30 15:11:17 +0000 UTC"}, 409 | // mon/dd/yyyy 410 | {in: "Oct/ 7/1970", out: "1970-10-07 00:00:00 +0000 UTC"}, 411 | {in: "Oct/31/1970", out: "1970-10-31 00:00:00 +0000 UTC"}, 412 | {in: "Oct/03/1970", out: "1970-10-03 00:00:00 +0000 UTC"}, 413 | {in: "Oct/03/1970 22:33:44", out: "1970-10-03 22:33:44 +0000 UTC"}, 414 | {in: "February/ 7/1970", out: "1970-02-07 00:00:00 +0000 UTC"}, 415 | {in: "February/27/1970", out: "1970-02-27 00:00:00 +0000 UTC"}, 416 | {in: "February/03/1970", out: "1970-02-03 00:00:00 +0000 UTC"}, 417 | {in: "February/03/1970 22:33:44.555", out: "1970-02-03 22:33:44.555 +0000 UTC"}, 418 | {in: "February/03/1970 11:33:44.555 PM PST", out: "1970-02-03 23:33:44.555 +0000 UTC", zname: "PST"}, 419 | // yyyy-mm-dd 420 | {in: "2014-04-02", out: "2014-04-02 00:00:00 +0000 UTC"}, 421 | {in: "2014-03-31", out: "2014-03-31 00:00:00 +0000 UTC"}, 422 | {in: "2014-4-2", out: "2014-04-02 00:00:00 +0000 UTC"}, 423 | // yyyy-mm-dd-07:00 424 | {in: "2020-07-20+08:00", out: "2020-07-19 16:00:00 +0000 UTC"}, 425 | {in: "2020-07-20+0800", out: "2020-07-19 16:00:00 +0000 UTC"}, 426 | // dd-mmm-yy (alpha month) 427 | {in: "28-Feb-02", out: "2002-02-28 00:00:00 +0000 UTC"}, 428 | {in: "15-Jan-18", out: "2018-01-15 00:00:00 +0000 UTC"}, 429 | {in: "15-Jan-2017", out: "2017-01-15 00:00:00 +0000 UTC"}, 430 | {in: "28-Feb-02 15:16:17", out: "2002-02-28 15:16:17 +0000 UTC"}, 431 | {in: "15-Jan-18 15:16:17", out: "2018-01-15 15:16:17 +0000 UTC"}, 432 | {in: "15-September-2017 15:16:17", out: "2017-09-15 15:16:17 +0000 UTC"}, 433 | // dd-mm-yy (digit month - potentially ambiguous) - https://github.com/araddon/dateparse/issues/139 434 | {in: "28-02-02", out: "2002-02-28 00:00:00 +0000 UTC"}, 435 | {in: "15-01-18", out: "2018-01-15 00:00:00 +0000 UTC"}, 436 | {in: "15-01-2017", out: "2017-01-15 00:00:00 +0000 UTC"}, 437 | {in: "28-02-02 15:16:17", out: "2002-02-28 15:16:17 +0000 UTC"}, 438 | {in: "15-01-18 15:16:17", out: "2018-01-15 15:16:17 +0000 UTC"}, 439 | {in: "15-01-2017 15:16:17", out: "2017-01-15 15:16:17 +0000 UTC"}, 440 | // yyyy-mm 441 | {in: "2014-04", out: "2014-04-01 00:00:00 +0000 UTC"}, 442 | // yyyy-mm-dd hh:mm:ss AM 443 | {in: "2014-04-02 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, 444 | {in: "2014-03-31 04:08", out: "2014-03-31 04:08:00 +0000 UTC"}, 445 | {in: "2014-4-2 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, 446 | {in: "2014-04-02 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, 447 | {in: "2014-04-02 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 448 | {in: "2014-03-31 04:08:09", out: "2014-03-31 04:08:09 +0000 UTC"}, 449 | {in: "2014-4-2 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 450 | {in: "2014-04-02 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 451 | {in: "2014-04-02 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, 452 | {in: "2014-04-02 04:08:09.12312312", out: "2014-04-02 04:08:09.12312312 +0000 UTC"}, 453 | {in: "2014-04-02 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, 454 | {in: "2014-04-02 04:08:09 AM PST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "PST"}, 455 | {in: "2014-04-02 04:08:09 AM CEST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "CEST"}, 456 | {in: "2014-03-31 04:08:09 AM", out: "2014-03-31 04:08:09 +0000 UTC"}, 457 | {in: "2014-03-31 04:08:09 AM PST", out: "2014-03-31 04:08:09 +0000 UTC", zname: "PST"}, 458 | {in: "2014-03-31 04:08:09 AM CEST", out: "2014-03-31 04:08:09 +0000 UTC", zname: "CEST"}, 459 | {in: "2014-04-26 05:24:37 PM", out: "2014-04-26 17:24:37 +0000 UTC"}, 460 | {in: "2014-04-26 05:24:37 PM PST", out: "2014-04-26 17:24:37 +0000 UTC", zname: "PST"}, 461 | {in: "2014-04-26 05:24:37 PM CEST", out: "2014-04-26 17:24:37 +0000 UTC", zname: "CEST"}, 462 | {in: "2014-4-2 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, 463 | {in: "2014-4-2 04:08:09 AM PST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "PST"}, 464 | {in: "2014-4-2 04:08:09 AM CEST", out: "2014-04-02 04:08:09 +0000 UTC", zname: "CEST"}, 465 | {in: "2014-04-02 04:08:09.123 AM", out: "2014-04-02 04:08:09.123 +0000 UTC"}, 466 | {in: "2014-04-02 04:08:09.123 AM PST", out: "2014-04-02 04:08:09.123 +0000 UTC", zname: "PST"}, 467 | {in: "2014-04-02 04:08:09.123 AM CEST", out: "2014-04-02 04:08:09.123 +0000 UTC", zname: "CEST"}, 468 | {in: "2014-04-02 04:08:09.123 PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, 469 | {in: "2014-04-02 04:08:09.123 PM PST", out: "2014-04-02 16:08:09.123 +0000 UTC", zname: "PST"}, 470 | {in: "2014-04-02 04:08:09.123 PM CEST", out: "2014-04-02 16:08:09.123 +0000 UTC", zname: "CEST"}, 471 | // https://github.com/araddon/dateparse/issues/150 472 | {in: "2023-01-04 12:01am", out: "2023-01-04 00:01:00 +0000 UTC"}, 473 | {in: "2023-01-04 12:01 AM", out: "2023-01-04 00:01:00 +0000 UTC"}, 474 | {in: "2023-01-04 12:01:59 AM", out: "2023-01-04 00:01:59 +0000 UTC"}, 475 | {in: "2023-01-04 12:01:59.765 AM", out: "2023-01-04 00:01:59.765 +0000 UTC"}, 476 | // https://github.com/araddon/dateparse/issues/157 477 | {in: "Thu Jan 28 2021", out: "2021-01-28 00:00:00 +0000 UTC"}, 478 | {in: "Thu Jan 28 2021 15:28:21 GMT+0000 (Coordinated Universal Time)", out: "2021-01-28 15:28:21 +0000 UTC"}, 479 | {in: "Thu Jan 28 2021 15:28:21 GMT+0100 (Coordinated Universal Time)", out: "2021-01-28 14:28:21 +0000 UTC"}, 480 | {in: "Thu Jan 28 2021 15:28:21 UTC+0000 (Coordinated Universal Time)", out: "2021-01-28 15:28:21 +0000 UTC"}, 481 | {in: "Thu Jan 28 2021 15:28:21 UTC+0100 (Coordinated Universal Time)", out: "2021-01-28 14:28:21 +0000 UTC"}, 482 | // https://github.com/araddon/dateparse/issues/130 483 | {in: "1985-04-12T23:20:50Z", out: "1985-04-12 23:20:50 +0000 UTC"}, 484 | {in: "1985-04-12T23:20:50.52Z", out: "1985-04-12 23:20:50.52 +0000 UTC"}, 485 | // https://github.com/araddon/dateparse/issues/123 486 | {in: "2017-04-03 22:32:14.322 CET", out: "2017-04-03 22:32:14.322 +0000 UTC", zname: "CET"}, 487 | {in: "2017-04-03 22:32:14 CET", out: "2017-04-03 22:32:14 +0000 UTC", zname: "CET"}, 488 | {in: "Mon Dec 26 16:22:08 2016", out: "2016-12-26 16:22:08 +0000 UTC"}, 489 | {in: "Mon Dec 26 16:15:55.103786 2016", out: "2016-12-26 16:15:55.103786 +0000 UTC"}, 490 | // https://github.com/araddon/dateparse/issues/109 491 | {in: "Sun, 07 Jun 2020 00:00:00 +0100", out: "2020-06-06 23:00:00 +0000 UTC"}, 492 | {in: "Sun, 07 Jun 2020", out: "2020-06-07 00:00:00 +0000 UTC"}, 493 | // https://github.com/araddon/dateparse/issues/100#issuecomment-1118868154 494 | {in: "1 Apr 2022 23:59", out: "2022-04-01 23:59:00 +0000 UTC"}, 495 | {in: "1 JANuary 2022 23:59", out: "2022-01-01 23:59:00 +0000 UTC"}, 496 | {in: "1 february 2022 23:59", out: "2022-02-01 23:59:00 +0000 UTC"}, 497 | {in: "1 marCH 2022 23:59", out: "2022-03-01 23:59:00 +0000 UTC"}, 498 | {in: "1 April 2022 23:59", out: "2022-04-01 23:59:00 +0000 UTC"}, 499 | {in: "1 May 2022 23:59", out: "2022-05-01 23:59:00 +0000 UTC"}, 500 | {in: "1 JuNe 2022 23:59", out: "2022-06-01 23:59:00 +0000 UTC"}, 501 | {in: "1 JULY 2022 23:59", out: "2022-07-01 23:59:00 +0000 UTC"}, 502 | {in: "1 august 2022 23:59", out: "2022-08-01 23:59:00 +0000 UTC"}, 503 | {in: "1 September 2022 23:59", out: "2022-09-01 23:59:00 +0000 UTC"}, 504 | {in: "1 October 2022 23:59", out: "2022-10-01 23:59:00 +0000 UTC"}, 505 | {in: "1 November 2022 23:59", out: "2022-11-01 23:59:00 +0000 UTC"}, 506 | {in: "1 December 2022 23:59", out: "2022-12-01 23:59:00 +0000 UTC"}, 507 | // https://github.com/araddon/dateparse/issues/149 508 | {in: "2018-09-30 21:09:13 PMDT", out: "2018-09-30 21:09:13 +0000 UTC", zname: "PMDT"}, 509 | {in: "2018-09-30 08:09:13 PM PMDT", out: "2018-09-30 20:09:13 +0000 UTC", zname: "PMDT"}, 510 | {in: "2018-09-30 08:09:13pm PMDT", out: "2018-09-30 20:09:13 +0000 UTC", zname: "PMDT"}, 511 | {in: "2018-09-30 21:09:13.123 PMDT", out: "2018-09-30 21:09:13.123 +0000 UTC", zname: "PMDT"}, 512 | {in: "2018-09-30 08:09:13.123 PM PMDT", out: "2018-09-30 20:09:13.123 +0000 UTC", zname: "PMDT"}, 513 | {in: "2018-09-30 08:09:13.123pm PMDT", out: "2018-09-30 20:09:13.123 +0000 UTC", zname: "PMDT"}, 514 | {in: "2018-09-30 21:09:13 AMT", out: "2018-09-30 21:09:13 +0000 UTC", zname: "AMT"}, 515 | {in: "2018-09-30 08:09:13 AM AMT", out: "2018-09-30 08:09:13 +0000 UTC", zname: "AMT"}, 516 | {in: "2018-09-30 08:09:13am AMT", out: "2018-09-30 08:09:13 +0000 UTC", zname: "AMT"}, 517 | {in: "2018-09-30 21:09:13.123 AMT", out: "2018-09-30 21:09:13.123 +0000 UTC", zname: "AMT"}, 518 | {in: "2018-09-30 08:09:13.123 am AMT", out: "2018-09-30 08:09:13.123 +0000 UTC", zname: "AMT"}, 519 | {in: "2018-09-30 08:09:13.123am AMT", out: "2018-09-30 08:09:13.123 +0000 UTC", zname: "AMT"}, 520 | /// yyyy mmm dd https://github.com/araddon/dateparse/issues/141 521 | {in: "2013 May 2", out: "2013-05-02 00:00:00 +0000 UTC"}, 522 | {in: "2013 May 02 11:37:55", out: "2013-05-02 11:37:55 +0000 UTC"}, 523 | {in: "2013 June 02 11:37:55", out: "2013-06-02 11:37:55 +0000 UTC"}, 524 | {in: "2013 December 02 11:37:55", out: "2013-12-02 11:37:55 +0000 UTC"}, 525 | // https://github.com/araddon/dateparse/issues/71 and https://github.com/araddon/dateparse/issues/72 526 | {in: "2017-12-31T16:00:00Z", out: "2017-12-31 16:00:00 +0000 UTC", loc: "America/Denver", zname: "UTC"}, 527 | {in: "Jul 9, 2012 at 5:02am (EST)", out: "2012-07-09 05:02:00 +0000 UTC", zname: "EST"}, 528 | {in: "Jul 9, 2012 at 5:02am (EST)", out: "2012-07-09 05:02:00 +0000 UTC", loc: "US/Pacific", zname: "EST"}, 529 | {in: "Jul 9, 2012 at 5:02am (EST)", out: "2012-07-09 10:02:00 +0000 UTC", loc: "America/New_York", zname: "EDT"}, 530 | // https://github.com/araddon/dateparse/pull/156 531 | {in: "04/02/2014, 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 532 | {in: "4/2/2014, 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, 533 | {in: "04/02/2014, 04:08 AM", out: "2014-04-02 04:08:00 +0000 UTC"}, 534 | {in: "04/02/2014, 04:08 PM", out: "2014-04-02 16:08:00 +0000 UTC"}, 535 | // Git log default date format - https://github.com/araddon/dateparse/pull/92 536 | {in: "Thu Apr 7 15:13:13 2005 -0700", out: "2005-04-07 22:13:13 +0000 UTC"}, 537 | {in: "Tue Dec 12 23:07:11 2023 -0700", out: "2023-12-13 06:07:11 +0000 UTC"}, 538 | // Variants with different offset formats, or that place the year after the offset and/or timezone 539 | {in: "Thu Apr 7 15:13:13 2005 -07:00", out: "2005-04-07 22:13:13 +0000 UTC"}, 540 | {in: "Thu Apr 7 15:13:13 2005 -07:00 PST", out: "2005-04-07 22:13:13 +0000 UTC", zname: "PST"}, 541 | {in: "Thu Apr 7 15:13:13 2005 -07:00 PST (Pacific Standard Time)", out: "2005-04-07 22:13:13 +0000 UTC", zname: "PST"}, 542 | {in: "Thu Apr 7 15:13:13 -0700 2005", out: "2005-04-07 22:13:13 +0000 UTC"}, 543 | {in: "Thu Apr 7 15:13:13 -07:00 2005", out: "2005-04-07 22:13:13 +0000 UTC"}, 544 | {in: "Thu Apr 7 15:13:13 -0700 PST 2005", out: "2005-04-07 22:13:13 +0000 UTC", zname: "PST"}, 545 | {in: "Thu Apr 7 15:13:13 -07:00 PST 2005", out: "2005-04-07 22:13:13 +0000 UTC", zname: "PST"}, 546 | {in: "Thu Apr 7 15:13:13 PST 2005", out: "2005-04-07 15:13:13 +0000 UTC", zname: "PST"}, 547 | // RabbitMQ log format - https://github.com/araddon/dateparse/pull/122 548 | {in: "8-Mar-2018::14:09:27", out: "2018-03-08 14:09:27 +0000 UTC"}, 549 | {in: "08-03-2018::02:09:29 PM", out: "2018-03-08 14:09:29 +0000 UTC"}, 550 | // yyyy-mm-dd hh:mm:ss,000 551 | {in: "2014-05-11 08:20:13,787", out: "2014-05-11 08:20:13.787 +0000 UTC"}, 552 | {in: "2014-05-11 08:20:13:787", out: "2014-05-11 08:20:13.787 +0000 UTC"}, 553 | // yyyy-mm-dd hh:mm:ss +0000 554 | {in: "2012-08-03 18:31:59 +0000", out: "2012-08-03 18:31:59 +0000 UTC"}, 555 | {in: "2012-08-03 13:31:59 -0600", out: "2012-08-03 19:31:59 +0000 UTC"}, 556 | {in: "2012-08-03 18:31:59.257000000 +0000", out: "2012-08-03 18:31:59.257 +0000 UTC"}, 557 | {in: "2012-08-03 8:1:59.257000000 +0000", out: "2012-08-03 08:01:59.257 +0000 UTC"}, 558 | {in: "2012-8-03 18:31:59.257000000 +0000", out: "2012-08-03 18:31:59.257 +0000 UTC"}, 559 | {in: "2012-8-3 18:31:59.257000000 +0000", out: "2012-08-03 18:31:59.257 +0000 UTC"}, 560 | {in: "2014-04-26 17:24:37.123456 +0000", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, 561 | {in: "2014-04-26 17:24:37.12 +0000", out: "2014-04-26 17:24:37.12 +0000 UTC"}, 562 | {in: "2014-04-26 17:24:37.1 +0000", out: "2014-04-26 17:24:37.1 +0000 UTC"}, 563 | {in: "2014-05-11 08:20:13 +0000", out: "2014-05-11 08:20:13 +0000 UTC"}, 564 | {in: "2014-05-11 08:20:13 +0530", out: "2014-05-11 02:50:13 +0000 UTC"}, 565 | {in: "2014-05-11 08:20:13 +0530 m=+0.000000001", out: "2014-05-11 02:50:13 +0000 UTC"}, 566 | {in: "2014-05-11 08:20:13.123456 +0530 m=+0.000000001", out: "2014-05-11 02:50:13.123456 +0000 UTC"}, 567 | // yyyy-mm-dd hh:mm:ss +0300 +03 ?? issue author said this is from golang? 568 | {in: "2018-06-29 19:09:57.77297118 +0300 +03", out: "2018-06-29 16:09:57.77297118 +0000 UTC"}, 569 | {in: "2018-06-29 19:09:57.77297118 +0300 +0300", out: "2018-06-29 16:09:57.77297118 +0000 UTC"}, 570 | {in: "2018-06-29 19:09:57 +0300 +03", out: "2018-06-29 16:09:57 +0000 UTC"}, 571 | {in: "2018-06-29 19:09:57 +0300 +0300", out: "2018-06-29 16:09:57 +0000 UTC"}, 572 | // yyyy-mm-dd hh:mm:ss +00:00 573 | {in: "2012-08-03 18:31:59 +00:00", out: "2012-08-03 18:31:59 +0000 UTC"}, 574 | {in: "2014-05-01 08:02:13 +00:00", out: "2014-05-01 08:02:13 +0000 UTC"}, 575 | {in: "2014-5-01 08:02:13 +00:00", out: "2014-05-01 08:02:13 +0000 UTC"}, 576 | {in: "2014-05-1 08:02:13 +00:00", out: "2014-05-01 08:02:13 +0000 UTC"}, 577 | {in: "2012-08-03 13:31:59 -06:00", out: "2012-08-03 19:31:59 +0000 UTC"}, 578 | {in: "2012-08-03 18:31:59.257000000 +00:00", out: "2012-08-03 18:31:59.257 +0000 UTC"}, 579 | {in: "2012-08-03 8:1:59.257000000 +00:00", out: "2012-08-03 08:01:59.257 +0000 UTC"}, 580 | {in: "2012-8-03 18:31:59.257000000 +00:00", out: "2012-08-03 18:31:59.257 +0000 UTC"}, 581 | {in: "2012-8-3 18:31:59.257000000 +00:00", out: "2012-08-03 18:31:59.257 +0000 UTC"}, 582 | {in: "2014-04-26 17:24:37.123456 +00:00", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, 583 | {in: "2014-04-26 17:24:37.12 +00:00", out: "2014-04-26 17:24:37.12 +0000 UTC"}, 584 | {in: "2014-04-26 17:24:37.1 +00:00", out: "2014-04-26 17:24:37.1 +0000 UTC"}, 585 | {in: "2014-04-26 17:24:37 +00:00 m=+0.000000001", out: "2014-04-26 17:24:37 +0000 UTC"}, 586 | {in: "2014-04-26 17:24:37.123456 +00:00 m=+0.000000001", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, 587 | // yyyy-mm-dd hh:mm:ss +0000 TZ 588 | // Golang Native Format 589 | {in: "2012-08-03 18:31:59 +0000 UTC", out: "2012-08-03 18:31:59 +0000 UTC", zname: "UTC"}, 590 | {in: "2012-08-03 13:31:59 -0600 MST", out: "2012-08-03 19:31:59 +0000 UTC", loc: "America/Denver", zname: "MST"}, 591 | {in: "2015-02-18 00:12:00 +0000 UTC", out: "2015-02-18 00:12:00 +0000 UTC", zname: "UTC"}, 592 | {in: "2015-02-18 00:12:00 +0000 GMT", out: "2015-02-18 00:12:00 +0000 UTC", zname: "GMT"}, 593 | {in: "2015-02-08 03:02:00 +0200 CEST", out: "2015-02-08 01:02:00 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 594 | {in: "2015-02-08 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC", zname: "MSK"}, 595 | {in: "2015-2-08 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC", zname: "MSK"}, 596 | {in: "2015-02-8 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC", zname: "MSK"}, 597 | {in: "2015-2-8 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC", zname: "MSK"}, 598 | {in: "2012-08-03 18:31:59.257000000 +0000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 599 | {in: "2012-08-03 8:1:59.257000000 +0000 UTC", out: "2012-08-03 08:01:59.257 +0000 UTC", zname: "UTC"}, 600 | {in: "2012-8-03 18:31:59.257000000 +0000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 601 | {in: "2012-8-3 18:31:59.257000000 +0000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 602 | {in: "2014-04-26 17:24:37.123456 +0000 UTC", out: "2014-04-26 17:24:37.123456 +0000 UTC", zname: "UTC"}, 603 | {in: "2014-04-26 17:24:37.12 +0000 UTC", out: "2014-04-26 17:24:37.12 +0000 UTC", zname: "UTC"}, 604 | {in: "2014-04-26 17:24:37.1 +0000 UTC", out: "2014-04-26 17:24:37.1 +0000 UTC", zname: "UTC"}, 605 | {in: "2015-02-08 03:02:00 +0200 CEST m=+0.000000001", out: "2015-02-08 01:02:00 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 606 | {in: "2015-02-08 03:02:00 +0300 MSK m=+0.000000001", out: "2015-02-08 00:02:00 +0000 UTC", zname: "MSK"}, 607 | {in: "2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001", out: "2015-02-08 00:02:00.001 +0000 UTC", zname: "MSK"}, 608 | // Variant with colon in offset 609 | {in: "2015-02-08 03:02:00 +02:00 CEST", out: "2015-02-08 01:02:00 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 610 | {in: "2015-02-08 03:02:00 +02:00 CEST (Central European Standard Time)", out: "2015-02-08 01:02:00 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 611 | // yyyy-mm-dd hh:mm:ss TZ 612 | {in: "2012-08-03 18:31:59 UTC", out: "2012-08-03 18:31:59 +0000 UTC", zname: "UTC"}, 613 | {in: "2012-08-03 18:31:59 CEST", out: "2012-08-03 18:31:59 +0000 UTC", zname: "CEST"}, 614 | {in: "2014-12-16 06:20:00 GMT", out: "2014-12-16 06:20:00 +0000 UTC", zname: "GMT"}, 615 | {in: "2012-08-03 13:31:58 MST", out: "2012-08-03 13:31:58 +0000 UTC", zname: "MST"}, 616 | {in: "2012-08-03 13:31:59 MST", out: "2012-08-03 20:31:59 +0000 UTC", loc: "America/Denver", zname: "MDT"}, 617 | {in: "2012-01-03 13:31:59 MST", out: "2012-01-03 20:31:59 +0000 UTC", loc: "America/Denver", zname: "MST"}, 618 | {in: "2012-08-03 18:31:59.257000000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 619 | {in: "2012-08-03 8:1:59.257000000 UTC", out: "2012-08-03 08:01:59.257 +0000 UTC", zname: "UTC"}, 620 | {in: "2012-8-03 18:31:59.257000000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 621 | {in: "2012-8-3 18:31:59.257000000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 622 | {in: "2012-8-3 18:31:59.257000000 CEST", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "CEST"}, 623 | {in: "2014-04-26 17:24:37.123456 UTC", out: "2014-04-26 17:24:37.123456 +0000 UTC", zname: "UTC"}, 624 | {in: "2014-04-26 17:24:37.123456 CEST", out: "2014-04-26 17:24:37.123456 +0000 UTC", zname: "CEST"}, 625 | {in: "2014-04-26 17:24:37.123456Z", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, 626 | {in: "2014-04-26 17:24:37.12 UTC", out: "2014-04-26 17:24:37.12 +0000 UTC", zname: "UTC"}, 627 | {in: "2014-04-26 17:24:37.12 CEST", out: "2014-04-26 17:24:37.12 +0000 UTC", zname: "CEST"}, 628 | {in: "2014-04-26 17:24:37.1 UTC", out: "2014-04-26 17:24:37.1 +0000 UTC", zname: "UTC"}, 629 | {in: "2014-04-26 17:24:37.1 CEST", out: "2014-04-26 17:24:37.1 +0000 UTC", zname: "CEST"}, 630 | // Test the capturing of arbitrary time zone names even if we use a different specific location (offset will be zero, but name will be filled in) 631 | {in: "2012-08-03 19:32:59 UTC", out: "2012-08-03 19:32:59 +0000 UTC", loc: "Europe/Berlin", zname: "UTC"}, 632 | {in: "2012-08-03 19:32:59 CEST", out: "2012-08-03 19:32:59 +0000 UTC", loc: "America/Denver", zname: "CEST"}, 633 | {in: "2014-12-16 07:22:00 GMT", out: "2014-12-16 07:22:00 +0000 UTC", loc: "America/Los_Angeles", zname: "GMT"}, 634 | {in: "2012-08-03 14:32:59 MST", out: "2012-08-03 14:32:59 +0000 UTC", loc: "America/Los_Angeles", zname: "MST"}, 635 | // This one is pretty special, it is TIMEZONE based but starts with P to emulate collions with PM 636 | {in: "2014-04-26 05:24:37 PST", out: "2014-04-26 05:24:37 +0000 UTC", zname: "PST"}, 637 | {in: "2014-04-26 05:24:38 PST", out: "2014-04-26 13:24:38 +0000 UTC", loc: "America/Los_Angeles", zname: "PDT"}, 638 | {in: "2014-01-26 05:24:39 PST", out: "2014-01-26 13:24:39 +0000 UTC", loc: "America/Los_Angeles", zname: "PST"}, 639 | // yyyy-mm-dd hh:mm:ss+00:00 640 | {in: "2012-08-03 18:31:59+00:00", out: "2012-08-03 18:31:59 +0000 UTC"}, 641 | {in: "2017-07-19 03:21:51+00:00", out: "2017-07-19 03:21:51 +0000 UTC"}, 642 | // yyyy:mm:dd hh:mm:ss+00:00 643 | {in: "2012:08:03 18:31:59+00:00", out: "2012-08-03 18:31:59 +0000 UTC"}, 644 | // mm:dd:yyyy hh:mm:ss+00:00 645 | {in: "08:03:2012 18:31:59+00:00", out: "2012-08-03 18:31:59 +0000 UTC"}, 646 | {in: "08:04:2012 18:31:59+00:00", out: "2012-04-08 18:31:59 +0000 UTC", preferDayFirst: true}, 647 | {in: "24:03:2012 18:31:59+00:00", out: "2012-03-24 18:31:59 +0000 UTC", retryAmbiguous: true}, 648 | // yyyy-mm-dd hh:mm:ss.000+00:00 PST 649 | {in: "2012-08-03 18:31:59.000+00:00 PST", out: "2012-08-03 18:31:59 +0000 UTC", loc: "America/Los_Angeles", zname: "PST"}, 650 | {in: "2012-08-03 18:31:59.000+00:00 CEST", out: "2012-08-03 18:31:59 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 651 | // yyyy-mm-dd hh:mm:ss +00:00 TZ 652 | {in: "2012-08-03 18:31:59 +00:00 UTC", out: "2012-08-03 18:31:59 +0000 UTC", zname: "UTC"}, 653 | {in: "2012-08-03 13:31:51 -07:00 MST", out: "2012-08-03 20:31:51 +0000 UTC", loc: "America/Denver", zname: "MST"}, 654 | {in: "2012-08-03 13:31:51 +02:00 CEST", out: "2012-08-03 11:31:51 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 655 | {in: "2012-08-03 18:31:59.257000000 +00:00 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 656 | {in: "2012-08-03 13:31:51.123 -08:00 PST", out: "2012-08-03 21:31:51.123 +0000 UTC", loc: "America/Los_Angeles", zname: "PST"}, 657 | {in: "2012-08-03 13:31:51.123 +02:00 CEST", out: "2012-08-03 11:31:51.123 +0000 UTC", loc: "Europe/Berlin", zname: "CEST"}, 658 | {in: "2012-08-03 13:31:51.123 +02:00 CEST", out: "2012-08-03 11:31:51.123 +0000 UTC", loc: "America/Los_Angeles", zname: "CEST"}, 659 | {in: "2012-08-03 8:1:59.257000000 +00:00 UTC", out: "2012-08-03 08:01:59.257 +0000 UTC", zname: "UTC"}, 660 | {in: "2012-08-03 8:1:59.257000000 +00:00 CEST", out: "2012-08-03 08:01:59.257 +0000 UTC", zname: "CEST"}, 661 | {in: "2012-8-03 18:31:59.257000000 +00:00 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 662 | {in: "2012-8-03 18:31:59.257000000 +00:00 CEST", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "CEST"}, 663 | {in: "2012-8-3 18:31:59.257000000 +00:00 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "UTC"}, 664 | {in: "2012-8-3 18:31:59.257000000 +00:00 CEST", out: "2012-08-03 18:31:59.257 +0000 UTC", zname: "CEST"}, 665 | {in: "2014-04-26 17:24:37.123456 +00:00 UTC", out: "2014-04-26 17:24:37.123456 +0000 UTC", zname: "UTC"}, 666 | {in: "2014-04-26 17:24:37.123456 +00:00 CEST", out: "2014-04-26 17:24:37.123456 +0000 UTC", zname: "CEST"}, 667 | {in: "2014-04-26 17:24:37.12 +00:00 UTC", out: "2014-04-26 17:24:37.12 +0000 UTC", zname: "UTC"}, 668 | {in: "2014-04-26 17:24:37.12 +00:00 CEST", out: "2014-04-26 17:24:37.12 +0000 UTC", zname: "CEST"}, 669 | {in: "2014-04-26 17:24:37.1 +00:00 UTC", out: "2014-04-26 17:24:37.1 +0000 UTC", zname: "UTC"}, 670 | {in: "2014-04-26 17:24:37.1 +00:00 CEST", out: "2014-04-26 17:24:37.1 +0000 UTC", zname: "CEST"}, 671 | // yyyy-mm-ddThh:mm:ss 672 | {in: "2009-08-12T22:15:09", out: "2009-08-12 22:15:09 +0000 UTC"}, 673 | {in: "2009-08-08T02:08:08", out: "2009-08-08 02:08:08 +0000 UTC"}, 674 | {in: "2009-08-08T2:8:8", out: "2009-08-08 02:08:08 +0000 UTC"}, 675 | {in: "2009-08-12T22:15:09.123", out: "2009-08-12 22:15:09.123 +0000 UTC"}, 676 | {in: "2009-08-12T22:15:09.123456", out: "2009-08-12 22:15:09.123456 +0000 UTC"}, 677 | {in: "2009-08-12T22:15:09.12", out: "2009-08-12 22:15:09.12 +0000 UTC"}, 678 | {in: "2009-08-12T22:15:09.1", out: "2009-08-12 22:15:09.1 +0000 UTC"}, 679 | {in: "2014-04-26 17:24:37.3186369", out: "2014-04-26 17:24:37.3186369 +0000 UTC"}, 680 | // yyyy-mm-ddThh:mm:ss-07:00 681 | {in: "2009-08-12T22:15:09-07:00", out: "2009-08-13 05:15:09 +0000 UTC"}, 682 | {in: "2009-08-12T22:15:09-03:00", out: "2009-08-13 01:15:09 +0000 UTC"}, 683 | {in: "2009-08-12T22:15:9-07:00", out: "2009-08-13 05:15:09 +0000 UTC"}, 684 | {in: "2009-08-12T22:15:09.123-07:00", out: "2009-08-13 05:15:09.123 +0000 UTC"}, 685 | {in: "2016-06-21T19:55:00+01:00", out: "2016-06-21 18:55:00 +0000 UTC"}, 686 | {in: "2016-06-21T19:55:00.799+01:00", out: "2016-06-21 18:55:00.799 +0000 UTC"}, 687 | // yyyy-mm-ddThh:mm:ss-07 TZ truncated to 2 digits instead of 4 688 | {in: "2019-05-29T08:41-04", out: "2019-05-29 12:41:00 +0000 UTC"}, 689 | // yyyy-mm-ddThh:mm:ss-0700 690 | {in: "2009-08-12T22:15:09-0700", out: "2009-08-13 05:15:09 +0000 UTC"}, 691 | {in: "2009-08-12T22:15:09-0300", out: "2009-08-13 01:15:09 +0000 UTC"}, 692 | {in: "2009-08-12T22:15:9-0700", out: "2009-08-13 05:15:09 +0000 UTC"}, 693 | {in: "2009-08-12T22:15:09.123-0700", out: "2009-08-13 05:15:09.123 +0000 UTC"}, 694 | {in: "2016-06-21T19:55:00+0100", out: "2016-06-21 18:55:00 +0000 UTC"}, 695 | {in: "2016-06-21T19:55:00.799+0100", out: "2016-06-21 18:55:00.799 +0000 UTC"}, 696 | {in: "2016-06-21T19:55:00+0100", out: "2016-06-21 18:55:00 +0000 UTC"}, 697 | {in: "2016-06-21T19:55:00-0700", out: "2016-06-22 02:55:00 +0000 UTC"}, 698 | {in: "2016-06-21T19:55:00.799+0100", out: "2016-06-21 18:55:00.799 +0000 UTC"}, 699 | {in: "2016-06-21T19:55+0100", out: "2016-06-21 18:55:00 +0000 UTC"}, 700 | {in: "2016-06-21T19:55+0130", out: "2016-06-21 18:25:00 +0000 UTC"}, 701 | // yyyy-mm-ddThh:mm:ss:000+0000 - weird format with additional colon in front of milliseconds 702 | {in: "2012-08-17T18:31:59:257", out: "2012-08-17 18:31:59.257 +0000 UTC"}, // https://github.com/araddon/dateparse/issues/137 703 | {in: "2012-08-17T18:31:59:257+0100", out: "2012-08-17 17:31:59.257 +0000 UTC"}, // https://github.com/araddon/dateparse/issues/117 704 | {in: "2012-08-17T18:31:59:257+0200 CET", out: "2012-08-17 16:31:59.257 +0000 UTC", zname: "CET"}, 705 | {in: "2012-08-17T18:31:59:257+0200 CET (Central European Time)", out: "2012-08-17 16:31:59.257 +0000 UTC", zname: "CET"}, 706 | // yyyy-mm-ddThh:mm:ssZ 707 | {in: "2009-08-12T22:15Z", out: "2009-08-12 22:15:00 +0000 UTC"}, 708 | {in: "2009-08-12T22:15:09Z", out: "2009-08-12 22:15:09 +0000 UTC"}, 709 | {in: "2009-08-12T22:15:09.99Z", out: "2009-08-12 22:15:09.99 +0000 UTC"}, 710 | {in: "2009-08-12T22:15:09.9999Z", out: "2009-08-12 22:15:09.9999 +0000 UTC"}, 711 | {in: "2009-08-12T22:15:09.99999999Z", out: "2009-08-12 22:15:09.99999999 +0000 UTC"}, 712 | {in: "2009-08-12T22:15:9.99999999Z", out: "2009-08-12 22:15:09.99999999 +0000 UTC"}, 713 | // yyyy.mm 714 | {in: "2014", out: "2014-01-01 00:00:00 +0000 UTC"}, 715 | {in: "2014.05", out: "2014-05-01 00:00:00 +0000 UTC"}, 716 | {in: "2018.09.30", out: "2018-09-30 00:00:00 +0000 UTC"}, 717 | // mm.dd.yyyy 718 | {in: "3.31.2014", out: "2014-03-31 00:00:00 +0000 UTC"}, 719 | {in: "3.3.2014", out: "2014-03-03 00:00:00 +0000 UTC"}, 720 | {in: "03.31.2014", out: "2014-03-31 00:00:00 +0000 UTC"}, 721 | {in: "03.31.2014 10:11:59 MST", out: "2014-03-31 10:11:59 +0000 UTC", zname: "MST"}, 722 | // mm.dd.yy 723 | {in: "08.21.71", out: "1971-08-21 00:00:00 +0000 UTC"}, 724 | // dd.mm.yyyy (see https://github.com/araddon/dateparse/issues/129 and https://github.com/araddon/dateparse/issues/28 and https://github.com/araddon/dateparse/pull/133) 725 | {in: "23.07.1938", out: "1938-07-23 00:00:00 +0000 UTC", retryAmbiguous: true}, 726 | {in: "23.07.1938", out: "1938-07-23 00:00:00 +0000 UTC", preferDayFirst: true}, 727 | {in: "23/07/1938", out: "1938-07-23 00:00:00 +0000 UTC", retryAmbiguous: true}, 728 | {in: "23/07/1938", out: "1938-07-23 00:00:00 +0000 UTC", preferDayFirst: true}, 729 | {in: "31/3/2014", out: "2014-03-31 00:00:00 +0000 UTC", retryAmbiguous: true}, 730 | {in: "31/3/2014", out: "2014-03-31 00:00:00 +0000 UTC", preferDayFirst: true}, 731 | {in: "31/03/2014", out: "2014-03-31 00:00:00 +0000 UTC", retryAmbiguous: true}, 732 | {in: "31/03/2014", out: "2014-03-31 00:00:00 +0000 UTC", preferDayFirst: true}, 733 | {in: "21/08/71", out: "1971-08-21 00:00:00 +0000 UTC", retryAmbiguous: true}, 734 | {in: "21/08/71", out: "1971-08-21 00:00:00 +0000 UTC", preferDayFirst: true}, 735 | {in: "1/8/71", out: "1971-01-08 00:00:00 +0000 UTC", preferDayFirst: false}, 736 | {in: "1/8/71", out: "1971-08-01 00:00:00 +0000 UTC", preferDayFirst: true}, 737 | {in: "8/4/2014 22:05", out: "2014-08-04 22:05:00 +0000 UTC", preferDayFirst: false}, 738 | {in: "8/4/2014 22:05", out: "2014-04-08 22:05:00 +0000 UTC", preferDayFirst: true}, 739 | {in: "08/04/2014 22:05", out: "2014-08-04 22:05:00 +0000 UTC", preferDayFirst: false}, 740 | {in: "08/04/2014 22:05", out: "2014-04-08 22:05:00 +0000 UTC", preferDayFirst: true}, 741 | {in: "2/04/2014 03:00:51", out: "2014-02-04 03:00:51 +0000 UTC", preferDayFirst: false}, 742 | {in: "2/04/2014 03:00:51", out: "2014-04-02 03:00:51 +0000 UTC", preferDayFirst: true}, 743 | {in: "19/03/2012 10:11:56", out: "2012-03-19 10:11:56 +0000 UTC", retryAmbiguous: true}, 744 | {in: "19/03/2012 10:11:57", out: "2012-03-19 10:11:57 +0000 UTC", preferDayFirst: true}, 745 | {in: "19/03/2012 10:11:58.3186369", out: "2012-03-19 10:11:58.3186369 +0000 UTC", retryAmbiguous: true}, 746 | {in: "19/03/2012 10:11:59.3186369", out: "2012-03-19 10:11:59.3186369 +0000 UTC", preferDayFirst: true}, 747 | // For certain parse modes that restart parsing, make sure that parsing options are passed along! 748 | {in: "Monday 19/03/2012 10:11:50", out: "2012-03-19 10:11:50 +0000 UTC", retryAmbiguous: true}, 749 | {in: "Monday 19/03/2012 10:11:51", out: "2012-03-19 10:11:51 +0000 UTC", preferDayFirst: true}, 750 | // https://github.com/araddon/dateparse/issues/105 751 | {in: "20/5/2006 19:51:45", out: "2006-05-20 19:51:45 +0000 UTC", retryAmbiguous: true}, 752 | {in: "20/5/2006 19:51:45", out: "2006-05-20 19:51:45 +0000 UTC", preferDayFirst: true}, 753 | // yyyymmdd and similar 754 | {in: "2014", out: "2014-01-01 00:00:00 +0000 UTC", allowWeekdayPrefix: false}, 755 | {in: "20140601", out: "2014-06-01 00:00:00 +0000 UTC", allowWeekdayPrefix: false}, 756 | {in: "20140722105203", out: "2014-07-22 10:52:03 +0000 UTC", allowWeekdayPrefix: false}, 757 | // https://github.com/araddon/dateparse/issues/143 758 | {in: "20140722105203.364", out: "2014-07-22 10:52:03.364 +0000 UTC", allowWeekdayPrefix: false}, 759 | // yymmdd hh:mm:yy mysql log https://github.com/araddon/dateparse/issues/119 760 | // 080313 05:21:55 mysqld started 761 | // 080313 5:21:55 InnoDB: Started; log sequence number 0 43655 762 | {in: "171113 14:14:20", out: "2017-11-13 14:14:20 +0000 UTC"}, 763 | // https://github.com/araddon/dateparse/issues/94 764 | {in: "190910 11:51:49", out: "2019-09-10 11:51:49 +0000 UTC"}, 765 | 766 | // all digits: unix secs, ms etc 767 | {in: "1332151919", out: "2012-03-19 10:11:59 +0000 UTC", zname: "UTC", allowWeekdayPrefix: false}, 768 | {in: "1332151919", out: "2012-03-19 10:11:59 +0000 UTC", loc: "America/Denver", zname: "MDT", allowWeekdayPrefix: false}, 769 | {in: "1384216367111", out: "2013-11-12 00:32:47.111 +0000 UTC", allowWeekdayPrefix: false}, 770 | {in: "1384216367111222", out: "2013-11-12 00:32:47.111222 +0000 UTC", allowWeekdayPrefix: false}, 771 | {in: "1384216367111222333", out: "2013-11-12 00:32:47.111222333 +0000 UTC", allowWeekdayPrefix: false}, 772 | 773 | // other 774 | {in: "Wed, 8 Feb 2023 19:00:46 +1100 (AEDT)", out: "2023-02-08 08:00:46 +0000 UTC"}, 775 | {in: "FRI, 16 AUG 2013 9:39:51 +1000", out: "2013-08-15 23:39:51 +0000 UTC"}, 776 | // https://github.com/araddon/dateparse/issues/158 777 | {in: "Mon, 1 Dec 2008 14:48:22 GMT-07:00", out: "2008-12-01 21:48:22 +0000 UTC"}, 778 | {in: "Mon, 1 Dec 2008 14:48:22 UTC-07:00", out: "2008-12-01 21:48:22 +0000 UTC"}, 779 | // Fixes for bugs mentioned in https://github.com/araddon/dateparse/pull/134 780 | {in: "2014.02.13", out: "2014-02-13 00:00:00 +0000 UTC"}, 781 | {in: "2014-02-13 00:00:00", out: "2014-02-13 00:00:00 +0000 UTC"}, 782 | {in: "2014.02.13 00:00:00", out: "2014-02-13 00:00:00 +0000 UTC"}, 783 | {in: "2014.02.13 08:33:44", out: "2014-02-13 08:33:44 +0000 UTC"}, 784 | {in: "2014.02.13T08:33:44", out: "2014-02-13 08:33:44 +0000 UTC"}, 785 | {in: "2014.02.13T08:33:44.555", out: "2014-02-13 08:33:44.555 +0000 UTC"}, 786 | {in: "2014.02.13T08:33:44.555 PM -0700 MST", out: "2014-02-14 03:33:44.555 +0000 UTC", zname: "MST"}, 787 | {in: "2014.02.13-0200", out: "2014-02-13 02:00:00 +0000 UTC"}, 788 | // Whitespace up front is now allowed 789 | {in: " 2018-01-02 17:08:09 -07:00", out: "2018-01-03 00:08:09 +0000 UTC"}, 790 | {in: " 2018-01-02 17:08:09 -07:00", out: "2018-01-03 00:08:09 +0000 UTC"}, 791 | {in: " 2018-01-02 17:08:09 -07:00", out: "2018-01-03 00:08:09 +0000 UTC"}, 792 | 793 | //syslog RFC3164 formats and non-conformant variants observed in the wild 794 | {in: "Apr 9 12:37:24", out: "0000-04-09 12:37:24 +0000 UTC"}, 795 | {in: "Apr 9 12:37:24-10", out: "0000-04-09 22:37:24 +0000 UTC"}, 796 | {in: "Apr 9 12:37:24-1000", out: "0000-04-09 22:37:24 +0000 UTC"}, 797 | {in: "Apr 9 12:37:24 UTC-10", out: "0000-04-09 22:37:24 +0000 UTC"}, 798 | {in: "Apr 9 12:37:24 MST", out: "0000-04-09 12:37:24 +0000 UTC", zname: "MST"}, 799 | {in: "Apr 9 12:37:24 MST-07:00", out: "0000-04-09 19:37:24 +0000 UTC", zname: "MST"}, 800 | {in: "Apr 9 12:37:24 TZ-10", out: "0000-04-09 22:37:24 +0000 UTC"}, 801 | {in: "Apr 9 12:37:24 TZ+02:00", out: "0000-04-09 10:37:24 +0000 UTC"}, 802 | {in: "Apr 9 12:37:24+10", out: "0000-04-09 02:37:24 +0000 UTC"}, 803 | {in: "Apr 9 12:37:24+10:00", out: "0000-04-09 02:37:24 +0000 UTC"}, 804 | {in: "Apr 9 12:37:24 CEST", out: "0000-04-09 12:37:24 +0000 UTC", zname: "CEST"}, 805 | {in: "Apr 9 12:37:24 CEST+0200", out: "0000-04-09 10:37:24 +0000 UTC", zname: "CEST"}, 806 | {in: "Apr 9 12:37:24 2025", out: "2025-04-09 12:37:24 +0000 UTC"}, 807 | {in: "Apr 9 12:37:24 2025 +02:00", out: "2025-04-09 10:37:24 +0000 UTC"}, 808 | {in: "Apr 9 2025 12:37:24", out: "2025-04-09 12:37:24 +0000 UTC"}, 809 | {in: "Apr 9 2025 12:37:24 -0700", out: "2025-04-09 19:37:24 +0000 UTC"}, 810 | //syslog RFC5424 formats and non-conformant variants observed in the wild 811 | {in: "2025-04-09T12:37:24Z", out: "2025-04-09 12:37:24 +0000 UTC"}, 812 | {in: "2025-04-09T12:37:24.123Z", out: "2025-04-09 12:37:24.123 +0000 UTC"}, 813 | {in: "2025-04-09T12:37:24.123456Z", out: "2025-04-09 12:37:24.123456 +0000 UTC"}, 814 | {in: "2025-04-09T12:37:24-10:00", out: "2025-04-09 22:37:24 +0000 UTC"}, 815 | {in: "2025-04-09T12:37:24.123 +0200", out: "2025-04-09 10:37:24.123 +0000 UTC"}, 816 | {in: "2025-04-09T12:37:24.123456 -0700 MDT", out: "2025-04-09 19:37:24.123456 +0000 UTC", zname: "MDT"}, 817 | } 818 | 819 | func TestParse(t *testing.T) { 820 | 821 | // Lets ensure we are operating on UTC 822 | time.Local = time.UTC 823 | 824 | zeroTime := time.Time{}.Unix() 825 | t.Run("Invalid", func(t *testing.T) { 826 | ts, err := ParseAny("INVALID") 827 | assert.Equal(t, zeroTime, ts.Unix()) 828 | assert.NotEqual(t, nil, err) 829 | 830 | assert.Equal(t, true, testDidPanic("NOT GONNA HAPPEN")) 831 | // https://github.com/golang/go/issues/5294 832 | _, err = ParseAny(time.RFC3339) 833 | assert.NotEqual(t, nil, err) 834 | }) 835 | 836 | allDays := make([]string, 0, len(knownDays)) 837 | for day := range knownDays { 838 | allDays = append(allDays, day) 839 | } 840 | 841 | i := 0 842 | for _, simpleErrorMessage := range []bool{false, true} { 843 | for _, addWeekday := range []bool{false, true} { 844 | for _, th := range testInputs { 845 | i++ 846 | prefix := "" 847 | if addWeekday && th.allowWeekdayPrefix { 848 | prefix = allDays[i%len(allDays)] 849 | if i%2 == 1 { 850 | prefix += "," 851 | } 852 | prefix += " " 853 | } 854 | fullInput := prefix + th.in 855 | 856 | t.Run(fmt.Sprintf("simpleerr-%v/addweekday-%v/%s", simpleErrorMessage, addWeekday, fullInput), func(t *testing.T) { 857 | var ts time.Time 858 | defer func() { 859 | if r := recover(); r != nil { 860 | t.Fatalf("error: %s", r) 861 | } 862 | }() 863 | parserOptions := []ParserOption{ 864 | PreferMonthFirst(!th.preferDayFirst), 865 | RetryAmbiguousDateWithSwap(th.retryAmbiguous), 866 | SimpleErrorMessages(simpleErrorMessage), 867 | } 868 | if len(th.loc) > 0 { 869 | loc, err := time.LoadLocation(th.loc) 870 | if err != nil { 871 | t.Fatalf("Expected to load location %q but got %v", th.loc, err) 872 | } 873 | ts, err = ParseIn(fullInput, loc, parserOptions...) 874 | if err != nil { 875 | t.Fatalf("expected to parse %q but got %v", fullInput, err) 876 | } 877 | got := fmt.Sprintf("%v", ts.In(time.UTC)) 878 | assert.Equal(t, th.out, got, "Expected %q but got %q from %q", th.out, got, fullInput) 879 | if th.out != got { 880 | t.Fatalf("whoops, got %s, expected %s", got, th.out) 881 | } 882 | if len(th.zname) > 0 { 883 | gotZone, _ := ts.Zone() 884 | assert.Equal(t, th.zname, gotZone, "Expected zname %q but got %q from %q", th.zname, gotZone, fullInput) 885 | } 886 | } else { 887 | ts = MustParse(fullInput, parserOptions...) 888 | got := fmt.Sprintf("%v", ts.In(time.UTC)) 889 | assert.Equal(t, th.out, got, "Expected %q but got %q from %q", th.out, got, fullInput) 890 | if th.out != got { 891 | t.Fatalf("whoops, got %s, expected %s", got, th.out) 892 | } 893 | if len(th.zname) > 0 { 894 | gotZone, _ := ts.Zone() 895 | assert.Equal(t, th.zname, gotZone, "Expected zname %q but got %q from %q", th.zname, gotZone, fullInput) 896 | } 897 | } 898 | }) 899 | } 900 | } 901 | } 902 | 903 | // some errors 904 | 905 | t.Run("", func(t *testing.T) { 906 | assert.Equal(t, true, testDidPanic(`{"ts":"now"}`)) 907 | }) 908 | 909 | t.Run("too many digits", func(t *testing.T) { 910 | _, err := ParseAny("138421636711122233311111") // too many digits 911 | assert.NotEqual(t, nil, err) 912 | }) 913 | 914 | t.Run("negative number", func(t *testing.T) { 915 | _, err := ParseAny("-1314") 916 | assert.NotEqual(t, nil, err) 917 | }) 918 | 919 | t.Run("month doesn't exist", func(t *testing.T) { 920 | _, err := ParseAny("2014-13-13 08:20:13,787") // month 13 doesn't exist so error 921 | assert.NotEqual(t, nil, err) 922 | }) 923 | } 924 | 925 | func testDidPanic(datestr string) (paniced bool) { 926 | defer func() { 927 | if r := recover(); r != nil { 928 | paniced = true 929 | } 930 | }() 931 | MustParse(datestr) 932 | return false 933 | } 934 | 935 | func TestPStruct(t *testing.T) { 936 | 937 | denverLoc, err := time.LoadLocation("America/Denver") 938 | assert.Equal(t, nil, err) 939 | 940 | p, err := newParser("08.21.71", denverLoc) 941 | if err != nil { 942 | t.Fatalf("Parser build error: %s", err) 943 | } 944 | 945 | p.setMonth() 946 | assert.Equal(t, 0, p.moi) 947 | p.setDay() 948 | assert.Equal(t, 0, p.dayi) 949 | p.set(-1, "not") 950 | p.set(15, "not") 951 | assert.Equal(t, "08.21.71", p.datestr) 952 | assert.Equal(t, "08.21.71", string(p.format)) 953 | assert.True(t, len(p.ds()) > 0) 954 | assert.True(t, len(p.ts()) > 0) 955 | } 956 | 957 | var testParseErrors = []dateTest{ 958 | {in: "3", err: true}, 959 | {in: `{"hello"}`, err: true}, 960 | {in: "2009-15-12T22:15Z", err: true}, 961 | {in: "5,000-9,999", err: true}, 962 | {in: "xyzq-baad", err: true}, 963 | {in: "oct.-7-1970", err: true}, 964 | {in: "septe. 7, 1970", err: true}, 965 | {in: "SeptemberRR 7th, 1970", err: true}, 966 | // a semantic version number should not be interpreted as a date 967 | {in: "1.22.3-78888", err: true}, 968 | // a semantic version number that starts with a date should not be interpreted as a date 969 | {in: "1.22.2023-78888", err: true}, 970 | // https://github.com/araddon/dateparse/issues/145 971 | {in: "dataddo, faces, bug", err: true}, 972 | // https://github.com/araddon/dateparse/issues/108 973 | {in: "1.jpg", err: true}, 974 | // https://github.com/araddon/dateparse/issues/98 975 | {in: "Wayne, Bruce", err: true}, 976 | {in: "Miami, Florida", err: true}, 977 | {in: "Doe, John", err: true}, 978 | // https://github.com/araddon/dateparse/issues/149 979 | {in: "2018-09-30 21:09:13PMDT", err: true}, 980 | {in: "2018-09-30 08:09:13pm PM", err: true}, 981 | {in: "2018-09-30 08:09:13 PM PM", err: true}, 982 | {in: "2018-09-30 08:09:13 PMDT PM", err: true}, 983 | {in: "2018-09-30 21:09:13.123PMDT", err: true}, 984 | {in: "2018-09-30 08:09:13.123PM pm", err: true}, 985 | {in: "2018-09-30 08:09:13.123 pm PM", err: true}, 986 | {in: "2018-09-30 08:09:13.123 PMDT pm", err: true}, 987 | {in: "2018-09-30 21:09:13AMT", err: true}, 988 | {in: "2018-09-30 08:09:13am AM", err: true}, 989 | {in: "2018-09-30 08:09:13 AM AM", err: true}, 990 | {in: "2018-09-30 08:09:13 AMT AM", err: true}, 991 | {in: "2018-09-30 21:09:13.123AMT", err: true}, 992 | {in: "2018-09-30 08:09:13.123AM am", err: true}, 993 | {in: "2018-09-30 08:09:13.123 am AM", err: true}, 994 | {in: "2018-09-30 08:09:13.123 AMDT am", err: true}, 995 | // https://github.com/araddon/dateparse/pull/134 996 | {in: "2014-02-13 00:00:00 utc", err: true}, // lowercase timezones are not valid 997 | {in: "2014-02-13t00:00:00.0z", err: true}, // lowercase 't' separator is not supported 998 | {in: "2014-02-13T00:00:00.0z", err: true}, // lowercase 'z' zulu timezone indicator not a valid format 999 | // Invalid variants of RabbitMQ log format 1000 | {in: "8-Mar-2018:14:09:27", err: true}, 1001 | {in: "8-Mar-2018: 14:09:27", err: true}, 1002 | {in: "8-Mar-2018:::14:09:27", err: true}, 1003 | // Invalid repeated year 1004 | {in: "Thu Apr 7 15:13:13 2005 2004", err: true}, 1005 | {in: "Thu Apr 7 15:13:13 2005 2004 ", err: true}, 1006 | {in: "Thu Apr 7 15:13:13 2005-0700", err: true}, 1007 | {in: "Thu Apr 7 15:13:13 2005-07:00", err: true}, 1008 | {in: "Thu Apr 7 15:13:13 2005 -0700 2005", err: true}, 1009 | {in: "Thu Apr 7 15:13:13 2005 -0700 PST 2005", err: true}, 1010 | {in: "Thu Apr 7 15:13:13 2005 -07:00 2005", err: true}, 1011 | {in: "Thu Apr 7 15:13:13 2005 -07:00 PST 2005", err: true}, 1012 | // Invalid offsets 1013 | {in: "Fri Jul 03 2015 18:04:07 GMT+0", err: true}, 1014 | {in: "Fri Jul 03 2015 18:04:07 GMT+000", err: true}, 1015 | {in: "Fri Jul 03 2015 18:04:07 GMT+0:100", err: true}, 1016 | {in: "Fri Jul 03 2015 18:04:07 GMT+010:0", err: true}, 1017 | {in: "Fri Jul 03 2015 18:04:07 GMT+01000", err: true}, 1018 | {in: "Fri Jul 03 2015 18:04:07 GMT+01:000", err: true}, 1019 | {in: "Fri Jul 03 2015 18:04:07 +0", err: true}, 1020 | {in: "Fri Jul 03 2015 18:04:07 +000", err: true}, 1021 | {in: "Fri Jul 03 2015 18:04:07 +0:100", err: true}, 1022 | {in: "Fri Jul 03 2015 18:04:07 +010:0", err: true}, 1023 | {in: "Fri Jul 03 2015 18:04:07 +01000", err: true}, 1024 | {in: "Fri Jul 03 2015 18:04:07 +01:000", err: true}, 1025 | // Invalid extra words on the end (or invalid time zone description) 1026 | {in: "2018-09-30 21:09:13 (Universal Coordinated Time)", err: true}, 1027 | {in: "2018-09-30 21:09:13pm (Universal Coordinated Time)", err: true}, 1028 | {in: "Fri Jul 3 2015 06:04:07 GMT+0100 blah", err: true}, 1029 | {in: "Fri Jul 3 2015 06:04:07 GMT+0100 hello world", err: true}, 1030 | {in: "Fri Jul 03 2015 18:04:07 UTC+0100 GMT Daylight Time", err: true}, 1031 | {in: "Fri Jul 3 2015 06:04:07 UTC+0100 (GMT", err: true}, 1032 | {in: "Fri Jul 3 2015 06:04:07 PST-0700 (Pacific (Daylight) Time)", err: true}, 1033 | {in: "Fri Jul 3 2015 06:04:07 CEST-0700 (Central European Summer Time) extra", err: true}, 1034 | {in: "Fri Jul 3 2015 06:04:07 +0100 blah", err: true}, 1035 | {in: "Fri Jul 3 2015 06:04:07 +0100 hello world", err: true}, 1036 | {in: "Fri Jul 03 2015 18:04:07 +0100 GMT Daylight Time", err: true}, 1037 | {in: "Fri Jul 3 2015 06:04:07 +0100 (GMT", err: true}, 1038 | {in: "Fri Jul 3 2015 06:04:07 -0700 (Pacific (Daylight) Time)", err: true}, 1039 | {in: "Fri Jul 3 2015 06:04:07 -0700 (Central European Summer Time) extra", err: true}, 1040 | {in: "Fri Jul 3 2015 06:04:07 +01:00 blah", err: true}, 1041 | {in: "Fri Jul 3 2015 06:04:07 +01:00 hello world", err: true}, 1042 | {in: "Fri Jul 03 2015 18:04:07 +01:00 GMT Daylight Time", err: true}, 1043 | {in: "Fri Jul 3 2015 06:04:07 +01:00 (GMT", err: true}, 1044 | {in: "Fri Jul 3 2015 06:04:07 -07:00 (Pacific (Daylight) Time)", err: true}, 1045 | {in: "Fri Jul 3 2015 06:04:07 -07:00 (Central European Summer Time) extra", err: true}, 1046 | {in: "Fri Jul 03 2015 18:04:07 GMT GMT", err: true}, 1047 | {in: "Fri Jul 3 2015 06:04:07 PMT blah", err: true}, 1048 | {in: "Fri Jul 3 2015 06:04:07 PMT hello world", err: true}, 1049 | {in: "Fri Jul 03 2015 18:04:07 AMT GMT Daylight Time", err: true}, 1050 | {in: "Fri Jul 3 2015 06:04:07 UTC (GMT", err: true}, 1051 | {in: "Fri Jul 3 2015 06:04:07 PST (Pacific (Daylight) Time)", err: true}, 1052 | {in: "Fri Jul 3 2015 06:04:07 CEST (Central European Summer Time) extra", err: true}, 1053 | // Special TZ indicator must be followed by an offset 1054 | {in: "Apr 9 12:37:24 TZ", err: true}, 1055 | } 1056 | 1057 | func TestParseErrors(t *testing.T) { 1058 | for _, th := range testParseErrors { 1059 | t.Run(th.in, func(t *testing.T) { 1060 | v, err := ParseAny(th.in) 1061 | assert.NotEqual(t, nil, err, "%v for %v", v, th.in) 1062 | 1063 | v, err = ParseAny(th.in, RetryAmbiguousDateWithSwap(true)) 1064 | assert.NotEqual(t, nil, err, "%v for %v", v, th.in) 1065 | }) 1066 | } 1067 | } 1068 | 1069 | func TestParseLayout(t *testing.T) { 1070 | 1071 | time.Local = time.UTC 1072 | // These tests are verifying that the layout returned by ParseFormat 1073 | // are correct. Above tests correct parsing, this tests correct 1074 | // re-usable formatting string 1075 | var testParseFormat = []dateTest{ 1076 | // errors 1077 | {in: "3", err: true}, 1078 | {in: `{"hello"}`, err: true}, 1079 | {in: "2009-15-12T22:15Z", err: true}, 1080 | {in: "5,000-9,999", err: true}, 1081 | // This 3 digit TZ offset (should be 2 or 4? is 3 a thing?) 1082 | {in: "2019-05-29T08:41-047", err: true}, 1083 | // 1084 | {in: "06/May/2008 15:04:05 -0700", out: "02/Jan/2006 15:04:05 -0700"}, 1085 | {in: "06/May/2008:15:04:05 -0700", out: "02/Jan/2006:15:04:05 -0700"}, 1086 | {in: "06/June/2008 15:04:05 -0700", out: "02/January/2006 15:04:05 -0700"}, 1087 | {in: "14 May 2019 19:11:40.164", out: "02 Jan 2006 15:04:05.000"}, 1088 | {in: "171113 14:14:20", out: "060102 15:04:05"}, 1089 | 1090 | {in: "oct 7, 1970", out: "Jan 2, 2006"}, 1091 | {in: "sept. 7, 1970", out: "Jan. 2, 2006"}, 1092 | {in: "May 05, 2015, 05:05:07", out: "Jan 02, 2006, 15:04:05"}, 1093 | // 03 February 2013 1094 | {in: "03 February 2013", out: "02 January 2006"}, 1095 | // 13:31:51.999 -07:00 MST 1096 | // yyyy-mm-dd hh:mm:ss +00:00 1097 | {in: "2012-08-03 18:31:59 +00:00", out: "2006-01-02 15:04:05 -07:00"}, 1098 | // yyyy-mm-dd hh:mm:ss +0000 TZ 1099 | // Golang Native Format = "2006-01-02 15:04:05.999999999 -0700 MST" 1100 | {in: "2012-08-03 18:31:59 +0000 UTC", out: "2006-01-02 15:04:05 -0700 MST"}, 1101 | // yyyy-mm-dd hh:mm:ss TZ 1102 | {in: "2012-08-03 18:31:59 UTC", out: "2006-01-02 15:04:05 MST"}, 1103 | {in: "2012-08-03 18:31:59 CEST", out: "2006-01-02 15:04:05 MST "}, 1104 | // yyyy-mm-ddThh:mm:ss-07:00 1105 | {in: "2009-08-12T22:15:09-07:00", out: "2006-01-02T15:04:05-07:00"}, 1106 | // yyyy-mm-ddThh:mm:ss-0700 1107 | {in: "2009-08-12T22:15:09-0700", out: "2006-01-02T15:04:05-0700"}, 1108 | // yyyy-mm-ddThh:mm:ssZ 1109 | {in: "2009-08-12T22:15Z", out: "2006-01-02T15:04Z"}, 1110 | } 1111 | 1112 | for _, th := range testParseFormat { 1113 | t.Run(th.in, func(t *testing.T) { 1114 | l, err := ParseFormat(th.in) 1115 | if th.err { 1116 | assert.NotEqual(t, nil, err) 1117 | } else { 1118 | assert.Equal(t, nil, err) 1119 | assert.Equal(t, th.out, l, "for in=%v", th.in) 1120 | } 1121 | }) 1122 | } 1123 | } 1124 | 1125 | var testParseStrict = []dateTest{ 1126 | // dd-mon-yy 13-Feb-03 1127 | {in: "03-03-14", err: true, expectAmbiguous: true}, 1128 | // mm.dd.yyyy 1129 | {in: "3.3.2014", err: true, expectAmbiguous: true}, 1130 | // mm.dd.yy 1131 | {in: "08.09.71", err: true, expectAmbiguous: true}, 1132 | // mm/dd/yyyy 1133 | {in: "3/5/2014", err: true, expectAmbiguous: true}, 1134 | // mm/dd/yy 1135 | {in: "08/08/71", err: true, expectAmbiguous: true}, 1136 | {in: "8/8/71", err: true, expectAmbiguous: true}, 1137 | // mm/dd/yy hh:mm:ss 1138 | {in: "04/02/2014 04:08:09", err: true, expectAmbiguous: true}, 1139 | {in: "4/2/2014 04:08:09", err: true, expectAmbiguous: true}, 1140 | {in: `{"hello"}`, err: true}, 1141 | {in: "2009-08-12T22:15Z"}, 1142 | // https://github.com/araddon/dateparse/issues/91 1143 | {in: "3.31.2014", err: true, expectAmbiguous: true}, 1144 | {in: "3.3.2014", err: true, expectAmbiguous: true}, 1145 | {in: "03.31.2014", err: true, expectAmbiguous: true}, 1146 | {in: "08.21.71", err: true, expectAmbiguous: true}, 1147 | {in: "3/31/2014", err: true, expectAmbiguous: true}, 1148 | {in: "3/3/2014", err: true, expectAmbiguous: true}, 1149 | {in: "03/31/2014", err: true, expectAmbiguous: true}, 1150 | {in: "08/21/71", err: true, expectAmbiguous: true}, 1151 | } 1152 | 1153 | func TestParseStrict(t *testing.T) { 1154 | 1155 | for _, th := range testParseStrict { 1156 | t.Run(th.in, func(t *testing.T) { 1157 | _, err := ParseStrict(th.in) 1158 | if th.err { 1159 | assert.NotEqual(t, nil, err) 1160 | if th.expectAmbiguous { 1161 | assert.Contains(t, err.Error(), ErrAmbiguousMMDD.Error(), "expected ambiguous") 1162 | } 1163 | } else { 1164 | assert.Equal(t, nil, err) 1165 | } 1166 | }) 1167 | } 1168 | } 1169 | 1170 | // Lets test to see how this performs using different Timezones/Locations 1171 | // Also of note, try changing your server/machine timezones and repeat 1172 | // 1173 | // !!!!! The time-zone of local machine effects the results! 1174 | // https://play.golang.org/p/IDHRalIyXh 1175 | // https://github.com/golang/go/issues/18012 1176 | func TestInLocation(t *testing.T) { 1177 | 1178 | denverLoc, err := time.LoadLocation("America/Denver") 1179 | assert.Equal(t, nil, err) 1180 | 1181 | // Start out with time.UTC 1182 | time.Local = time.UTC 1183 | 1184 | // Just normal parse to test out zone/offset 1185 | ts := MustParse("2013-02-01 00:00:00") 1186 | zone, offset := ts.Zone() 1187 | assert.Equal(t, 0, offset, "Should have found offset = 0 %v", offset) 1188 | assert.Equal(t, "UTC", zone, "Should have found zone = UTC %v", zone) 1189 | assert.Equal(t, "2013-02-01 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1190 | 1191 | // Now lets set to denver (MST/MDT) and re-parse the same time string 1192 | // and since no timezone info in string, we expect same result 1193 | time.Local = denverLoc 1194 | ts = MustParse("2013-02-01 00:00:00") 1195 | zone, offset = ts.Zone() 1196 | assert.Equal(t, 0, offset, "Should have found offset = 0 %v", offset) 1197 | assert.Equal(t, "UTC", zone, "Should have found zone = UTC %v", zone) 1198 | assert.Equal(t, "2013-02-01 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1199 | 1200 | ts = MustParse("Tue, 5 Jul 2017 16:28:13 -0700 (MST)") 1201 | assert.Equal(t, "2017-07-05 23:28:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1202 | 1203 | ts = MustParse("Tue, 5 Jul 2017 16:28:13 +0300 (CEST)") 1204 | assert.Equal(t, "2017-07-05 13:28:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1205 | 1206 | // Now we are going to use ParseIn() and see that it gives different answer 1207 | // with different zone, offset 1208 | time.Local = nil 1209 | ts, err = ParseIn("2013-02-01 00:00:00", denverLoc) 1210 | assert.Equal(t, nil, err) 1211 | zone, offset = ts.Zone() 1212 | assert.Equal(t, -25200, offset, "Should have found offset = -25200 %v %v", offset, denverLoc) 1213 | assert.Equal(t, "MST", zone, "Should have found zone = MST %v", zone) 1214 | assert.Equal(t, "2013-02-01 07:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1215 | 1216 | ts, err = ParseIn("18 January 2018", denverLoc) 1217 | assert.Equal(t, nil, err) 1218 | zone, offset = ts.Zone() 1219 | assert.Equal(t, -25200, offset, "Should have found offset = 0 %v", offset) 1220 | assert.Equal(t, "MST", zone, "Should have found zone = UTC %v", zone) 1221 | assert.Equal(t, "2018-01-18 07:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1222 | 1223 | // Now we are going to use ParseLocal() and see that it gives same 1224 | // answer as ParseIn when we have time.Local set to a location 1225 | time.Local = denverLoc 1226 | ts, err = ParseLocal("2013-02-01 00:00:00") 1227 | assert.Equal(t, nil, err) 1228 | zone, offset = ts.Zone() 1229 | assert.Equal(t, -25200, offset, "Should have found offset = -25200 %v %v", offset, denverLoc) 1230 | assert.Equal(t, "MST", zone, "Should have found zone = MST %v", zone) 1231 | assert.Equal(t, "2013-02-01 07:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1232 | 1233 | // Lets advance past daylight savings time start 1234 | // use parseIn and see offset/zone has changed to Daylight Savings Equivalents 1235 | ts, err = ParseIn("2013-04-01 00:00:00", denverLoc) 1236 | assert.Equal(t, nil, err) 1237 | zone, offset = ts.Zone() 1238 | assert.Equal(t, -21600, offset, "Should have found offset = -21600 %v %v", offset, denverLoc) 1239 | assert.Equal(t, "MDT", zone, "Should have found zone = MDT %v", zone) 1240 | assert.Equal(t, "2013-04-01 06:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1241 | 1242 | // reset to UTC 1243 | time.Local = time.UTC 1244 | 1245 | // UnixDate = "Mon Jan _2 15:04:05 MST 2006" 1246 | ts = MustParse("Mon Jan 2 15:04:05 MST 2006") 1247 | 1248 | _, offset = ts.Zone() 1249 | assert.Equal(t, 0, offset, "Should have found offset = 0 %v", offset) 1250 | assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1251 | 1252 | // Now lets set to denver(mst/mdt) 1253 | time.Local = denverLoc 1254 | ts = MustParse("Mon Jan 2 15:04:05 MST 2006") 1255 | 1256 | // this time is different from one above parsed with time.Local set to UTC 1257 | _, offset = ts.Zone() 1258 | assert.Equal(t, -25200, offset, "Should have found offset = -25200 %v", offset) 1259 | assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1260 | 1261 | // Now Reset To UTC 1262 | time.Local = time.UTC 1263 | 1264 | // RFC850 = "Monday, 02-Jan-06 15:04:05 MST" 1265 | ts = MustParse("Monday, 02-Jan-06 15:04:05 MST") 1266 | _, offset = ts.Zone() 1267 | assert.Equal(t, 0, offset, "Should have found offset = 0 %v", offset) 1268 | assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1269 | 1270 | // Now lets set to denver 1271 | time.Local = denverLoc 1272 | ts = MustParse("Monday, 02-Jan-06 15:04:05 MST") 1273 | _, offset = ts.Zone() 1274 | assert.NotEqual(t, 0, offset, "Should have found offset %v", offset) 1275 | assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1276 | 1277 | // Now some errors 1278 | zeroTime := time.Time{}.Unix() 1279 | ts, err = ParseIn("INVALID", denverLoc) 1280 | assert.Equal(t, zeroTime, ts.Unix()) 1281 | assert.NotEqual(t, nil, err) 1282 | 1283 | ts, err = ParseLocal("INVALID") 1284 | assert.Equal(t, zeroTime, ts.Unix()) 1285 | assert.NotEqual(t, nil, err) 1286 | } 1287 | 1288 | func TestPreferMonthFirst(t *testing.T) { 1289 | // default case is true 1290 | ts, err := ParseAny("04/02/2014 04:08:09 +0000 UTC") 1291 | assert.Equal(t, nil, err) 1292 | assert.Equal(t, "2014-04-02 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1293 | ts, err = ParseAny("4/02/2014 04:08:09 +0000 UTC") 1294 | assert.Equal(t, nil, err) 1295 | assert.Equal(t, "2014-04-02 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1296 | ts, err = ParseAny("04/2/2014 04:08:09 +0000 UTC") 1297 | assert.Equal(t, nil, err) 1298 | assert.Equal(t, "2014-04-02 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1299 | 1300 | preferMonthFirstTrue := PreferMonthFirst(true) 1301 | ts, err = ParseAny("04/02/2014 04:08:09 +0000 UTC", preferMonthFirstTrue) 1302 | assert.Equal(t, nil, err) 1303 | assert.Equal(t, "2014-04-02 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1304 | ts, err = ParseAny("4/02/2014 04:08:09 +0000 UTC", preferMonthFirstTrue) 1305 | assert.Equal(t, nil, err) 1306 | assert.Equal(t, "2014-04-02 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1307 | ts, err = ParseAny("04/2/2014 04:08:09 +0000 UTC", preferMonthFirstTrue) 1308 | assert.Equal(t, nil, err) 1309 | assert.Equal(t, "2014-04-02 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1310 | 1311 | // allows the day to be preferred before the month, when completely ambiguous 1312 | preferMonthFirstFalse := PreferMonthFirst(false) 1313 | ts, err = ParseAny("04/02/2014 04:08:09 +0000 UTC", preferMonthFirstFalse) 1314 | assert.Equal(t, nil, err) 1315 | assert.Equal(t, "2014-02-04 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1316 | ts, err = ParseAny("4/02/2014 04:08:09 +0000 UTC", preferMonthFirstFalse) 1317 | assert.Equal(t, nil, err) 1318 | assert.Equal(t, "2014-02-04 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1319 | ts, err = ParseAny("04/2/2014 04:08:09 +0000 UTC", preferMonthFirstFalse) 1320 | assert.Equal(t, nil, err) 1321 | assert.Equal(t, "2014-02-04 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1322 | } 1323 | 1324 | func TestRetryAmbiguousDateWithSwap(t *testing.T) { 1325 | // default is false 1326 | _, err := ParseAny("13/02/2014 04:08:09 +0000 UTC") 1327 | assert.NotEqual(t, nil, err) 1328 | _, err = ParseAny("13/2/2014 04:08:09 +0000 UTC") 1329 | assert.NotEqual(t, nil, err) 1330 | 1331 | // will fail error if the month preference cannot work due to the value being larger than 12 1332 | retryAmbiguousDateWithSwapFalse := RetryAmbiguousDateWithSwap(false) 1333 | _, err = ParseAny("13/02/2014 04:08:09 +0000 UTC", retryAmbiguousDateWithSwapFalse) 1334 | assert.NotEqual(t, nil, err) 1335 | _, err = ParseAny("13/2/2014 04:08:09 +0000 UTC", retryAmbiguousDateWithSwapFalse) 1336 | assert.NotEqual(t, nil, err) 1337 | 1338 | // will retry with the other month preference if this error is detected 1339 | retryAmbiguousDateWithSwapTrue := RetryAmbiguousDateWithSwap(true) 1340 | ts, err := ParseAny("13/02/2014 04:08:09 +0000 UTC", retryAmbiguousDateWithSwapTrue) 1341 | assert.Equal(t, nil, err) 1342 | assert.Equal(t, "2014-02-13 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1343 | ts, err = ParseAny("13/2/2014 04:08:09 +0000 UTC", retryAmbiguousDateWithSwapTrue) 1344 | assert.Equal(t, nil, err) 1345 | assert.Equal(t, "2014-02-13 04:08:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1346 | } 1347 | 1348 | // Convenience function for debugging a particular broken test case 1349 | func TestDebug(t *testing.T) { 1350 | ts := MustParse("September 17, 2012 at 10:09am CEST+02", RetryAmbiguousDateWithSwap(true)) 1351 | assert.Equal(t, "2012-09-17 08:09:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 1352 | } 1353 | --------------------------------------------------------------------------------