diff options
author | Michael Muré <batolettre@gmail.com> | 2020-02-05 22:03:19 +0100 |
---|---|---|
committer | Michael Muré <batolettre@gmail.com> | 2020-02-05 22:33:03 +0100 |
commit | 1d4bb7ceb0cef79d68df0bacc913b01e40e6ddd6 (patch) | |
tree | e088b0fa43058afde1db71541d8fcb4b94905d6e /vendor/github.com/araddon/dateparse | |
parent | f093be96e98284580d61664adecd0a2ff8b354e4 (diff) | |
download | git-bug-1d4bb7ceb0cef79d68df0bacc913b01e40e6ddd6.tar.gz |
migrate to go modules
Diffstat (limited to 'vendor/github.com/araddon/dateparse')
-rw-r--r-- | vendor/github.com/araddon/dateparse/.travis.yml | 14 | ||||
-rw-r--r-- | vendor/github.com/araddon/dateparse/LICENSE | 21 | ||||
-rw-r--r-- | vendor/github.com/araddon/dateparse/README.md | 282 | ||||
-rw-r--r-- | vendor/github.com/araddon/dateparse/parseany.go | 1864 |
4 files changed, 0 insertions, 2181 deletions
diff --git a/vendor/github.com/araddon/dateparse/.travis.yml b/vendor/github.com/araddon/dateparse/.travis.yml deleted file mode 100644 index f071cf95..00000000 --- a/vendor/github.com/araddon/dateparse/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go - -go: - - 1.10.x - - 1.11.x - -before_install: - - go get -t -v ./... - -script: - - go test -race -coverprofile=coverage.txt -covermode=atomic - -after_success: - - bash <(curl -s https://codecov.io/bash) diff --git a/vendor/github.com/araddon/dateparse/LICENSE b/vendor/github.com/araddon/dateparse/LICENSE deleted file mode 100644 index f675ed31..00000000 --- a/vendor/github.com/araddon/dateparse/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2017 Aaron Raddon - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/araddon/dateparse/README.md b/vendor/github.com/araddon/dateparse/README.md deleted file mode 100644 index 005e456f..00000000 --- a/vendor/github.com/araddon/dateparse/README.md +++ /dev/null @@ -1,282 +0,0 @@ -Go Date Parser ---------------------------- - -Parse many date strings without knowing format in advance. Uses a scanner to read bytes and use a state machine to find format. Much faster than shotgun based parse methods. See [bench_test.go](https://github.com/araddon/dateparse/blob/master/bench_test.go) for performance comparison. - - -[![Code Coverage](https://codecov.io/gh/araddon/dateparse/branch/master/graph/badge.svg)](https://codecov.io/gh/araddon/dateparse) -[![GoDoc](https://godoc.org/github.com/araddon/dateparse?status.svg)](http://godoc.org/github.com/araddon/dateparse) -[![Build Status](https://travis-ci.org/araddon/dateparse.svg?branch=master)](https://travis-ci.org/araddon/dateparse) -[![Go ReportCard](https://goreportcard.com/badge/araddon/dateparse)](https://goreportcard.com/report/araddon/dateparse) - -**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. - -**Timezones** The location your server is configured affects the results! See example or https://play.golang.org/p/IDHRalIyXh and last paragraph here https://golang.org/pkg/time/#Parse. - - -```go - -// Normal parse. Equivalent Timezone rules as time.Parse() -t, err := dateparse.ParseAny("3/1/2014") - -// Parse Strict, error on ambigous mm/dd vs dd/mm dates -t, err := dateparse.ParseStrict("3/1/2014") -> returns error - -// Return a string that represents the layout to parse the given date-time. -layout, err := dateparse.ParseFormat("May 8, 2009 5:57:51 PM") -> "Jan 2, 2006 3:04:05 PM" - -``` - -cli tool for testing dateformats ----------------------------------- - -[Date Parse CLI](https://github.com/araddon/dateparse/blob/master/dateparse) - - -Extended example -------------------- - -https://github.com/araddon/dateparse/blob/master/example/main.go - -```go -package main - -import ( - "flag" - "fmt" - "time" - - "github.com/apcera/termtables" - "github.com/araddon/dateparse" -) - -var examples = []string{ - "May 8, 2009 5:57:51 PM", - "oct 7, 1970", - "oct 7, '70", - "oct. 7, 1970", - "oct. 7, 70", - "Mon Jan 2 15:04:05 2006", - "Mon Jan 2 15:04:05 MST 2006", - "Mon Jan 02 15:04:05 -0700 2006", - "Monday, 02-Jan-06 15:04:05 MST", - "Mon, 02 Jan 2006 15:04:05 MST", - "Tue, 11 Jul 2017 16:28:13 +0200 (CEST)", - "Mon, 02 Jan 2006 15:04:05 -0700", - "Thu, 4 Jan 2018 17:53:36 +0000", - "Mon Aug 10 15:44:11 UTC+0100 2015", - "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", - "September 17, 2012 10:09am", - "September 17, 2012 at 10:09am PST-08", - "September 17, 2012, 10:10:09", - "October 7, 1970", - "October 7th, 1970", - "12 Feb 2006, 19:17", - "12 Feb 2006 19:17", - "7 oct 70", - "7 oct 1970", - "03 February 2013", - "1 July 2013", - "2013-Feb-03", - // mm/dd/yy - "3/31/2014", - "03/31/2014", - "08/21/71", - "8/1/71", - "4/8/2014 22:05", - "04/08/2014 22:05", - "4/8/14 22:05", - "04/2/2014 03:00:51", - "8/8/1965 12:00:00 AM", - "8/8/1965 01:00:01 PM", - "8/8/1965 01:00 PM", - "8/8/1965 1:00 PM", - "8/8/1965 12:00 AM", - "4/02/2014 03:00:51", - "03/19/2012 10:11:59", - "03/19/2012 10:11:59.3186369", - // yyyy/mm/dd - "2014/3/31", - "2014/03/31", - "2014/4/8 22:05", - "2014/04/08 22:05", - "2014/04/2 03:00:51", - "2014/4/02 03:00:51", - "2012/03/19 10:11:59", - "2012/03/19 10:11:59.3186369", - // Chinese - "2014年04月08日", - // yyyy-mm-ddThh - "2006-01-02T15:04:05+0000", - "2009-08-12T22:15:09-07:00", - "2009-08-12T22:15:09", - "2009-08-12T22:15:09Z", - // yyyy-mm-dd hh:mm:ss - "2014-04-26 17:24:37.3186369", - "2012-08-03 18:31:59.257000000", - "2014-04-26 17:24:37.123", - "2013-04-01 22:43", - "2013-04-01 22:43:22", - "2014-12-16 06:20:00 UTC", - "2014-12-16 06:20:00 GMT", - "2014-04-26 05:24:37 PM", - "2014-04-26 13:13:43 +0800", - "2014-04-26 13:13:43 +0800 +08", - "2014-04-26 13:13:44 +09:00", - "2012-08-03 18:31:59.257000000 +0000 UTC", - "2015-09-30 18:48:56.35272715 +0000 UTC", - "2015-02-18 00:12:00 +0000 GMT", - "2015-02-18 00:12:00 +0000 UTC", - "2015-02-08 03:02:00 +0300 MSK m=+0.000000001", - "2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001", - "2017-07-19 03:21:51+00:00", - "2014-04-26", - "2014-04", - "2014", - "2014-05-11 08:20:13,787", - // mm.dd.yy - "3.31.2014", - "03.31.2014", - "08.21.71", - "2014.03", - "2014.03.30", - // yyyymmdd and similar - "20140601", - "20140722105203", - // unix seconds, ms, micro, nano - "1332151919", - "1384216367189", - "1384216367111222", - "1384216367111222333", -} - -var ( - timezone = "" -) - -func main() { - flag.StringVar(&timezone, "timezone", "UTC", "Timezone aka `America/Los_Angeles` formatted time-zone") - flag.Parse() - - if timezone != "" { - // NOTE: This is very, very important to understand - // time-parsing in go - loc, err := time.LoadLocation(timezone) - if err != nil { - panic(err.Error()) - } - time.Local = loc - } - - table := termtables.CreateTable() - - table.AddHeaders("Input", "Parsed, and Output as %v") - for _, dateExample := range examples { - t, err := dateparse.ParseLocal(dateExample) - if err != nil { - panic(err.Error()) - } - table.AddRow(dateExample, fmt.Sprintf("%v", t)) - } - fmt.Println(table.Render()) -} - -/* -+-------------------------------------------------------+-----------------------------------------+ -| Input | Parsed, and Output as %v | -+-------------------------------------------------------+-----------------------------------------+ -| May 8, 2009 5:57:51 PM | 2009-05-08 17:57:51 +0000 UTC | -| oct 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | -| oct 7, '70 | 1970-10-07 00:00:00 +0000 UTC | -| oct. 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | -| oct. 7, 70 | 1970-10-07 00:00:00 +0000 UTC | -| Mon Jan 2 15:04:05 2006 | 2006-01-02 15:04:05 +0000 UTC | -| Mon Jan 2 15:04:05 MST 2006 | 2006-01-02 15:04:05 +0000 MST | -| Mon Jan 02 15:04:05 -0700 2006 | 2006-01-02 15:04:05 -0700 -0700 | -| Monday, 02-Jan-06 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | -| Mon, 02 Jan 2006 15:04:05 MST | 2006-01-02 15:04:05 +0000 MST | -| Tue, 11 Jul 2017 16:28:13 +0200 (CEST) | 2017-07-11 16:28:13 +0200 +0200 | -| Mon, 02 Jan 2006 15:04:05 -0700 | 2006-01-02 15:04:05 -0700 -0700 | -| Thu, 4 Jan 2018 17:53:36 +0000 | 2018-01-04 17:53:36 +0000 UTC | -| Mon Aug 10 15:44:11 UTC+0100 2015 | 2015-08-10 15:44:11 +0000 UTC | -| Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) | 2015-07-03 18:04:07 +0100 GMT | -| September 17, 2012 10:09am | 2012-09-17 10:09:00 +0000 UTC | -| September 17, 2012 at 10:09am PST-08 | 2012-09-17 10:09:00 -0800 PST | -| September 17, 2012, 10:10:09 | 2012-09-17 10:10:09 +0000 UTC | -| October 7, 1970 | 1970-10-07 00:00:00 +0000 UTC | -| October 7th, 1970 | 1970-10-07 00:00:00 +0000 UTC | -| 12 Feb 2006, 19:17 | 2006-02-12 19:17:00 +0000 UTC | -| 12 Feb 2006 19:17 | 2006-02-12 19:17:00 +0000 UTC | -| 7 oct 70 | 1970-10-07 00:00:00 +0000 UTC | -| 7 oct 1970 | 1970-10-07 00:00:00 +0000 UTC | -| 03 February 2013 | 2013-02-03 00:00:00 +0000 UTC | -| 1 July 2013 | 2013-07-01 00:00:00 +0000 UTC | -| 2013-Feb-03 | 2013-02-03 00:00:00 +0000 UTC | -| 3/31/2014 | 2014-03-31 00:00:00 +0000 UTC | -| 03/31/2014 | 2014-03-31 00:00:00 +0000 UTC | -| 08/21/71 | 1971-08-21 00:00:00 +0000 UTC | -| 8/1/71 | 1971-08-01 00:00:00 +0000 UTC | -| 4/8/2014 22:05 | 2014-04-08 22:05:00 +0000 UTC | -| 04/08/2014 22:05 | 2014-04-08 22:05:00 +0000 UTC | -| 4/8/14 22:05 | 2014-04-08 22:05:00 +0000 UTC | -| 04/2/2014 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | -| 8/8/1965 12:00:00 AM | 1965-08-08 00:00:00 +0000 UTC | -| 8/8/1965 01:00:01 PM | 1965-08-08 13:00:01 +0000 UTC | -| 8/8/1965 01:00 PM | 1965-08-08 13:00:00 +0000 UTC | -| 8/8/1965 1:00 PM | 1965-08-08 13:00:00 +0000 UTC | -| 8/8/1965 12:00 AM | 1965-08-08 00:00:00 +0000 UTC | -| 4/02/2014 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | -| 03/19/2012 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | -| 03/19/2012 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | -| 2014/3/31 | 2014-03-31 00:00:00 +0000 UTC | -| 2014/03/31 | 2014-03-31 00:00:00 +0000 UTC | -| 2014/4/8 22:05 | 2014-04-08 22:05:00 +0000 UTC | -| 2014/04/08 22:05 | 2014-04-08 22:05:00 +0000 UTC | -| 2014/04/2 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | -| 2014/4/02 03:00:51 | 2014-04-02 03:00:51 +0000 UTC | -| 2012/03/19 10:11:59 | 2012-03-19 10:11:59 +0000 UTC | -| 2012/03/19 10:11:59.3186369 | 2012-03-19 10:11:59.3186369 +0000 UTC | -| 2014年04月08日 | 2014-04-08 00:00:00 +0000 UTC | -| 2006-01-02T15:04:05+0000 | 2006-01-02 15:04:05 +0000 UTC | -| 2009-08-12T22:15:09-07:00 | 2009-08-12 22:15:09 -0700 -0700 | -| 2009-08-12T22:15:09 | 2009-08-12 22:15:09 +0000 UTC | -| 2009-08-12T22:15:09Z | 2009-08-12 22:15:09 +0000 UTC | -| 2014-04-26 17:24:37.3186369 | 2014-04-26 17:24:37.3186369 +0000 UTC | -| 2012-08-03 18:31:59.257000000 | 2012-08-03 18:31:59.257 +0000 UTC | -| 2014-04-26 17:24:37.123 | 2014-04-26 17:24:37.123 +0000 UTC | -| 2013-04-01 22:43 | 2013-04-01 22:43:00 +0000 UTC | -| 2013-04-01 22:43:22 | 2013-04-01 22:43:22 +0000 UTC | -| 2014-12-16 06:20:00 UTC | 2014-12-16 06:20:00 +0000 UTC | -| 2014-12-16 06:20:00 GMT | 2014-12-16 06:20:00 +0000 UTC | -| 2014-04-26 05:24:37 PM | 2014-04-26 17:24:37 +0000 UTC | -| 2014-04-26 13:13:43 +0800 | 2014-04-26 13:13:43 +0800 +0800 | -| 2014-04-26 13:13:43 +0800 +08 | 2014-04-26 13:13:43 +0800 +0800 | -| 2014-04-26 13:13:44 +09:00 | 2014-04-26 13:13:44 +0900 +0900 | -| 2012-08-03 18:31:59.257000000 +0000 UTC | 2012-08-03 18:31:59.257 +0000 UTC | -| 2015-09-30 18:48:56.35272715 +0000 UTC | 2015-09-30 18:48:56.35272715 +0000 UTC | -| 2015-02-18 00:12:00 +0000 GMT | 2015-02-18 00:12:00 +0000 UTC | -| 2015-02-18 00:12:00 +0000 UTC | 2015-02-18 00:12:00 +0000 UTC | -| 2015-02-08 03:02:00 +0300 MSK m=+0.000000001 | 2015-02-08 03:02:00 +0300 +0300 | -| 2015-02-08 03:02:00.001 +0300 MSK m=+0.000000001 | 2015-02-08 03:02:00.001 +0300 +0300 | -| 2017-07-19 03:21:51+00:00 | 2017-07-19 03:21:51 +0000 UTC | -| 2014-04-26 | 2014-04-26 00:00:00 +0000 UTC | -| 2014-04 | 2014-04-01 00:00:00 +0000 UTC | -| 2014 | 2014-01-01 00:00:00 +0000 UTC | -| 2014-05-11 08:20:13,787 | 2014-05-11 08:20:13.787 +0000 UTC | -| 3.31.2014 | 2014-03-31 00:00:00 +0000 UTC | -| 03.31.2014 | 2014-03-31 00:00:00 +0000 UTC | -| 08.21.71 | 1971-08-21 00:00:00 +0000 UTC | -| 2014.03 | 2014-03-01 00:00:00 +0000 UTC | -| 2014.03.30 | 2014-03-30 00:00:00 +0000 UTC | -| 20140601 | 2014-06-01 00:00:00 +0000 UTC | -| 20140722105203 | 2014-07-22 10:52:03 +0000 UTC | -| 1332151919 | 2012-03-19 10:11:59 +0000 UTC | -| 1384216367189 | 2013-11-12 00:32:47.189 +0000 UTC | -| 1384216367111222 | 2013-11-12 00:32:47.111222 +0000 UTC | -| 1384216367111222333 | 2013-11-12 00:32:47.111222333 +0000 UTC | -+-------------------------------------------------------+-----------------------------------------+ -*/ - -``` diff --git a/vendor/github.com/araddon/dateparse/parseany.go b/vendor/github.com/araddon/dateparse/parseany.go deleted file mode 100644 index 5e66aa6d..00000000 --- a/vendor/github.com/araddon/dateparse/parseany.go +++ /dev/null @@ -1,1864 +0,0 @@ -// Package dateparse parses date-strings without knowing the format -// in advance, using a fast lex based approach to eliminate shotgun -// attempts. It leans towards US style dates when there is a conflict. -package dateparse - -import ( - "fmt" - "strconv" - "strings" - "time" - "unicode" - "unicode/utf8" -) - -// func init() { -// gou.SetupLogging("debug") -// gou.SetColorOutput() -// } - -var months = []string{ - "january", - "february", - "march", - "april", - "may", - "june", - "july", - "august", - "september", - "october", - "november", - "december", -} - -type dateState uint8 -type timeState uint8 - -const ( - dateStart dateState = iota // 0 - dateDigit - dateYearDash - dateYearDashAlphaDash - dateYearDashDash - dateYearDashDashWs // 5 - dateYearDashDashT - dateDigitDash - dateDigitDashAlpha - dateDigitDashAlphaDash - dateDigitDot // 10 - dateDigitDotDot - dateDigitSlash - dateDigitChineseYear - dateDigitChineseYearWs - dateDigitWs // 15 - dateDigitWsMoYear - dateDigitWsMolong - dateAlpha - dateAlphaWs - dateAlphaWsDigit // 20 - dateAlphaWsDigitMore - dateAlphaWsDigitMoreWs - dateAlphaWsDigitMoreWsYear - dateAlphaWsMonth - dateAlphaWsMonthMore - dateAlphaWsMonthSuffix - dateAlphaWsMore - dateAlphaWsAtTime - dateAlphaWsAlpha - dateAlphaWsAlphaYearmaybe - dateAlphaPeriodWsDigit - dateWeekdayComma - dateWeekdayAbbrevComma -) -const ( - // Time state - timeIgnore timeState = iota // 0 - timeStart - timeWs - timeWsAlpha - timeWsAlphaWs - timeWsAlphaZoneOffset // 5 - timeWsAlphaZoneOffsetWs - timeWsAlphaZoneOffsetWsYear - timeWsAlphaZoneOffsetWsExtra - timeWsAMPMMaybe - timeWsAMPM // 10 - timeWsOffset - timeWsOffsetWs // 12 - timeWsOffsetColonAlpha - timeWsOffsetColon - timeWsYear // 15 - timeOffset - timeOffsetColon - timeAlpha - timePeriod - timePeriodOffset // 20 - timePeriodOffsetColon - timePeriodOffsetColonWs - timePeriodWs - timePeriodWsAlpha - timePeriodWsOffset // 25 - timePeriodWsOffsetWs - timePeriodWsOffsetWsAlpha - timePeriodWsOffsetColon - timePeriodWsOffsetColonAlpha - timeZ - timeZDigit -) - -var ( - // ErrAmbiguousMMDD for date formats such as 04/02/2014 the mm/dd vs dd/mm are - // ambiguous, so it is an error for strict parse rules. - ErrAmbiguousMMDD = fmt.Errorf("This date has ambiguous mm/dd vs dd/mm type format") -) - -func unknownErr(datestr string) error { - return fmt.Errorf("Could not find format for %q", datestr) -} - -// ParseAny parse an unknown date format, detect the layout. -// Normal parse. Equivalent Timezone rules as time.Parse(). -// NOTE: please see readme on mmdd vs ddmm ambiguous dates. -func ParseAny(datestr string) (time.Time, error) { - p, err := parseTime(datestr, nil) - if err != nil { - return time.Time{}, err - } - return p.parse() -} - -// ParseIn with Location, equivalent to time.ParseInLocation() timezone/offset -// rules. Using location arg, if timezone/offset info exists in the -// datestring, it uses the given location rules for any zone interpretation. -// That is, MST means one thing when using America/Denver and something else -// in other locations. -func ParseIn(datestr string, loc *time.Location) (time.Time, error) { - p, err := parseTime(datestr, loc) - if err != nil { - return time.Time{}, err - } - return p.parse() -} - -// ParseLocal Given an unknown date format, detect the layout, -// using time.Local, parse. -// -// Set Location to time.Local. Same as ParseIn Location but lazily uses -// the global time.Local variable for Location argument. -// -// denverLoc, _ := time.LoadLocation("America/Denver") -// time.Local = denverLoc -// -// t, err := dateparse.ParseLocal("3/1/2014") -// -// Equivalent to: -// -// t, err := dateparse.ParseIn("3/1/2014", denverLoc) -// -func ParseLocal(datestr string) (time.Time, error) { - p, err := parseTime(datestr, time.Local) - if err != nil { - return time.Time{}, err - } - return p.parse() -} - -// MustParse parse a date, and panic if it can't be parsed. Used for testing. -// Not recommended for most use-cases. -func MustParse(datestr string) time.Time { - p, err := parseTime(datestr, nil) - if err != nil { - panic(err.Error()) - } - t, err := p.parse() - if err != nil { - panic(err.Error()) - } - return t -} - -// ParseFormat parse's an unknown date-time string and returns a layout -// string that can parse this (and exact same format) other date-time strings. -// -// layout, err := dateparse.ParseFormat("2013-02-01 00:00:00") -// // layout = "2006-01-02 15:04:05" -// -func ParseFormat(datestr string) (string, error) { - p, err := parseTime(datestr, nil) - if err != nil { - return "", err - } - _, err = p.parse() - if err != nil { - return "", err - } - return string(p.format), nil -} - -// ParseStrict parse an unknown date format. IF the date is ambigous -// mm/dd vs dd/mm then return an error. These return errors: 3.3.2014 , 8/8/71 etc -func ParseStrict(datestr string) (time.Time, error) { - p, err := parseTime(datestr, nil) - if err != nil { - return time.Time{}, err - } - if p.ambiguousMD { - return time.Time{}, ErrAmbiguousMMDD - } - return p.parse() -} - -func parseTime(datestr string, loc *time.Location) (*parser, error) { - - p := newParser(datestr, loc) - i := 0 - - // General strategy is to read rune by rune through the date looking for - // certain hints of what type of date we are dealing with. - // Hopefully we only need to read about 5 or 6 bytes before - // we figure it out and then attempt a parse -iterRunes: - for ; i < len(datestr); i++ { - //r := rune(datestr[i]) - r, bytesConsumed := utf8.DecodeRuneInString(datestr[i:]) - if bytesConsumed > 1 { - i += (bytesConsumed - 1) - } - - //gou.Debugf("i=%d r=%s state=%d %s", i, string(r), p.stateDate, datestr) - switch p.stateDate { - case dateStart: - if unicode.IsDigit(r) { - p.stateDate = dateDigit - } else if unicode.IsLetter(r) { - p.stateDate = dateAlpha - } else { - return nil, unknownErr(datestr) - } - case dateDigit: - - switch r { - case '-', '\u2212': - // 2006-01-02 - // 2013-Feb-03 - // 13-Feb-03 - // 29-Jun-2016 - if i == 4 { - p.stateDate = dateYearDash - p.yeari = 0 - p.yearlen = i - p.moi = i + 1 - p.set(0, "2006") - } else { - p.stateDate = dateDigitDash - } - case '/': - // 03/31/2005 - // 2014/02/24 - p.stateDate = dateDigitSlash - if i == 4 { - p.yearlen = i - p.moi = i + 1 - p.setYear() - } else { - p.ambiguousMD = true - if p.preferMonthFirst { - if p.molen == 0 { - p.molen = i - p.setMonth() - p.dayi = i + 1 - } - } - } - - case '.': - // 3.31.2014 - // 08.21.71 - // 2014.05 - p.stateDate = dateDigitDot - if i == 4 { - p.yearlen = i - p.moi = i + 1 - p.setYear() - } else { - p.ambiguousMD = true - p.moi = 0 - p.molen = i - p.setMonth() - p.dayi = i + 1 - } - - case ' ': - // 18 January 2018 - // 8 January 2018 - // 8 jan 2018 - // 02 Jan 2018 23:59 - // 02 Jan 2018 23:59:34 - // 12 Feb 2006, 19:17 - // 12 Feb 2006, 19:17:22 - p.stateDate = dateDigitWs - p.dayi = 0 - p.daylen = i - case '年': - // Chinese Year - p.stateDate = dateDigitChineseYear - case ',': - return nil, unknownErr(datestr) - default: - continue - } - p.part1Len = i - - case dateYearDash: - // dateYearDashDashT - // 2006-01-02T15:04:05Z07:00 - // dateYearDashDashWs - // 2013-04-01 22:43:22 - // dateYearDashAlphaDash - // 2013-Feb-03 - switch r { - case '-': - p.molen = i - p.moi - p.dayi = i + 1 - p.stateDate = dateYearDashDash - p.setMonth() - default: - if unicode.IsLetter(r) { - p.stateDate = dateYearDashAlphaDash - } - } - - case dateYearDashDash: - // dateYearDashDashT - // 2006-01-02T15:04:05Z07:00 - // dateYearDashDashWs - // 2013-04-01 22:43:22 - switch r { - case ' ': - p.daylen = i - p.dayi - p.stateDate = dateYearDashDashWs - p.stateTime = timeStart - p.setDay() - break iterRunes - case 'T': - p.daylen = i - p.dayi - p.stateDate = dateYearDashDashT - p.stateTime = timeStart - p.setDay() - break iterRunes - } - case dateYearDashAlphaDash: - // 2013-Feb-03 - switch r { - case '-': - p.molen = i - p.moi - p.set(p.moi, "Jan") - p.dayi = i + 1 - } - case dateDigitDash: - // 13-Feb-03 - // 29-Jun-2016 - if unicode.IsLetter(r) { - p.stateDate = dateDigitDashAlpha - p.moi = i - } else { - return nil, unknownErr(datestr) - } - case dateDigitDashAlpha: - // 13-Feb-03 - // 28-Feb-03 - // 29-Jun-2016 - switch r { - case '-': - p.molen = i - p.moi - p.set(p.moi, "Jan") - p.yeari = i + 1 - p.stateDate = dateDigitDashAlphaDash - } - - case dateDigitDashAlphaDash: - // 13-Feb-03 ambiguous - // 28-Feb-03 ambiguous - // 29-Jun-2016 - switch r { - case ' ': - // we need to find if this was 4 digits, aka year - // or 2 digits which makes it ambiguous year/day - length := i - (p.moi + p.molen + 1) - if length == 4 { - p.yearlen = 4 - p.set(p.yeari, "2006") - // We now also know that part1 was the day - p.dayi = 0 - p.daylen = p.part1Len - p.setDay() - } else if length == 2 { - // We have no idea if this is - // yy-mon-dd OR dd-mon-yy - // - // We are going to ASSUME (bad, bad) that it is dd-mon-yy which is a horible assumption - p.ambiguousMD = true - p.yearlen = 2 - p.set(p.yeari, "06") - // We now also know that part1 was the day - p.dayi = 0 - p.daylen = p.part1Len - p.setDay() - } - p.stateTime = timeStart - break iterRunes - } - - case dateDigitSlash: - // 2014/07/10 06:55:38.156283 - // 03/19/2012 10:11:59 - // 04/2/2014 03:00:37 - // 3/1/2012 10:11:59 - // 4/8/2014 22:05 - // 3/1/2014 - // 10/13/2014 - // 01/02/2006 - // 1/2/06 - - switch r { - case ' ': - p.stateTime = timeStart - if p.yearlen == 0 { - p.yearlen = i - p.yeari - p.setYear() - } else if p.daylen == 0 { - p.daylen = i - p.dayi - p.setDay() - } - break iterRunes - case '/': - if p.yearlen > 0 { - // 2014/07/10 06:55:38.156283 - if p.molen == 0 { - p.molen = i - p.moi - p.setMonth() - p.dayi = i + 1 - } - } else if p.preferMonthFirst { - if p.daylen == 0 { - p.daylen = i - p.dayi - p.setDay() - p.yeari = i + 1 - } - } - } - - case dateDigitWs: - // 18 January 2018 - // 8 January 2018 - // 8 jan 2018 - // 1 jan 18 - // 02 Jan 2018 23:59 - // 02 Jan 2018 23:59:34 - // 12 Feb 2006, 19:17 - // 12 Feb 2006, 19:17:22 - switch r { - case ' ': - p.yeari = i + 1 - //p.yearlen = 4 - p.dayi = 0 - p.daylen = p.part1Len - p.setDay() - p.stateTime = timeStart - if i > p.daylen+len(" Sep") { // November etc - // If len greather than space + 3 it must be full month - p.stateDate = dateDigitWsMolong - } else { - // If len=3, the might be Feb or May? Ie ambigous abbreviated but - // we can parse may with either. BUT, that means the - // format may not be correct? - // mo := strings.ToLower(datestr[p.daylen+1 : i]) - p.moi = p.daylen + 1 - p.molen = i - p.moi - p.set(p.moi, "Jan") - p.stateDate = dateDigitWsMoYear - } - } - - case dateDigitWsMoYear: - // 8 jan 2018 - // 02 Jan 2018 23:59 - // 02 Jan 2018 23:59:34 - // 12 Feb 2006, 19:17 - // 12 Feb 2006, 19:17:22 - switch r { - case ',': - p.yearlen = i - p.yeari - p.setYear() - i++ - break iterRunes - case ' ': - p.yearlen = i - p.yeari - p.setYear() - break iterRunes - } - case dateDigitWsMolong: - // 18 January 2018 - // 8 January 2018 - - case dateDigitChineseYear: - // dateDigitChineseYear - // 2014年04月08日 - // weekday %Y年%m月%e日 %A %I:%M %p - // 2013年07月18日 星期四 10:27 上午 - if r == ' ' { - p.stateDate = dateDigitChineseYearWs - break - } - case dateDigitDot: - // This is the 2nd period - // 3.31.2014 - // 08.21.71 - // 2014.05 - // 2018.09.30 - if r == '.' { - if p.moi == 0 { - // 3.31.2014 - p.daylen = i - p.dayi - p.yeari = i + 1 - p.setDay() - p.stateDate = dateDigitDotDot - } else { - // 2018.09.30 - //p.molen = 2 - p.molen = i - p.moi - p.dayi = i + 1 - p.setMonth() - p.stateDate = dateDigitDotDot - } - } - case dateDigitDotDot: - // iterate all the way through - case dateAlpha: - // dateAlphaWS - // Mon Jan _2 15:04:05 2006 - // Mon Jan _2 15:04:05 MST 2006 - // Mon Jan 02 15:04:05 -0700 2006 - // Mon Aug 10 15:44:11 UTC+0100 2015 - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - // dateAlphaWSDigit - // May 8, 2009 5:57:51 PM - // oct 1, 1970 - // dateAlphaWsMonth - // April 8, 2009 - // dateAlphaWsMore - // dateAlphaWsAtTime - // January 02, 2006 at 3:04pm MST-07 - // - // dateAlphaPeriodWsDigit - // oct. 1, 1970 - // dateWeekdayComma - // Monday, 02 Jan 2006 15:04:05 MST - // Monday, 02-Jan-06 15:04:05 MST - // Monday, 02 Jan 2006 15:04:05 -0700 - // Monday, 02 Jan 2006 15:04:05 +0100 - // dateWeekdayAbbrevComma - // Mon, 02 Jan 2006 15:04:05 MST - // Mon, 02 Jan 2006 15:04:05 -0700 - // Thu, 13 Jul 2017 08:58:40 +0100 - // Tue, 11 Jul 2017 16:28:13 +0200 (CEST) - // Mon, 02-Jan-06 15:04:05 MST - switch { - case r == ' ': - // X - // April 8, 2009 - if i > 3 { - // Check to see if the alpha is name of month? or Day? - month := strings.ToLower(datestr[0:i]) - if isMonthFull(month) { - p.fullMonth = month - // len(" 31, 2018") = 9 - if len(datestr[i:]) < 10 { - // April 8, 2009 - p.stateDate = dateAlphaWsMonth - } else { - p.stateDate = dateAlphaWsMore - } - p.dayi = i + 1 - break - } - - } else { - // This is possibly ambiguous? May will parse as either though. - // So, it could return in-correct format. - // May 05, 2005, 05:05:05 - // May 05 2005, 05:05:05 - // Jul 05, 2005, 05:05:05 - p.stateDate = dateAlphaWs - } - - case r == ',': - // Mon, 02 Jan 2006 - // p.moi = 0 - // p.molen = i - if i == 3 { - p.stateDate = dateWeekdayAbbrevComma - p.set(0, "Mon") - } else { - p.stateDate = dateWeekdayComma - p.skip = i + 2 - i++ - // TODO: lets just make this "skip" as we don't need - // the mon, monday, they are all superfelous and not needed - // just lay down the skip, no need to fill and then skip - } - case r == '.': - // sept. 28, 2017 - // jan. 28, 2017 - p.stateDate = dateAlphaPeriodWsDigit - if i == 3 { - p.molen = i - p.set(0, "Jan") - } else if i == 4 { - // gross - datestr = datestr[0:i-1] + datestr[i:] - return parseTime(datestr, loc) - } else { - return nil, unknownErr(datestr) - } - } - - case dateAlphaWs: - // dateAlphaWsAlpha - // Mon Jan _2 15:04:05 2006 - // Mon Jan _2 15:04:05 MST 2006 - // Mon Jan 02 15:04:05 -0700 2006 - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - // Mon Aug 10 15:44:11 UTC+0100 2015 - // dateAlphaWsDigit - // May 8, 2009 5:57:51 PM - // May 8 2009 5:57:51 PM - // oct 1, 1970 - // oct 7, '70 - switch { - case unicode.IsLetter(r): - p.set(0, "Mon") - p.stateDate = dateAlphaWsAlpha - p.set(i, "Jan") - case unicode.IsDigit(r): - p.set(0, "Jan") - p.stateDate = dateAlphaWsDigit - p.dayi = i - } - - case dateAlphaWsDigit: - // May 8, 2009 5:57:51 PM - // May 8 2009 5:57:51 PM - // oct 1, 1970 - // oct 7, '70 - // oct. 7, 1970 - if r == ',' { - p.daylen = i - p.dayi - p.setDay() - p.stateDate = dateAlphaWsDigitMore - } else if r == ' ' { - p.daylen = i - p.dayi - p.setDay() - p.yeari = i + 1 - p.stateDate = dateAlphaWsDigitMoreWs - } else if unicode.IsLetter(r) { - p.stateDate = dateAlphaWsMonthSuffix - i-- - } - case dateAlphaWsDigitMore: - // x - // May 8, 2009 5:57:51 PM - // May 05, 2005, 05:05:05 - // May 05 2005, 05:05:05 - // oct 1, 1970 - // oct 7, '70 - if r == ' ' { - p.yeari = i + 1 - p.stateDate = dateAlphaWsDigitMoreWs - } - case dateAlphaWsDigitMoreWs: - // x - // May 8, 2009 5:57:51 PM - // May 05, 2005, 05:05:05 - // oct 1, 1970 - // oct 7, '70 - switch r { - case '\'': - p.yeari = i + 1 - case ' ', ',': - // x - // May 8, 2009 5:57:51 PM - // x - // May 8, 2009, 5:57:51 PM - p.stateDate = dateAlphaWsDigitMoreWsYear - p.yearlen = i - p.yeari - p.setYear() - p.stateTime = timeStart - break iterRunes - } - - case dateAlphaWsAlpha: - // Mon Jan _2 15:04:05 2006 - // Mon Jan 02 15:04:05 -0700 2006 - // Mon Jan _2 15:04:05 MST 2006 - // Mon Aug 10 15:44:11 UTC+0100 2015 - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - if r == ' ' { - if p.dayi > 0 { - p.daylen = i - p.dayi - p.setDay() - p.yeari = i + 1 - p.stateDate = dateAlphaWsAlphaYearmaybe - p.stateTime = timeStart - } - } else if unicode.IsDigit(r) { - if p.dayi == 0 { - p.dayi = i - } - } - - case dateAlphaWsAlphaYearmaybe: - // x - // Mon Jan _2 15:04:05 2006 - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - if r == ':' { - i = i - 3 - p.stateDate = dateAlphaWsAlpha - p.yeari = 0 - break iterRunes - } else if r == ' ' { - // must be year format, not 15:04 - p.yearlen = i - p.yeari - p.setYear() - break iterRunes - } - - case dateAlphaWsMonth: - // April 8, 2009 - // April 8 2009 - switch r { - case ' ', ',': - // x - // June 8, 2009 - // x - // June 8 2009 - if p.daylen == 0 { - p.daylen = i - p.dayi - p.setDay() - } - case 's', 'S', 'r', 'R', 't', 'T', 'n', 'N': - // st, rd, nd, st - i-- - p.stateDate = dateAlphaWsMonthSuffix - default: - if p.daylen > 0 && p.yeari == 0 { - p.yeari = i - } - } - case dateAlphaWsMonthMore: - // X - // January 02, 2006, 15:04:05 - // January 02 2006, 15:04:05 - // January 02, 2006 15:04:05 - // January 02 2006 15:04:05 - switch r { - case ',': - p.yearlen = i - p.yeari - p.setYear() - p.stateTime = timeStart - i++ - break iterRunes - case ' ': - p.yearlen = i - p.yeari - p.setYear() - p.stateTime = timeStart - break iterRunes - } - case dateAlphaWsMonthSuffix: - // x - // April 8th, 2009 - // April 8th 2009 - switch r { - case 't', 'T': - if p.nextIs(i, 'h') || p.nextIs(i, 'H') { - if len(datestr) > i+2 { - return parseTime(fmt.Sprintf("%s%s", p.datestr[0:i], p.datestr[i+2:]), loc) - } - } - case 'n', 'N': - if p.nextIs(i, 'd') || p.nextIs(i, 'D') { - if len(datestr) > i+2 { - return parseTime(fmt.Sprintf("%s%s", p.datestr[0:i], p.datestr[i+2:]), loc) - } - } - case 's', 'S': - if p.nextIs(i, 't') || p.nextIs(i, 'T') { - if len(datestr) > i+2 { - return parseTime(fmt.Sprintf("%s%s", p.datestr[0:i], p.datestr[i+2:]), loc) - } - } - case 'r', 'R': - if p.nextIs(i, 'd') || p.nextIs(i, 'D') { - if len(datestr) > i+2 { - return parseTime(fmt.Sprintf("%s%s", p.datestr[0:i], p.datestr[i+2:]), loc) - } - } - } - case dateAlphaWsMore: - // January 02, 2006, 15:04:05 - // January 02 2006, 15:04:05 - // January 2nd, 2006, 15:04:05 - // January 2nd 2006, 15:04:05 - // September 17, 2012 at 5:00pm UTC-05 - switch { - case r == ',': - // x - // January 02, 2006, 15:04:05 - if p.nextIs(i, ' ') { - p.daylen = i - p.dayi - p.setDay() - p.yeari = i + 2 - p.stateDate = dateAlphaWsMonthMore - i++ - } - - case r == ' ': - // x - // January 02 2006, 15:04:05 - p.daylen = i - p.dayi - p.setDay() - p.yeari = i + 1 - p.stateDate = dateAlphaWsMonthMore - case unicode.IsDigit(r): - // XX - // January 02, 2006, 15:04:05 - continue - case unicode.IsLetter(r): - // X - // January 2nd, 2006, 15:04:05 - p.daylen = i - p.dayi - p.setDay() - p.stateDate = dateAlphaWsMonthSuffix - i-- - } - - case dateAlphaPeriodWsDigit: - // oct. 7, '70 - switch { - case r == ' ': - // continue - case unicode.IsDigit(r): - p.stateDate = dateAlphaWsDigit - p.dayi = i - default: - return p, unknownErr(datestr) - } - case dateWeekdayComma: - // Monday, 02 Jan 2006 15:04:05 MST - // Monday, 02 Jan 2006 15:04:05 -0700 - // Monday, 02 Jan 2006 15:04:05 +0100 - // Monday, 02-Jan-06 15:04:05 MST - if p.dayi == 0 { - p.dayi = i - } - switch r { - case ' ', '-': - if p.moi == 0 { - p.moi = i + 1 - p.daylen = i - p.dayi - p.setDay() - } else if p.yeari == 0 { - p.yeari = i + 1 - p.molen = i - p.moi - p.set(p.moi, "Jan") - } else { - p.stateTime = timeStart - break iterRunes - } - } - case dateWeekdayAbbrevComma: - // Mon, 02 Jan 2006 15:04:05 MST - // Mon, 02 Jan 2006 15:04:05 -0700 - // Thu, 13 Jul 2017 08:58:40 +0100 - // Thu, 4 Jan 2018 17:53:36 +0000 - // Tue, 11 Jul 2017 16:28:13 +0200 (CEST) - // Mon, 02-Jan-06 15:04:05 MST - switch r { - case ' ', '-': - if p.dayi == 0 { - p.dayi = i + 1 - } else if p.moi == 0 { - p.daylen = i - p.dayi - p.setDay() - p.moi = i + 1 - } else if p.yeari == 0 { - p.molen = i - p.moi - p.set(p.moi, "Jan") - p.yeari = i + 1 - } else { - p.yearlen = i - p.yeari - p.setYear() - p.stateTime = timeStart - break iterRunes - } - } - - default: - break iterRunes - } - } - p.coalesceDate(i) - if p.stateTime == timeStart { - // increment first one, since the i++ occurs at end of loop - if i < len(p.datestr) { - i++ - } - // ensure we skip any whitespace prefix - for ; i < len(datestr); i++ { - r := rune(datestr[i]) - if r != ' ' { - break - } - } - - iterTimeRunes: - for ; i < len(datestr); i++ { - r := rune(datestr[i]) - - //gou.Debugf("%d %s %d iterTimeRunes %s %s", i, string(r), p.stateTime, p.ds(), p.ts()) - - switch p.stateTime { - case timeStart: - // 22:43:22 - // 22:43 - // timeComma - // 08:20:13,787 - // timeWs - // 05:24:37 PM - // 06:20:00 UTC - // 06:20:00 UTC-05 - // 00:12:00 +0000 UTC - // 22:18:00 +0000 UTC m=+0.000000001 - // 15:04:05 -0700 - // 15:04:05 -07:00 - // 15:04:05 2008 - // timeOffset - // 03:21:51+00:00 - // 19:55:00+0100 - // timePeriod - // 17:24:37.3186369 - // 00:07:31.945167 - // 18:31:59.257000000 - // 00:00:00.000 - // timePeriodOffset - // 19:55:00.799+0100 - // timePeriodOffsetColon - // 15:04:05.999-07:00 - // timePeriodWs - // timePeriodWsOffset - // 00:07:31.945167 +0000 - // 00:00:00.000 +0000 - // timePeriodWsOffsetAlpha - // 00:07:31.945167 +0000 UTC - // 22:18:00.001 +0000 UTC m=+0.000000001 - // 00:00:00.000 +0000 UTC - // timePeriodWsAlpha - // 06:20:00.000 UTC - if p.houri == 0 { - p.houri = i - } - switch r { - case ',': - // hm, lets just swap out comma for period. for some reason go - // won't parse it. - // 2014-05-11 08:20:13,787 - ds := []byte(p.datestr) - ds[i] = '.' - return parseTime(string(ds), loc) - case '-', '+': - // 03:21:51+00:00 - p.stateTime = timeOffset - if p.seci == 0 { - // 22:18+0530 - p.minlen = i - p.mini - } else { - p.seclen = i - p.seci - } - p.offseti = i - case '.': - p.stateTime = timePeriod - p.seclen = i - p.seci - p.msi = i + 1 - case 'Z': - p.stateTime = timeZ - if p.seci == 0 { - p.minlen = i - p.mini - } else { - p.seclen = i - p.seci - } - case 'a', 'A': - if p.nextIs(i, 't') || p.nextIs(i, 'T') { - // x - // September 17, 2012 at 5:00pm UTC-05 - i++ // skip t - if p.nextIs(i, ' ') { - // x - // September 17, 2012 at 5:00pm UTC-05 - i++ // skip ' - p.houri = 0 // reset hour - } - } else { - switch { - case r == 'a' && p.nextIs(i, 'm'): - p.coalesceTime(i) - p.set(i, "am") - case r == 'A' && p.nextIs(i, 'M'): - p.coalesceTime(i) - p.set(i, "PM") - } - } - - case 'p', 'P': - // Could be AM/PM - switch { - case r == 'p' && p.nextIs(i, 'm'): - p.coalesceTime(i) - p.set(i, "pm") - case r == 'P' && p.nextIs(i, 'M'): - p.coalesceTime(i) - p.set(i, "PM") - } - case ' ': - p.coalesceTime(i) - p.stateTime = timeWs - case ':': - if p.mini == 0 { - p.mini = i + 1 - p.hourlen = i - p.houri - } else if p.seci == 0 { - p.seci = i + 1 - p.minlen = i - p.mini - } - } - case timeOffset: - // 19:55:00+0100 - // timeOffsetColon - // 15:04:05+07:00 - // 15:04:05-07:00 - if r == ':' { - p.stateTime = timeOffsetColon - } - case timeWs: - // timeWsAlpha - // 06:20:00 UTC - // 06:20:00 UTC-05 - // 15:44:11 UTC+0100 2015 - // 18:04:07 GMT+0100 (GMT Daylight Time) - // 17:57:51 MST 2009 - // timeWsAMPMMaybe - // 05:24:37 PM - // timeWsOffset - // 15:04:05 -0700 - // 00:12:00 +0000 UTC - // timeWsOffsetColon - // 15:04:05 -07:00 - // 17:57:51 -0700 2009 - // timeWsOffsetColonAlpha - // 00:12:00 +00:00 UTC - // timeWsYear - // 00:12:00 2008 - // timeZ - // 15:04:05.99Z - switch r { - case 'A', 'P': - // Could be AM/PM or could be PST or similar - p.tzi = i - p.stateTime = timeWsAMPMMaybe - case '+', '-': - p.offseti = i - p.stateTime = timeWsOffset - default: - if unicode.IsLetter(r) { - // 06:20:00 UTC - // 06:20:00 UTC-05 - // 15:44:11 UTC+0100 2015 - // 17:57:51 MST 2009 - p.tzi = i - p.stateTime = timeWsAlpha - //break iterTimeRunes - } else if unicode.IsDigit(r) { - // 00:12:00 2008 - p.stateTime = timeWsYear - p.yeari = i - } - } - case timeWsAlpha: - // 06:20:00 UTC - // 06:20:00 UTC-05 - // timeWsAlphaWs - // 17:57:51 MST 2009 - // timeWsAlphaZoneOffset - // timeWsAlphaZoneOffsetWs - // timeWsAlphaZoneOffsetWsExtra - // 18:04:07 GMT+0100 (GMT Daylight Time) - // timeWsAlphaZoneOffsetWsYear - // 15:44:11 UTC+0100 2015 - switch r { - case '+', '-': - p.tzlen = i - p.tzi - if p.tzlen == 4 { - p.set(p.tzi, " MST") - } else if p.tzlen == 3 { - p.set(p.tzi, "MST") - } - p.stateTime = timeWsAlphaZoneOffset - p.offseti = i - case ' ': - // 17:57:51 MST 2009 - p.tzlen = i - p.tzi - if p.tzlen == 4 { - p.set(p.tzi, " MST") - } else if p.tzlen == 3 { - p.set(p.tzi, "MST") - } - p.stateTime = timeWsAlphaWs - p.yeari = i + 1 - } - case timeWsAlphaWs: - // 17:57:51 MST 2009 - - case timeWsAlphaZoneOffset: - // 06:20:00 UTC-05 - // timeWsAlphaZoneOffset - // timeWsAlphaZoneOffsetWs - // timeWsAlphaZoneOffsetWsExtra - // 18:04:07 GMT+0100 (GMT Daylight Time) - // timeWsAlphaZoneOffsetWsYear - // 15:44:11 UTC+0100 2015 - switch r { - case ' ': - p.set(p.offseti, "-0700") - p.yeari = i + 1 - p.stateTime = timeWsAlphaZoneOffsetWs - } - case timeWsAlphaZoneOffsetWs: - // timeWsAlphaZoneOffsetWs - // timeWsAlphaZoneOffsetWsExtra - // 18:04:07 GMT+0100 (GMT Daylight Time) - // timeWsAlphaZoneOffsetWsYear - // 15:44:11 UTC+0100 2015 - if unicode.IsDigit(r) { - p.stateTime = timeWsAlphaZoneOffsetWsYear - } else { - p.extra = i - 1 - p.stateTime = timeWsAlphaZoneOffsetWsExtra - } - case timeWsAlphaZoneOffsetWsYear: - // 15:44:11 UTC+0100 2015 - if unicode.IsDigit(r) { - p.yearlen = i - p.yeari + 1 - if p.yearlen == 4 { - p.setYear() - } - } - case timeWsAMPMMaybe: - // timeWsAMPMMaybe - // timeWsAMPM - // 05:24:37 PM - // timeWsAlpha - // 00:12:00 PST - // 15:44:11 UTC+0100 2015 - if r == 'M' { - //return parse("2006-01-02 03:04:05 PM", datestr, loc) - p.stateTime = timeWsAMPM - p.set(i-1, "PM") - if p.hourlen == 2 { - p.set(p.houri, "03") - } else if p.hourlen == 1 { - p.set(p.houri, "3") - } - } else { - p.stateTime = timeWsAlpha - } - - case timeWsOffset: - // timeWsOffset - // 15:04:05 -0700 - // timeWsOffsetWsOffset - // 17:57:51 -0700 -07 - // timeWsOffsetWs - // 17:57:51 -0700 2009 - // 00:12:00 +0000 UTC - // timeWsOffsetColon - // 15:04:05 -07:00 - // timeWsOffsetColonAlpha - // 00:12:00 +00:00 UTC - switch r { - case ':': - p.stateTime = timeWsOffsetColon - case ' ': - p.set(p.offseti, "-0700") - p.yeari = i + 1 - p.stateTime = timeWsOffsetWs - } - case timeWsOffsetWs: - // 17:57:51 -0700 2009 - // 00:12:00 +0000 UTC - // 22:18:00.001 +0000 UTC m=+0.000000001 - // w Extra - // 17:57:51 -0700 -07 - switch r { - case '=': - // eff you golang - if datestr[i-1] == 'm' { - p.extra = i - 2 - p.trimExtra() - break - } - case '+', '-': - // This really doesn't seem valid, but for some reason when round-tripping a go date - // their is an extra +03 printed out. seems like go bug to me, but, parsing anyway. - // 00:00:00 +0300 +03 - // 00:00:00 +0300 +0300 - p.extra = i - 1 - p.stateTime = timeWsOffset - p.trimExtra() - break - default: - switch { - case unicode.IsDigit(r): - p.yearlen = i - p.yeari + 1 - if p.yearlen == 4 { - p.setYear() - } - case unicode.IsLetter(r): - if p.tzi == 0 { - p.tzi = i - } - } - } - - case timeWsOffsetColon: - // timeWsOffsetColon - // 15:04:05 -07:00 - // timeWsOffsetColonAlpha - // 2015-02-18 00:12:00 +00:00 UTC - if unicode.IsLetter(r) { - // 2015-02-18 00:12:00 +00:00 UTC - p.stateTime = timeWsOffsetColonAlpha - break iterTimeRunes - } - case timePeriod: - // 15:04:05.999999999+07:00 - // 15:04:05.999999999-07:00 - // 15:04:05.999999+07:00 - // 15:04:05.999999-07:00 - // 15:04:05.999+07:00 - // 15:04:05.999-07:00 - // timePeriod - // 17:24:37.3186369 - // 00:07:31.945167 - // 18:31:59.257000000 - // 00:00:00.000 - // timePeriodOffset - // 19:55:00.799+0100 - // timePeriodOffsetColon - // 15:04:05.999-07:00 - // timePeriodWs - // timePeriodWsOffset - // 00:07:31.945167 +0000 - // 00:00:00.000 +0000 - // With Extra - // 00:00:00.000 +0300 +03 - // timePeriodWsOffsetAlpha - // 00:07:31.945167 +0000 UTC - // 00:00:00.000 +0000 UTC - // 22:18:00.001 +0000 UTC m=+0.000000001 - // timePeriodWsAlpha - // 06:20:00.000 UTC - switch r { - case ' ': - p.mslen = i - p.msi - p.stateTime = timePeriodWs - case '+', '-': - // This really shouldn't happen - p.mslen = i - p.msi - p.offseti = i - p.stateTime = timePeriodOffset - default: - if unicode.IsLetter(r) { - // 06:20:00.000 UTC - p.mslen = i - p.msi - p.stateTime = timePeriodWsAlpha - } - } - case timePeriodOffset: - // timePeriodOffset - // 19:55:00.799+0100 - // timePeriodOffsetColon - // 15:04:05.999-07:00 - // 13:31:51.999-07:00 MST - if r == ':' { - p.stateTime = timePeriodOffsetColon - } - case timePeriodOffsetColon: - // timePeriodOffset - // timePeriodOffsetColon - // 15:04:05.999-07:00 - // 13:31:51.999 -07:00 MST - switch r { - case ' ': - p.set(p.offseti, "-07:00") - p.stateTime = timePeriodOffsetColonWs - p.tzi = i + 1 - } - case timePeriodOffsetColonWs: - // continue - case timePeriodWs: - // timePeriodWs - // timePeriodWsOffset - // 00:07:31.945167 +0000 - // 00:00:00.000 +0000 - // timePeriodWsOffsetAlpha - // 00:07:31.945167 +0000 UTC - // 00:00:00.000 +0000 UTC - // timePeriodWsOffsetColon - // 13:31:51.999 -07:00 MST - // timePeriodWsAlpha - // 06:20:00.000 UTC - if p.offseti == 0 { - p.offseti = i - } - switch r { - case '+', '-': - p.mslen = i - p.msi - 1 - p.stateTime = timePeriodWsOffset - default: - if unicode.IsLetter(r) { - // 00:07:31.945167 +0000 UTC - // 00:00:00.000 +0000 UTC - p.stateTime = timePeriodWsOffsetWsAlpha - break iterTimeRunes - } - } - - case timePeriodWsOffset: - // timePeriodWs - // timePeriodWsOffset - // 00:07:31.945167 +0000 - // 00:00:00.000 +0000 - // With Extra - // 00:00:00.000 +0300 +03 - // timePeriodWsOffsetAlpha - // 00:07:31.945167 +0000 UTC - // 00:00:00.000 +0000 UTC - // 03:02:00.001 +0300 MSK m=+0.000000001 - // timePeriodWsOffsetColon - // 13:31:51.999 -07:00 MST - // timePeriodWsAlpha - // 06:20:00.000 UTC - switch r { - case ':': - p.stateTime = timePeriodWsOffsetColon - case ' ': - p.set(p.offseti, "-0700") - case '+', '-': - // This really doesn't seem valid, but for some reason when round-tripping a go date - // their is an extra +03 printed out. seems like go bug to me, but, parsing anyway. - // 00:00:00.000 +0300 +03 - // 00:00:00.000 +0300 +0300 - p.extra = i - 1 - p.trimExtra() - break - default: - if unicode.IsLetter(r) { - // 00:07:31.945167 +0000 UTC - // 00:00:00.000 +0000 UTC - // 03:02:00.001 +0300 MSK m=+0.000000001 - p.stateTime = timePeriodWsOffsetWsAlpha - } - } - case timePeriodWsOffsetWsAlpha: - // 03:02:00.001 +0300 MSK m=+0.000000001 - // eff you golang - if r == '=' && datestr[i-1] == 'm' { - p.extra = i - 2 - p.trimExtra() - break - } - - case timePeriodWsOffsetColon: - // 13:31:51.999 -07:00 MST - switch r { - case ' ': - p.set(p.offseti, "-07:00") - default: - if unicode.IsLetter(r) { - // 13:31:51.999 -07:00 MST - p.tzi = i - p.stateTime = timePeriodWsOffsetColonAlpha - } - } - case timePeriodWsOffsetColonAlpha: - // continue - case timeZ: - // timeZ - // 15:04:05.99Z - // With a time-zone at end after Z - // 2006-01-02T15:04:05.999999999Z07:00 - // 2006-01-02T15:04:05Z07:00 - // RFC3339 = "2006-01-02T15:04:05Z07:00" - // RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" - if unicode.IsDigit(r) { - p.stateTime = timeZDigit - } - - } - } - - switch p.stateTime { - case timeWsAlphaWs: - p.yearlen = i - p.yeari - p.setYear() - case timeWsYear: - p.yearlen = i - p.yeari - p.setYear() - case timeWsAlphaZoneOffsetWsExtra: - p.trimExtra() - case timeWsAlphaZoneOffset: - // 06:20:00 UTC-05 - if i-p.offseti < 4 { - p.set(p.offseti, "-07") - } else { - p.set(p.offseti, "-0700") - } - - case timePeriod: - p.mslen = i - p.msi - case timeOffset: - // 19:55:00+0100 - p.set(p.offseti, "-0700") - case timeWsOffset: - p.set(p.offseti, "-0700") - case timeWsOffsetWs: - // 17:57:51 -0700 2009 - // 00:12:00 +0000 UTC - case timeWsOffsetColon: - // 17:57:51 -07:00 - p.set(p.offseti, "-07:00") - case timeOffsetColon: - // 15:04:05+07:00 - p.set(p.offseti, "-07:00") - case timePeriodOffset: - // 19:55:00.799+0100 - p.set(p.offseti, "-0700") - case timePeriodOffsetColon: - p.set(p.offseti, "-07:00") - case timePeriodWsOffsetColonAlpha: - p.tzlen = i - p.tzi - switch p.tzlen { - case 3: - p.set(p.tzi, "MST") - case 4: - p.set(p.tzi, "MST ") - } - case timePeriodWsOffset: - p.set(p.offseti, "-0700") - } - p.coalesceTime(i) - } - - switch p.stateDate { - case dateDigit: - // unixy timestamps ish - // example ct type - // 1499979655583057426 19 nanoseconds - // 1499979795437000 16 micro-seconds - // 20180722105203 14 yyyyMMddhhmmss - // 1499979795437 13 milliseconds - // 1332151919 10 seconds - // 20140601 8 yyyymmdd - // 2014 4 yyyy - t := time.Time{} - if len(datestr) == len("1499979655583057426") { // 19 - // nano-seconds - if nanoSecs, err := strconv.ParseInt(datestr, 10, 64); err == nil { - t = time.Unix(0, nanoSecs) - } - } else if len(datestr) == len("1499979795437000") { // 16 - // micro-seconds - if microSecs, err := strconv.ParseInt(datestr, 10, 64); err == nil { - t = time.Unix(0, microSecs*1000) - } - } else if len(datestr) == len("yyyyMMddhhmmss") { // 14 - // yyyyMMddhhmmss - p.format = []byte("20060102150405") - return p, nil - } else if len(datestr) == len("1332151919000") { // 13 - if miliSecs, err := strconv.ParseInt(datestr, 10, 64); err == nil { - t = time.Unix(0, miliSecs*1000*1000) - } - } else if len(datestr) == len("1332151919") { //10 - if secs, err := strconv.ParseInt(datestr, 10, 64); err == nil { - t = time.Unix(secs, 0) - } - } else if len(datestr) == len("20140601") { - p.format = []byte("20060102") - return p, nil - } else if len(datestr) == len("2014") { - p.format = []byte("2006") - return p, nil - } else if len(datestr) < 4 { - return nil, fmt.Errorf("unrecognized format, too short %v", datestr) - } - if !t.IsZero() { - if loc == nil { - p.t = &t - return p, nil - } - t = t.In(loc) - p.t = &t - return p, nil - } - - case dateYearDash: - // 2006-01 - return p, nil - - case dateYearDashDash: - // 2006-01-02 - // 2006-1-02 - // 2006-1-2 - // 2006-01-2 - return p, nil - - case dateYearDashAlphaDash: - // 2013-Feb-03 - // 2013-Feb-3 - p.daylen = i - p.dayi - p.setDay() - return p, nil - - case dateYearDashDashWs: - // 2013-04-01 - return p, nil - - case dateYearDashDashT: - return p, nil - - case dateDigitDashAlphaDash: - // 13-Feb-03 ambiguous - // 28-Feb-03 ambiguous - // 29-Jun-2016 - length := len(datestr) - (p.moi + p.molen + 1) - if length == 4 { - p.yearlen = 4 - p.set(p.yeari, "2006") - // We now also know that part1 was the day - p.dayi = 0 - p.daylen = p.part1Len - p.setDay() - } else if length == 2 { - // We have no idea if this is - // yy-mon-dd OR dd-mon-yy - // - // We are going to ASSUME (bad, bad) that it is dd-mon-yy which is a horible assumption - p.ambiguousMD = true - p.yearlen = 2 - p.set(p.yeari, "06") - // We now also know that part1 was the day - p.dayi = 0 - p.daylen = p.part1Len - p.setDay() - } - - return p, nil - - case dateDigitDot: - // 2014.05 - p.molen = i - p.moi - p.setMonth() - return p, nil - - case dateDigitDotDot: - // 03.31.1981 - // 3.31.2014 - // 3.2.1981 - // 3.2.81 - // 08.21.71 - // 2018.09.30 - return p, nil - - case dateDigitWsMoYear: - // 2 Jan 2018 - // 2 Jan 18 - // 2 Jan 2018 23:59 - // 02 Jan 2018 23:59 - // 12 Feb 2006, 19:17 - return p, nil - - case dateDigitWsMolong: - // 18 January 2018 - // 8 January 2018 - if p.daylen == 2 { - p.format = []byte("02 January 2006") - return p, nil - } - p.format = []byte("2 January 2006") - return p, nil // parse("2 January 2006", datestr, loc) - - case dateAlphaWsMonth: - p.yearlen = i - p.yeari - p.setYear() - return p, nil - - case dateAlphaWsMonthMore: - return p, nil - - case dateAlphaWsDigitMoreWs: - // oct 1, 1970 - p.yearlen = i - p.yeari - p.setYear() - return p, nil - - case dateAlphaWsDigitMoreWsYear: - // May 8, 2009 5:57:51 PM - // Jun 7, 2005, 05:57:51 - return p, nil - - case dateAlphaWsAlpha: - return p, nil - - case dateAlphaWsAlphaYearmaybe: - return p, nil - - case dateDigitSlash: - // 3/1/2014 - // 10/13/2014 - // 01/02/2006 - // 2014/10/13 - return p, nil - - case dateDigitChineseYear: - // dateDigitChineseYear - // 2014年04月08日 - p.format = []byte("2006年01月02日") - return p, nil - - case dateDigitChineseYearWs: - p.format = []byte("2006年01月02日 15:04:05") - return p, nil - - case dateWeekdayComma: - // Monday, 02 Jan 2006 15:04:05 -0700 - // Monday, 02 Jan 2006 15:04:05 +0100 - // Monday, 02-Jan-06 15:04:05 MST - return p, nil - - case dateWeekdayAbbrevComma: - // Mon, 02-Jan-06 15:04:05 MST - // Mon, 02 Jan 2006 15:04:05 MST - return p, nil - - } - - return nil, unknownErr(datestr) -} - -type parser struct { - loc *time.Location - preferMonthFirst bool - ambiguousMD bool - stateDate dateState - stateTime timeState - format []byte - datestr string - fullMonth string - skip int - extra int - part1Len int - yeari int - yearlen int - moi int - molen int - dayi int - daylen int - houri int - hourlen int - mini int - minlen int - seci int - seclen int - msi int - mslen int - offseti int - offsetlen int - tzi int - tzlen int - t *time.Time -} - -func newParser(dateStr string, loc *time.Location) *parser { - p := parser{ - stateDate: dateStart, - stateTime: timeIgnore, - datestr: dateStr, - loc: loc, - preferMonthFirst: true, - } - p.format = []byte(dateStr) - return &p -} - -func (p *parser) nextIs(i int, b byte) bool { - if len(p.datestr) > i+1 && p.datestr[i+1] == b { - return true - } - return false -} - -func (p *parser) set(start int, val string) { - if start < 0 { - return - } - if len(p.format) < start+len(val) { - return - } - for i, r := range val { - p.format[start+i] = byte(r) - } -} -func (p *parser) setMonth() { - if p.molen == 2 { - p.set(p.moi, "01") - } else if p.molen == 1 { - p.set(p.moi, "1") - } -} - -func (p *parser) setDay() { - if p.daylen == 2 { - p.set(p.dayi, "02") - } else if p.daylen == 1 { - p.set(p.dayi, "2") - } -} -func (p *parser) setYear() { - if p.yearlen == 2 { - p.set(p.yeari, "06") - } else if p.yearlen == 4 { - p.set(p.yeari, "2006") - } -} -func (p *parser) coalesceDate(end int) { - if p.yeari > 0 { - if p.yearlen == 0 { - p.yearlen = end - p.yeari - } - p.setYear() - } - if p.moi > 0 && p.molen == 0 { - p.molen = end - p.moi - p.setMonth() - } - if p.dayi > 0 && p.daylen == 0 { - p.daylen = end - p.dayi - p.setDay() - } -} -func (p *parser) ts() string { - return fmt.Sprintf("h:(%d:%d) m:(%d:%d) s:(%d:%d)", p.houri, p.hourlen, p.mini, p.minlen, p.seci, p.seclen) -} -func (p *parser) ds() string { - return fmt.Sprintf("%s d:(%d:%d) m:(%d:%d) y:(%d:%d)", p.datestr, p.dayi, p.daylen, p.moi, p.molen, p.yeari, p.yearlen) -} -func (p *parser) coalesceTime(end int) { - // 03:04:05 - // 15:04:05 - // 3:04:05 - // 3:4:5 - // 15:04:05.00 - if p.houri > 0 { - if p.hourlen == 2 { - p.set(p.houri, "15") - } else if p.hourlen == 1 { - p.set(p.houri, "3") - } - } - if p.mini > 0 { - if p.minlen == 0 { - p.minlen = end - p.mini - } - if p.minlen == 2 { - p.set(p.mini, "04") - } else { - p.set(p.mini, "4") - } - } - if p.seci > 0 { - if p.seclen == 0 { - p.seclen = end - p.seci - } - if p.seclen == 2 { - p.set(p.seci, "05") - } else { - p.set(p.seci, "5") - } - } - - if p.msi > 0 { - for i := 0; i < p.mslen; i++ { - p.format[p.msi+i] = '0' - } - } -} -func (p *parser) setFullMonth(month string) { - if p.moi == 0 { - p.format = []byte(fmt.Sprintf("%s%s", "January", p.format[len(month):])) - } -} - -func (p *parser) trimExtra() { - if p.extra > 0 && len(p.format) > p.extra { - p.format = p.format[0:p.extra] - p.datestr = p.datestr[0:p.extra] - } -} - -// func (p *parser) remove(i, length int) { -// if len(p.format) > i+length { -// //append(a[:i], a[j:]...) -// p.format = append(p.format[0:i], p.format[i+length:]...) -// } -// if len(p.datestr) > i+length { -// //append(a[:i], a[j:]...) -// p.datestr = fmt.Sprintf("%s%s", p.datestr[0:i], p.datestr[i+length:]) -// } -// } - -func (p *parser) parse() (time.Time, error) { - if p.t != nil { - return *p.t, nil - } - if len(p.fullMonth) > 0 { - p.setFullMonth(p.fullMonth) - } - if p.skip > 0 && len(p.format) > p.skip { - p.format = p.format[p.skip:] - p.datestr = p.datestr[p.skip:] - } - //gou.Debugf("parse %q AS %q", p.datestr, string(p.format)) - if p.loc == nil { - return time.Parse(string(p.format), p.datestr) - } - return time.ParseInLocation(string(p.format), p.datestr, p.loc) -} -func isMonthFull(alpha string) bool { - for _, month := range months { - if alpha == month { - return true - } - } - return false -} |