diff --git a/README.md b/README.md index a1d4bc6..26cbe7c 100644 --- a/README.md +++ b/README.md @@ -62,6 +62,8 @@ import ( var examples = []string{ "May 8, 2009 5:57:51 PM", + "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", @@ -74,6 +76,8 @@ var examples = []string{ "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", "12 Feb 2006, 19:17", "12 Feb 2006 19:17", + "7 oct 70", + "7 oct 1970", "03 February 2013", "2013-Feb-03", // mm/dd/yy @@ -176,6 +180,8 @@ func main() { | 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 | | 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 | @@ -188,6 +194,8 @@ func main() { | Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) | 2015-07-03 18:04:07 +0100 GMT | | 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 | | 2013-Feb-03 | 2013-02-03 00:00:00 +0000 UTC | | 3/31/2014 | 2014-03-31 00:00:00 +0000 UTC | @@ -228,7 +236,7 @@ func main() { | 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:44 +09:00 | 2014-04-26 13:13:44 +0900 +0900 | +| 2014-04-26 13:13:44 +09:00 | 2014-04-26 13:13:44 +0000 UTC | | 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 | diff --git a/bench_test.go b/bench_test.go index 5b8e1b8..f30eb98 100644 --- a/bench_test.go +++ b/bench_test.go @@ -13,6 +13,10 @@ go test -bench Parse BenchmarkShotgunParse 50000 37588 ns/op 13258 B/op 167 allocs/op BenchmarkDateparseParseAny 500000 5752 ns/op 0 B/op 0 allocs/op +// Aarons Laptop Lenovo 900 Feb 2018 +BenchmarkShotgunParse-4 50000 30045 ns/op 13136 B/op 169 allocs/op +BenchmarkParseAny-4 200000 8627 ns/op 144 B/op 3 allocs/op + */ func BenchmarkShotgunParse(b *testing.B) { b.ReportAllocs() diff --git a/dateparse/main.go b/dateparse/main.go index b052f13..78d4ba4 100644 --- a/dateparse/main.go +++ b/dateparse/main.go @@ -105,7 +105,7 @@ func parseAny(datestr string, loc *time.Location, utc bool) string { return err.Error() } if utc { - return t.In(time.UTC).String() + return fmt.Sprintf("%s day=%d", t.In(time.UTC), t.In(time.UTC).Weekday()) } return t.String() } diff --git a/example/main.go b/example/main.go index fd70f0a..4e10c9e 100644 --- a/example/main.go +++ b/example/main.go @@ -11,6 +11,8 @@ import ( var examples = []string{ "May 8, 2009 5:57:51 PM", + "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", @@ -23,6 +25,8 @@ var examples = []string{ "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", "12 Feb 2006, 19:17", "12 Feb 2006 19:17", + "7 oct 70", + "7 oct 1970", "03 February 2013", "2013-Feb-03", // mm/dd/yy @@ -125,6 +129,8 @@ func main() { | 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 | | 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 | @@ -137,6 +143,8 @@ func main() { | Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) | 2015-07-03 18:04:07 +0100 GMT | | 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 | | 2013-Feb-03 | 2013-02-03 00:00:00 +0000 UTC | | 3/31/2014 | 2014-03-31 00:00:00 +0000 UTC | @@ -177,7 +185,7 @@ func main() { | 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:44 +09:00 | 2014-04-26 13:13:44 +0900 +0900 | +| 2014-04-26 13:13:44 +09:00 | 2014-04-26 13:13:44 +0000 UTC | | 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 | diff --git a/parseany.go b/parseany.go index f33719b..5bf1fb2 100644 --- a/parseany.go +++ b/parseany.go @@ -11,62 +11,71 @@ import ( "unicode/utf8" ) -type dateState int +type dateState uint8 +type timeState uint8 const ( - stateStart dateState = iota - stateDigit - stateDigitDash - stateDigitDashAlpha - stateDigitDashWs - stateDigitDashWsWs - stateDigitDashWsWsAMPMMaybe - stateDigitDashWsWsOffset - stateDigitDashWsWsOffsetAlpha - stateDigitDashWsWsOffsetColonAlpha - stateDigitDashWsWsOffsetColon - stateDigitDashWsOffset - stateDigitDashWsWsAlpha - stateDigitDashWsPeriod - stateDigitDashWsPeriodAlpha - stateDigitDashWsPeriodOffset - stateDigitDashWsPeriodOffsetAlpha - stateDigitDashT - stateDigitDashTZ - stateDigitDashTZDigit - stateDigitDashTOffset - stateDigitDashTOffsetColon - stateDigitDot - stateDigitDotDot - stateDigitSlash - stateDigitSlashWS - stateDigitSlashWSColon - stateDigitSlashWSColonAMPM - stateDigitSlashWSColonColon - stateDigitSlashWSColonColonAMPM - stateDigitChineseYear - stateDigitChineseYearWs - stateDigitWs - stateDigitWsMoShort - stateDigitWsMoShortColon - stateDigitWsMoShortColonColon - stateDigitWsMoShortComma - stateAlpha - stateAlphaWS - stateAlphaWSDigitComma - stateAlphaWSAlpha - stateAlphaWSAlphaColon - stateAlphaWSAlphaColonOffset - stateAlphaWSAlphaColonAlpha - stateAlphaWSAlphaColonAlphaOffset - stateAlphaWSAlphaColonAlphaOffsetAlpha - stateWeekdayComma - stateWeekdayCommaDash - stateWeekdayCommaOffset - stateWeekdayAbbrevComma - stateWeekdayAbbrevCommaDash - stateWeekdayAbbrevCommaOffset - stateWeekdayAbbrevCommaOffsetZone + dateStart dateState = iota + dateDigit + dateDigitDash + dateDigitDashDash + dateDigitDashDashWs + dateDigitDashDashT + dateDigitDashDashAlpha + dateDigitDot + dateDigitDotDot + dateDigitSlash + dateDigitChineseYear + dateDigitChineseYearWs + dateDigitWs + dateDigitWsMoYear + dateDigitWsMolong + dateAlpha + dateAlphaWs + dateAlphaWsDigit + dateAlphaWsDigitComma + dateAlphaWsDigitCommaWs + dateAlphaWsDigitCommaWsYear + dateAlphaWsAlpha + dateAlphaWsAlphaYearmaybe + dateWeekdayComma + dateWeekdayAbbrevComma + //dateWeekdayAbbrevCommaDash +) +const ( + // Time state + timeIgnore timeState = iota + timeStart + timeWs + timeWsAlpha + timeWsAlphaWs + timeWsAlphaZoneOffset + timeWsAlphaZoneOffsetWs + timeWsAlphaZoneOffsetWsYear + timeWsAlphaZoneOffsetWsExtra + timeWsAMPMMaybe + timeWsAMPM + timeWsOffset + timeWsOffsetWs + timeWsOffsetColonAlpha + timeWsOffsetColon + timeWsYear + timeOffset + timeOffsetColon + timeAlpha + timePeriod + timePeriodOffset + timePeriodOffsetColon + timePeriodOffsetColonWs + timePeriodWs + timePeriodWsAlpha + timePeriodWsOffset + timePeriodWsOffsetWs + timePeriodWsOffsetWsAlpha + timePeriodWsOffsetColon + timePeriodWsOffsetColonAlpha + timeZ + timeZDigit ) var ( @@ -124,64 +133,254 @@ func parse(layout, datestr string, loc *time.Location) (time.Time, error) { return time.ParseInLocation(layout, datestr, loc) } -func parseTime(datestr string, loc *time.Location) (time.Time, error) { - state := stateStart +type parser struct { + loc *time.Location + preferMonthFirst bool + stateDate dateState + stateTime timeState + format []byte + datestr 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 +} - part1Len := 0 - part2Len := 0 - part3Len := 0 +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) 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) 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) parse() (time.Time, error) { + 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 %s", 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 parseTime(datestr string, loc *time.Location) (time.Time, 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 := 0; i < len(datestr); i++ { + for ; i < len(datestr); i++ { //r := rune(datestr[i]) r, bytesConsumed := utf8.DecodeRuneInString(datestr[i:]) if bytesConsumed > 1 { i += (bytesConsumed - 1) } - switch state { - case stateStart: + switch p.stateDate { + case dateStart: if unicode.IsDigit(r) { - state = stateDigit + p.stateDate = dateDigit } else if unicode.IsLetter(r) { - state = stateAlpha - } - case stateDigit: // starts digits - if unicode.IsDigit(r) { - continue - } else if unicode.IsLetter(r) { - if r == '年' { - // Chinese Year - state = stateDigitChineseYear - } + p.stateDate = dateAlpha } + case dateDigit: + switch r { case '-', '\u2212': - state = stateDigitDash - part1Len = i + // 2006-01-02 + // 2006-01-02T15:04:05Z07:00 + // 13-Feb-03 + // 2013-Feb-03 + p.stateDate = dateDigitDash + p.yeari = 0 + p.yearlen = i + p.moi = i + 1 + if i == 4 { + p.set(0, "2006") + } case '/': - state = stateDigitSlash - part1Len = i - case '.': - state = stateDigitDot - part1Len = i - case ' ': - state = stateDigitWs - part1Len = i - } + // 03/31/2005 + // 2014/02/24 + p.stateDate = dateDigitSlash + if i == 4 { + p.yearlen = i + p.moi = i + 1 + p.setYear() + } else { + if p.preferMonthFirst { + if p.molen == 0 { + p.molen = i + p.setMonth() + p.dayi = i + 1 + } + } + } - case stateDigitDash: // starts digit then dash 02- + case '.': + // 3.31.2014 + p.moi = 0 + p.molen = i + p.setMonth() + p.dayi = i + 1 + p.stateDate = dateDigitDot + 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 + default: + //if unicode.IsDigit(r) { + continue + } + p.part1Len = i + + case dateDigitDash: + // 2006-01 // 2006-01-02 - // stateDigitDashT + // dateDigitDashDashT // 2006-01-02T15:04:05Z07:00 // 2017-06-25T17:46:57.45706582-07:00 // 2006-01-02T15:04:05.999999999Z07:00 // 2006-01-02T15:04:05+0000 - // stateDigitDashWs + // dateDigitDashDashWs // 2012-08-03 18:31:59.257000000 // 2014-04-26 17:24:37.3186369 // 2017-01-27 00:07:31.945167 @@ -190,197 +389,63 @@ iterRunes: // 2017-07-19 03:21:51+00:00 // 2013-04-01 22:43:22 // 2014-04-26 05:24:37 PM - // stateDigitDashAlpha + // dateDigitDashDashAlpha // 2013-Feb-03 - switch { - case r == '-': - part2Len = i - part1Len - 1 - case r == ' ': - part3Len = i - part1Len - part2Len - 1 - 1 - state = stateDigitDashWs - case r == 'T': - state = stateDigitDashT + // 13-Feb-03 + switch r { + case '-': + p.molen = i - p.moi + p.dayi = i + 1 + p.stateDate = dateDigitDashDash + p.setMonth() default: - if unicode.IsLetter(r) { - state = stateDigitDashAlpha - break iterRunes + if unicode.IsDigit(r) { + //continue + } else if unicode.IsLetter(r) { + p.stateDate = dateDigitDashDashAlpha } } - case stateDigitDashWs: - // 2013-04-01 22:43:22 - // 2014-05-11 08:20:13,787 - // stateDigitDashWsWs - // 2014-04-26 05:24:37 PM - // 2014-12-16 06:20:00 UTC - // 2015-02-18 00:12:00 +0000 UTC - // 2006-01-02 15:04:05 -0700 - // 2006-01-02 15:04:05 -07:00 - // stateDigitDashWsOffset - // 2017-07-19 03:21:51+00:00 - // stateDigitDashWsPeriod - // 2014-04-26 17:24:37.3186369 - // 2017-01-27 00:07:31.945167 - // 2012-08-03 18:31:59.257000000 - // 2016-03-14 00:00:00.000 - // stateDigitDashWsPeriodOffset - // 2017-01-27 00:07:31.945167 +0000 - // 2016-03-14 00:00:00.000 +0000 - // stateDigitDashWsPeriodOffsetAlpha - // 2017-01-27 00:07:31.945167 +0000 UTC - // 2016-03-14 00:00:00.000 +0000 UTC - // stateDigitDashWsPeriodAlpha - // 2014-12-16 06:20:00.000 UTC + case dateDigitDashDash: + // 2006-01-02 + // dateDigitDashDashT + // 2006-01-02T15:04:05Z07:00 + // 2017-06-25T17:46:57.45706582-07:00 + // 2006-01-02T15:04:05.999999999Z07:00 + // 2006-01-02T15:04:05+0000 + // dateDigitDashDashWs + // 2012-08-03 18:31:59.257000000 + // 2014-04-26 17:24:37.3186369 + // 2017-01-27 00:07:31.945167 + // 2016-03-14 00:00:00.000 + // 2014-05-11 08:20:13,787 + // 2017-07-19 03:21:51+00:00 + // 2013-04-01 22:43:22 + // 2014-04-26 05:24:37 PM + switch r { - case ',': - if len(datestr) == len("2014-05-11 08:20:13,787") { - // go doesn't seem to parse this one natively? or did i miss it? - t, err := parse("2006-01-02 03:04:05", datestr[:i], loc) - if err == nil { - ms, err := strconv.Atoi(datestr[i+1:]) - if err == nil { - return time.Unix(0, t.UnixNano()+int64(ms)*1e6), nil - } - } - return t, err - } - case '-', '+': - state = stateDigitDashWsOffset - case '.': - state = stateDigitDashWsPeriod case ' ': - state = stateDigitDashWsWs + p.daylen = i - p.dayi + p.stateDate = dateDigitDashDashWs + p.stateTime = timeStart + p.setDay() + break iterRunes + case 'T': + p.daylen = i - p.dayi + p.stateDate = dateDigitDashDashT + p.stateTime = timeStart + p.setDay() + break iterRunes } - - case stateDigitDashWsWs: - // stateDigitDashWsWsAlpha - // 2014-12-16 06:20:00 UTC - // stateDigitDashWsWsAMPMMaybe - // 2014-04-26 05:24:37 PM - // stateDigitDashWsWsOffset - // 2006-01-02 15:04:05 -0700 - // stateDigitDashWsWsOffsetColon - // 2006-01-02 15:04:05 -07:00 - // stateDigitDashWsWsOffsetColonAlpha - // 2015-02-18 00:12:00 +00:00 UTC - // stateDigitDashWsWsOffsetAlpha - // 2015-02-18 00:12:00 +0000 UTC + case dateDigitDashDashAlpha: + // 2013-Feb-03 + // 13-Feb-03 switch r { - case 'A', 'P': - state = stateDigitDashWsWsAMPMMaybe - case '+', '-': - state = stateDigitDashWsWsOffset - default: - if unicode.IsLetter(r) { - // 2014-12-16 06:20:00 UTC - state = stateDigitDashWsWsAlpha - break iterRunes - } + case '-': + p.molen = i - p.moi + p.set(p.moi, "Jan") + p.dayi = i + 1 } - - case stateDigitDashWsWsAMPMMaybe: - if r == 'M' { - return parse("2006-01-02 03:04:05 PM", datestr, loc) - } - state = stateDigitDashWsWsAlpha - - case stateDigitDashWsWsOffset: - // stateDigitDashWsWsOffset - // 2006-01-02 15:04:05 -0700 - // stateDigitDashWsWsOffsetColon - // 2006-01-02 15:04:05 -07:00 - // stateDigitDashWsWsOffsetColonAlpha - // 2015-02-18 00:12:00 +00:00 UTC - // stateDigitDashWsWsOffsetAlpha - // 2015-02-18 00:12:00 +0000 UTC - if r == ':' { - state = stateDigitDashWsWsOffsetColon - } else if unicode.IsLetter(r) { - // 2015-02-18 00:12:00 +0000 UTC - state = stateDigitDashWsWsOffsetAlpha - break iterRunes - } - - case stateDigitDashWsWsOffsetColon: - // stateDigitDashWsWsOffsetColon - // 2006-01-02 15:04:05 -07:00 - // stateDigitDashWsWsOffsetColonAlpha - // 2015-02-18 00:12:00 +00:00 UTC - if unicode.IsLetter(r) { - // 2015-02-18 00:12:00 +00:00 UTC - state = stateDigitDashWsWsOffsetColonAlpha - break iterRunes - } - - case stateDigitDashWsPeriod: - // 2014-04-26 17:24:37.3186369 - // 2017-01-27 00:07:31.945167 - // 2012-08-03 18:31:59.257000000 - // 2016-03-14 00:00:00.000 - // stateDigitDashWsPeriodOffset - // 2017-01-27 00:07:31.945167 +0000 - // 2016-03-14 00:00:00.000 +0000 - // stateDigitDashWsPeriodOffsetAlpha - // 2017-01-27 00:07:31.945167 +0000 UTC - // 2016-03-14 00:00:00.000 +0000 UTC - // stateDigitDashWsPeriodAlpha - // 2014-12-16 06:20:00.000 UTC - if unicode.IsLetter(r) { - // 2014-12-16 06:20:00.000 UTC - state = stateDigitDashWsPeriodAlpha - break iterRunes - } else if r == '+' || r == '-' { - state = stateDigitDashWsPeriodOffset - } - case stateDigitDashWsPeriodOffset: - // 2017-01-27 00:07:31.945167 +0000 - // 2016-03-14 00:00:00.000 +0000 - // stateDigitDashWsPeriodOffsetAlpha - // 2017-01-27 00:07:31.945167 +0000 UTC - // 2016-03-14 00:00:00.000 +0000 UTC - if unicode.IsLetter(r) { - // 2014-12-16 06:20:00.000 UTC - // 2017-01-27 00:07:31.945167 +0000 UTC - // 2016-03-14 00:00:00.000 +0000 UTC - state = stateDigitDashWsPeriodOffsetAlpha - break iterRunes - } - case stateDigitDashT: // starts digit then dash 02- then T - // stateDigitDashT - // 2006-01-02T15:04:05 - // stateDigitDashTZ - // 2006-01-02T15:04:05.999999999Z - // 2006-01-02T15:04:05.99999999Z - // 2006-01-02T15:04:05.9999999Z - // 2006-01-02T15:04:05.999999Z - // 2006-01-02T15:04:05.99999Z - // 2006-01-02T15:04:05.9999Z - // 2006-01-02T15:04:05.999Z - // 2006-01-02T15:04:05.99Z - // 2009-08-12T22:15Z - // stateDigitDashTZDigit - // 2006-01-02T15:04:05.999999999Z07:00 - // 2006-01-02T15:04:05Z07:00 - // With another dash aka time-zone at end - // stateDigitDashTOffset - // stateDigitDashTOffsetColon - // 2017-06-25T17:46:57.45706582-07:00 - // 2017-06-25T17:46:57+04:00 - // 2006-01-02T15:04:05+0000 - switch r { - case '-', '+': - state = stateDigitDashTOffset - case 'Z': - state = stateDigitDashTZ - } - case stateDigitDashTZ: - if unicode.IsDigit(r) { - state = stateDigitDashTZDigit - } - case stateDigitDashTOffset: - if r == ':' { - state = stateDigitDashTOffsetColon - } - case stateDigitSlash: // starts digit then slash 02/ + case dateDigitSlash: // 2014/07/10 06:55:38.156283 // 03/19/2012 10:11:59 // 04/2/2014 03:00:37 @@ -390,271 +455,759 @@ iterRunes: // 10/13/2014 // 01/02/2006 // 1/2/06 - if unicode.IsDigit(r) || r == '/' { - continue - } + switch r { case ' ': - state = stateDigitSlashWS - } - case stateDigitSlashWS: // starts digit then slash 02/ more digits/slashes then whitespace - // 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 - // 4/8/14 22:05 - switch r { - case ':': - state = stateDigitSlashWSColon - } - case stateDigitSlashWSColon: // starts digit then slash 02/ more digits/slashes then whitespace - // 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 - // 4/8/14 22:05 - // 3/1/2012 10:11:59 AM - switch r { - case ':': - state = stateDigitSlashWSColonColon - case 'A', 'P': - state = stateDigitSlashWSColonAMPM - } - case stateDigitSlashWSColonColon: // starts digit then slash 02/ more digits/slashes then whitespace - // 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 - // 4/8/14 22:05 - // 3/1/2012 10:11:59 AM - switch r { - case 'A', 'P': - state = stateDigitSlashWSColonColonAMPM + 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 + } + } + + default: + // if unicode.IsDigit(r) || r == '/' { + // continue + // } } - case stateDigitWs: + case dateDigitWs: // 18 January 2018 // 8 January 2018 - //stateDigitWsMoShort - // 02 Jan 2018 23:59 - // 02 Jan 2018 23:59:34 - // stateDigitWsMoShortComma - // 12 Feb 2006, 19:17 - // 12 Feb 2006, 19:17:22 - if r == ' ' { - if i <= part1Len+len(" Feb") { - state = stateDigitWsMoShort + // 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 <= len("12 Feb") { + p.moi = p.daylen + 1 + p.molen = 3 + p.set(p.moi, "Jan") + p.stateDate = dateDigitWsMoYear } else { - break iterRunes + p.stateDate = dateDigitWsMolong } } - case stateDigitWsMoShort: + + 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 - // stateDigitWsMoShort - // stateDigitWsMoShortColon - // 02 Jan 2018 23:59 - // stateDigitWsMoShortComma - // 12 Feb 2006, 19:17 - // 12 Feb 2006, 19:17:22 - switch r { - case ':': - state = stateDigitWsMoShortColon - case ',': - state = stateDigitWsMoShortComma - } - case stateDigitWsMoShortColon: - // 02 Jan 2018 23:59 - // stateDigitWsMoShortColonColon - // 02 Jan 2018 23:59:45 - switch r { - case ':': - state = stateDigitWsMoShortColonColon - break iterRunes - } - - case stateDigitChineseYear: - // stateDigitChineseYear + case dateDigitChineseYear: + // dateDigitChineseYear // 2014年04月08日 // weekday %Y年%m月%e日 %A %I:%M %p // 2013年07月18日 星期四 10:27 上午 if r == ' ' { - state = stateDigitChineseYearWs + p.stateDate = dateDigitChineseYearWs break } - case stateDigitDot: + case dateDigitDot: // 3.31.2014 if r == '.' { - state = stateDigitDotDot - part2Len = i + p.daylen = i - p.dayi + p.yeari = i + 1 + p.setDay() + p.stateDate = dateDigitDotDot } - case stateDigitDotDot: + case dateDigitDotDot: // iterate all the way through - case stateAlpha: // starts alpha - // stateAlphaWS + 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) - // stateAlphaWSDigitComma + // dateAlphaWSDigit // May 8, 2009 5:57:51 PM + // oct 1, 1970 // - // stateWeekdayComma + // dateWeekdayComma // Monday, 02 Jan 2006 15:04:05 MST - // stateWeekdayCommaDash - // Monday, 02-Jan-06 15:04:05 MST - // stateWeekdayCommaOffset - // Monday, 02 Jan 2006 15:04:05 -0700 - // Monday, 02 Jan 2006 15:04:05 +0100 - // stateWeekdayAbbrevComma - // Mon, 02 Jan 2006 15:04:05 MST - // stateWeekdayAbbrevCommaDash - // Mon, 02-Jan-06 15:04:05 MST - // stateWeekdayAbbrevCommaOffset - // Mon, 02 Jan 2006 15:04:05 -0700 - // Thu, 13 Jul 2017 08:58:40 +0100 - // stateWeekdayAbbrevCommaOffsetZone - // Tue, 11 Jul 2017 16:28:13 +0200 (CEST) - switch { - case unicode.IsLetter(r): - continue - case r == ' ': - state = stateAlphaWS - case r == ',': - part1Len = i - if i == 3 { - state = stateWeekdayAbbrevComma - } else { - state = stateWeekdayComma - } - i++ - } - case stateWeekdayComma: // Starts alpha then comma - // Monday, 02 Jan 2006 15:04:05 MST - // stateWeekdayCommaDash // Monday, 02-Jan-06 15:04:05 MST - // stateWeekdayCommaOffset // Monday, 02 Jan 2006 15:04:05 -0700 // Monday, 02 Jan 2006 15:04:05 +0100 - switch { - case r == '-': - if i < 15 { - state = stateWeekdayCommaDash - break iterRunes - } - state = stateWeekdayCommaOffset - case r == '+': - state = stateWeekdayCommaOffset - } - case stateWeekdayAbbrevComma: // Starts alpha then comma - // Mon, 02 Jan 2006 15:04:05 MST - // stateWeekdayAbbrevCommaDash + // 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 - // stateWeekdayAbbrevCommaOffset - // Mon, 02 Jan 2006 15:04:05 -0700 - // Thu, 13 Jul 2017 08:58:40 +0100 - // Thu, 4 Jan 2018 17:53:36 +0000 - // stateWeekdayAbbrevCommaOffsetZone - // Tue, 11 Jul 2017 16:28:13 +0200 (CEST) + switch { - case r == ' ' && part3Len == 0: - part3Len = i - part1Len - 2 - case r == '-': - if i < 15 { - state = stateWeekdayAbbrevCommaDash + case r == ' ': + p.stateDate = dateAlphaWs + case r == ',': + // p.moi = 0 + // p.molen = i + if i == 3 { + p.stateDate = dateWeekdayAbbrevComma + p.set(0, "Mon") + } else { + p.stateDate = dateWeekdayComma + //p.set(0, "Monday") + 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 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 } - state = stateWeekdayAbbrevCommaOffset - case r == '+': - state = stateWeekdayAbbrevCommaOffset } - case stateWeekdayAbbrevCommaOffset: - // stateWeekdayAbbrevCommaOffset - // Mon, 02 Jan 2006 15:04:05 -0700 - // Thu, 13 Jul 2017 08:58:40 +0100 - // Thu, 4 Jan 2018 17:53:36 +0000 - // stateWeekdayAbbrevCommaOffsetZone - // Tue, 11 Jul 2017 16:28:13 +0200 (CEST) - if r == '(' { - state = stateWeekdayAbbrevCommaOffsetZone - } - - case stateAlphaWS: // Starts alpha then whitespace - // 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 + 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 + // oct 1, 1970 + // oct 7, '70 switch { case unicode.IsLetter(r): - state = stateAlphaWSAlpha + p.set(0, "Mon") + p.stateDate = dateAlphaWsAlpha + //p.moi = i + p.set(i, "Jan") case unicode.IsDigit(r): - state = stateAlphaWSDigitComma + p.set(0, "Jan") + p.stateDate = dateAlphaWsDigit + p.dayi = i } - case stateAlphaWSDigitComma: // Starts Alpha, whitespace, digit, comma + case dateAlphaWsDigit: // May 8, 2009 5:57:51 PM - for _, layout := range []string{ - "Jan 2, 2006 3:04:05 PM", - "Jan 2, 2006 3:4:05 PM", - "Jan 2, 2006 3:4:5 PM", - "Jan 2, 2006 3:04:5 PM", - "Jan 02, 2006 3:04:05 PM", - "Jan 02, 2006 3:4:05 PM", - "Jan 02, 2006 3:4:5 PM", - "Jan 02, 2006 3:04:5 PM", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil + // oct 1, 1970 + // oct 7, '70 + //gou.Debugf("%d %s dateAlphaWsDigit %s %s", i, string(r), p.ds(), p.ts()) + if r == ',' { + p.daylen = i - p.dayi + p.setDay() + p.stateDate = dateAlphaWsDigitComma + } + case dateAlphaWsDigitComma: + // x + // May 8, 2009 5:57:51 PM + // oct 1, 1970 + // oct 7, '70 + if r == ' ' { + p.stateDate = dateAlphaWsDigitCommaWs + p.yeari = i + 1 + } + case dateAlphaWsDigitCommaWs: + // x + // May 8, 2009 5:57:51 PM + // oct 1, 1970 + // oct 7, '70 + switch r { + case '\'': + p.yeari = i + 1 + case ' ': + p.stateDate = dateAlphaWsDigitCommaWsYear + 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 stateAlphaWSAlpha: // Alpha, whitespace, alpha + case dateAlphaWsAlphaYearmaybe: + // x // 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 == ':' { - state = stateAlphaWSAlphaColon - } - case stateAlphaWSAlphaColon: // Alpha, whitespace, alpha, : - // 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 unicode.IsLetter(r) { - state = stateAlphaWSAlphaColonAlpha - } else if r == '-' || r == '+' { - state = stateAlphaWSAlphaColonOffset - } - case stateAlphaWSAlphaColonAlpha: // Alpha, whitespace, alpha, :, alpha - // 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 == '+' { - state = stateAlphaWSAlphaColonAlphaOffset - } - case stateAlphaWSAlphaColonAlphaOffset: // Alpha, whitespace, alpha, : , alpha, offset, ? - // Mon Aug 10 15:44:11 UTC+0100 2015 - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - if unicode.IsLetter(r) { - state = stateAlphaWSAlphaColonAlphaOffsetAlpha + 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 } + 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 + } + } - switch state { - case stateDigit: + iterTimeRunes: + for ; i < len(datestr); i++ { + r := rune(datestr[i]) + + //gou.Debugf("%d %s iterTimeRunes %s %s", i, string(r), 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 + // 00:12:00 +0000 UTC + // 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 + // 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 + 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 ' ': + 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 + // 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 + // 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 + // 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.stateTime = timeWsAlphaWs + p.yeari = i + 1 + } + case timeWsAlphaWs: + // 17:57:51 MST 2009 + + case timeWsAlphaZoneOffset: + // 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 + // 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 + if unicode.IsDigit(r) { + p.yearlen = i - p.yeari + 1 + if p.yearlen == 4 { + p.setYear() + } + } else if 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 + // timePeriodWsOffsetAlpha + // 00:07:31.945167 +0000 UTC + // 00:00:00.000 +0000 UTC + // 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 + // 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 + switch r { + case ':': + p.stateTime = timePeriodWsOffsetColon + case ' ': + p.set(p.offseti, "-0700") + default: + if unicode.IsLetter(r) { + // 00:07:31.945167 +0000 UTC + // 00:00:00.000 +0000 UTC + p.stateTime = timePeriodWsOffsetWsAlpha + break iterTimeRunes + } + } + + 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 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 // 1499979655583057426 nanoseconds // 1499979795437000 micro-seconds @@ -698,896 +1251,100 @@ iterRunes: return t.In(loc), nil } - case stateDigitDash: // starts digit then dash 02- + case dateDigitDash: + // 2006-01 + return p.parse() + + case dateDigitDashDash: // 2006-01-02 // 2006-1-02 // 2006-1-2 // 2006-01-2 - // 2006-01 - for _, layout := range []string{ - "2006-01-02", - "2006-01", - "2006-1-2", - "2006-01-2", - "2006-1-02", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } + return p.parse() - case stateDigitDashAlpha: + case dateDigitDashDashAlpha: // 2013-Feb-03 // 2013-Feb-3 - for _, layout := range []string{ - "2006-Jan-02", - "2006-Jan-2", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } + p.daylen = i - p.dayi + p.setDay() + return p.parse() - case stateDigitDashTOffset: - // 2006-01-02T15:04:05+0000 - for _, layout := range []string{ - "2006-01-02T15:04:05-0700", - "2006-01-02T15:04:5-0700", - "2006-01-02T15:4:05-0700", - "2006-01-02T15:4:5-0700", - "2006-1-02T15:04:05-0700", - "2006-1-02T15:4:05-0700", - "2006-1-02T15:04:5-0700", - "2006-1-02T15:4:5-0700", - "2006-01-2T15:04:05-0700", - "2006-01-2T15:04:5-0700", - "2006-01-2T15:4:05-0700", - "2006-01-2T15:4:5-0700", - "2006-1-2T15:04:05-0700", - "2006-1-2T15:04:5-0700", - "2006-1-2T15:4:05-0700", - "2006-1-2T15:4:5-0700", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashTOffsetColon: - // With another +/- time-zone at end - // 2006-01-02T15:04:05.999999999+07:00 - // 2006-01-02T15:04:05.999999999-07:00 - // 2006-01-02T15:04:05.999999+07:00 - // 2006-01-02T15:04:05.999999-07:00 - // 2006-01-02T15:04:05.999+07:00 - // 2006-01-02T15:04:05.999-07:00 - // 2006-01-02T15:04:05+07:00 - // 2006-01-02T15:04:05-07:00 - for _, layout := range []string{ - "2006-01-02T15:04:05-07:00", - "2006-01-02T15:04:5-07:00", - "2006-01-02T15:4:05-07:00", - "2006-01-02T15:4:5-07:00", - "2006-1-02T15:04:05-07:00", - "2006-1-02T15:4:05-07:00", - "2006-1-02T15:04:5-07:00", - "2006-1-02T15:4:5-07:00", - "2006-01-2T15:04:05-07:00", - "2006-01-2T15:04:5-07:00", - "2006-01-2T15:4:05-07:00", - "2006-01-2T15:4:5-07:00", - "2006-1-2T15:04:05-07:00", - "2006-1-2T15:04:5-07:00", - "2006-1-2T15:4:05-07:00", - "2006-1-2T15:4:5-07:00", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashT: // starts digit then dash 02- then T - // 2006-01-02T15:04:05.999999 - // 2006-01-02T15:04:05.999999 - for _, layout := range []string{ - "2006-01-02T15:04:05", - "2006-01-02T15:04:5", - "2006-01-02T15:4:05", - "2006-01-02T15:4:5", - "2006-1-02T15:04:05", - "2006-1-02T15:4:05", - "2006-1-02T15:04:5", - "2006-1-02T15:4:5", - "2006-01-2T15:04:05", - "2006-01-2T15:04:5", - "2006-01-2T15:4:05", - "2006-01-2T15:4:5", - "2006-1-2T15:04:05", - "2006-1-2T15:04:5", - "2006-1-2T15:4:05", - "2006-1-2T15:4:5", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashTZDigit: - // 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" - return time.Time{}, fmt.Errorf("RFC339 Dates may not contain both Z & Offset for %q see https://github.com/golang/go/issues/5294", datestr) - - case stateDigitDashTZ: // starts digit then dash 02- then T Then Z - // 2006-01-02T15:04:05.999999999Z - // 2006-01-02T15:04:05.99999999Z - // 2006-01-02T15:04:05.9999999Z - // 2006-01-02T15:04:05.999999Z - // 2006-01-02T15:04:05.99999Z - // 2006-01-02T15:04:05.9999Z - // 2006-01-02T15:04:05.999Z - // 2006-01-02T15:04:05.99Z - // 2009-08-12T22:15Z -- No seconds/milliseconds - for _, layout := range []string{ - "2006-01-02T15:04:05Z", - "2006-01-02T15:04:5Z", - "2006-01-02T15:4:05Z", - "2006-01-02T15:4:5Z", - "2006-01-02T15:4Z", - "2006-01-02T15:04Z", - "2006-1-02T15:04:05Z", - "2006-1-02T15:4:05Z", - "2006-1-02T15:04:5Z", - "2006-1-02T15:4:5Z", - "2006-1-02T15:04Z", - "2006-1-02T15:4Z", - "2006-01-2T15:04:05Z", - "2006-01-2T15:04:5Z", - "2006-01-2T15:4:05Z", - "2006-01-2T15:4:5Z", - "2006-01-2T15:4Z", - "2006-01-2T15:04Z", - "2006-1-2T15:04:05Z", - "2006-1-2T15:04:5Z", - "2006-1-2T15:4:05Z", - "2006-1-2T15:4:5Z", - "2006-1-2T15:04Z", - "2006-1-2T15:4Z", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashWs: // starts digit then dash 02- then whitespace 1 << 2 << 5 + 3 + case dateDigitDashDashWs: // starts digit then dash 02- then whitespace 1 << 2 << 5 + 3 // 2013-04-01 22:43:22 // 2013-04-01 22:43 - for _, layout := range []string{ - "2006-01-02 15:04:05", - "2006-01-02 15:04:5", - "2006-01-02 15:4:05", - "2006-01-02 15:4:5", - "2006-01-02 15:4", - "2006-01-02 15:04", - "2006-1-02 15:04:05", - "2006-1-02 15:4:05", - "2006-1-02 15:04:5", - "2006-1-02 15:4:5", - "2006-1-02 15:04", - "2006-1-02 15:4", - "2006-01-2 15:04:05", - "2006-01-2 15:04:5", - "2006-01-2 15:4:05", - "2006-01-2 15:4:5", - "2006-01-2 15:4", - "2006-01-2 15:04", - "2006-1-2 15:04:05", - "2006-1-2 15:04:5", - "2006-1-2 15:4:05", - "2006-1-2 15:4:5", - "2006-1-2 15:04", - "2006-1-2 15:4", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } + return p.parse() - case stateDigitDashWsWsOffset: - // 2006-01-02 15:04:05 -0700 - for _, layout := range []string{ - "2006-01-02 15:04:05 -0700", - "2006-01-02 15:04:5 -0700", - "2006-01-02 15:4:05 -0700", - "2006-01-02 15:4:5 -0700", - "2006-1-02 15:04:05 -0700", - "2006-1-02 15:4:05 -0700", - "2006-1-02 15:04:5 -0700", - "2006-1-02 15:4:5 -0700", - "2006-01-2 15:04:05 -0700", - "2006-01-2 15:04:5 -0700", - "2006-01-2 15:4:05 -0700", - "2006-01-2 15:4:5 -0700", - "2006-1-2 15:04:05 -0700", - "2006-1-2 15:04:5 -0700", - "2006-1-2 15:4:05 -0700", - "2006-1-2 15:4:5 -0700", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } + case dateDigitDashDashT: + return p.parse() - case stateDigitDashWsWsOffsetColon: - // 2006-01-02 15:04:05 -07:00 - switch { - case part2Len == 2 && part3Len == 2: - for _, layout := range []string{ - "2006-01-02 15:04:05 -07:00", - "2006-01-02 15:04:5 -07:00", - "2006-01-02 15:4:05 -07:00", - "2006-01-02 15:4:5 -07:00", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case part2Len == 2 && part3Len == 1: - for _, layout := range []string{ - "2006-01-2 15:04:05 -07:00", - "2006-01-2 15:04:5 -07:00", - "2006-01-2 15:4:05 -07:00", - "2006-01-2 15:4:5 -07:00", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case part2Len == 1 && part3Len == 2: - for _, layout := range []string{ - "2006-1-02 15:04:05 -07:00", - "2006-1-02 15:4:05 -07:00", - "2006-1-02 15:04:5 -07:00", - "2006-1-02 15:4:5 -07:00", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case part2Len == 1 && part3Len == 1: - for _, layout := range []string{ - "2006-1-2 15:04:05 -07:00", - "2006-1-2 15:04:5 -07:00", - "2006-1-2 15:4:05 -07:00", - "2006-1-2 15:4:5 -07:00", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } + case dateDigitDotDot: + // 03.31.1981 + // 3.2.1981 + // 3.2.81 + p.setYear() + p.yearlen = i - p.yeari + return p.parse() - case stateDigitDashWsWsOffsetAlpha: - // 2015-02-18 00:12:00 +0000 UTC - - switch { - case part2Len == 2 && part3Len == 2: - for _, layout := range []string{ - "2006-01-02 15:04:05 -0700 MST", - "2006-01-02 15:04:5 -0700 MST", - "2006-01-02 15:4:05 -0700 MST", - "2006-01-02 15:4:5 -0700 MST", - "2006-01-02 15:04:05 +0000 GMT", - "2006-01-02 15:04:5 +0000 GMT", - "2006-01-02 15:4:05 +0000 GMT", - "2006-01-02 15:4:5 +0000 GMT", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case part2Len == 2 && part3Len == 1: - for _, layout := range []string{ - "2006-01-2 15:04:05 -0700 MST", - "2006-01-2 15:04:5 -0700 MST", - "2006-01-2 15:4:05 -0700 MST", - "2006-01-2 15:4:5 -0700 MST", - "2006-01-2 15:04:05 +0000 GMT", - "2006-01-2 15:04:5 +0000 GMT", - "2006-01-2 15:4:05 +0000 GMT", - "2006-01-2 15:4:5 +0000 GMT", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case part2Len == 1 && part3Len == 2: - for _, layout := range []string{ - "2006-1-02 15:04:05 -0700 MST", - "2006-1-02 15:4:05 -0700 MST", - "2006-1-02 15:04:5 -0700 MST", - "2006-1-02 15:4:5 -0700 MST", - "2006-1-02 15:04:05 +0000 GMT", - "2006-1-02 15:4:05 +0000 GMT", - "2006-1-02 15:04:5 +0000 GMT", - "2006-1-02 15:4:5 +0000 GMT", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case part2Len == 1 && part3Len == 1: - for _, layout := range []string{ - "2006-1-2 15:04:05 -0700 MST", - "2006-1-2 15:04:5 -0700 MST", - "2006-1-2 15:4:05 -0700 MST", - "2006-1-2 15:4:5 -0700 MST", - "2006-1-2 15:04:05 +0000 GMT", - "2006-1-2 15:04:5 +0000 GMT", - "2006-1-2 15:4:05 +0000 GMT", - "2006-1-2 15:4:5 +0000 GMT", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - - case stateDigitDashWsWsOffsetColonAlpha: - // 2015-02-18 00:12:00 +00:00 UTC - for _, layout := range []string{ - "2006-01-02 15:04:05 -07:00 UTC", - "2006-01-02 15:04:5 -07:00 UTC", - "2006-01-02 15:4:05 -07:00 UTC", - "2006-01-02 15:4:5 -07:00 UTC", - "2006-1-02 15:04:05 -07:00 UTC", - "2006-1-02 15:4:05 -07:00 UTC", - "2006-1-02 15:04:5 -07:00 UTC", - "2006-1-02 15:4:5 -07:00 UTC", - "2006-01-2 15:04:05 -07:00 UTC", - "2006-01-2 15:04:5 -07:00 UTC", - "2006-01-2 15:4:05 -07:00 UTC", - "2006-01-2 15:4:5 -07:00 UTC", - "2006-1-2 15:04:05 -07:00 UTC", - "2006-1-2 15:04:5 -07:00 UTC", - "2006-1-2 15:4:05 -07:00 UTC", - "2006-1-2 15:4:5 -07:00 UTC", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashWsOffset: - // 2017-07-19 03:21:51+00:00 - for _, layout := range []string{ - "2006-01-02 15:04:05-07:00", - "2006-01-02 15:04:5-07:00", - "2006-01-02 15:4:05-07:00", - "2006-01-02 15:4:5-07:00", - "2006-1-02 15:04:05-07:00", - "2006-1-02 15:4:05-07:00", - "2006-1-02 15:04:5-07:00", - "2006-1-02 15:4:5-07:00", - "2006-01-2 15:04:05-07:00", - "2006-01-2 15:04:5-07:00", - "2006-01-2 15:4:05-07:00", - "2006-01-2 15:4:5-07:00", - "2006-1-2 15:04:05-07:00", - "2006-1-2 15:04:5-07:00", - "2006-1-2 15:4:05-07:00", - "2006-1-2 15:4:5-07:00", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashWsWsAlpha: - // 2014-12-16 06:20:00 UTC - for _, layout := range []string{ - "2006-01-02 15:04:05 UTC", - "2006-01-02 15:04:5 UTC", - "2006-01-02 15:4:05 UTC", - "2006-01-02 15:4:5 UTC", - "2006-1-02 15:04:05 UTC", - "2006-1-02 15:4:05 UTC", - "2006-1-02 15:04:5 UTC", - "2006-1-02 15:4:5 UTC", - "2006-01-2 15:04:05 UTC", - "2006-01-2 15:04:5 UTC", - "2006-01-2 15:4:05 UTC", - "2006-01-2 15:4:5 UTC", - "2006-1-2 15:04:05 UTC", - "2006-1-2 15:04:5 UTC", - "2006-1-2 15:4:05 UTC", - "2006-1-2 15:4:5 UTC", - "2006-01-02 15:04:05 GMT", - "2006-01-02 15:04:5 GMT", - "2006-01-02 15:4:05 GMT", - "2006-01-02 15:4:5 GMT", - "2006-1-02 15:04:05 GMT", - "2006-1-02 15:4:05 GMT", - "2006-1-02 15:04:5 GMT", - "2006-1-02 15:4:5 GMT", - "2006-01-2 15:04:05 GMT", - "2006-01-2 15:04:5 GMT", - "2006-01-2 15:4:05 GMT", - "2006-01-2 15:4:5 GMT", - "2006-1-2 15:04:05 GMT", - "2006-1-2 15:04:5 GMT", - "2006-1-2 15:4:05 GMT", - "2006-1-2 15:4:5 GMT", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - if len(datestr) > len("2006-01-02 03:04:05") { - t, err := parse("2006-01-02 03:04:05", datestr[:len("2006-01-02 03:04:05")], loc) - if err == nil { - return t, nil - } - } - - case stateDigitDashWsPeriod: - // 2012-08-03 18:31:59.257000000 - // 2014-04-26 17:24:37.3186369 - // 2017-01-27 00:07:31.945167 - // 2016-03-14 00:00:00.000 - for _, layout := range []string{ - "2006-01-02 15:04:05", - "2006-01-02 15:04:5", - "2006-01-02 15:4:05", - "2006-01-02 15:4:5", - "2006-1-02 15:04:05", - "2006-1-02 15:4:05", - "2006-1-02 15:04:5", - "2006-1-02 15:4:5", - "2006-01-2 15:04:05", - "2006-01-2 15:04:5", - "2006-01-2 15:4:05", - "2006-01-2 15:4:5", - "2006-1-2 15:04:05", - "2006-1-2 15:04:5", - "2006-1-2 15:4:05", - "2006-1-2 15:4:5", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashWsPeriodAlpha: - // 2012-08-03 18:31:59.257000000 UTC - // 2014-04-26 17:24:37.3186369 UTC - // 2017-01-27 00:07:31.945167 UTC - // 2016-03-14 00:00:00.000 UTC - for _, layout := range []string{ - "2006-01-02 15:04:05 UTC", - "2006-01-02 15:04:5 UTC", - "2006-01-02 15:4:05 UTC", - "2006-01-02 15:4:5 UTC", - "2006-1-02 15:04:05 UTC", - "2006-1-02 15:4:05 UTC", - "2006-1-02 15:04:5 UTC", - "2006-1-02 15:4:5 UTC", - "2006-01-2 15:04:05 UTC", - "2006-01-2 15:04:5 UTC", - "2006-01-2 15:4:05 UTC", - "2006-01-2 15:4:5 UTC", - "2006-1-2 15:04:05 UTC", - "2006-1-2 15:04:5 UTC", - "2006-1-2 15:4:05 UTC", - "2006-1-2 15:4:5 UTC", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashWsPeriodOffset: - // 2012-08-03 18:31:59.257000000 +0000 - // 2014-04-26 17:24:37.3186369 +0000 - // 2017-01-27 00:07:31.945167 +0000 - // 2016-03-14 00:00:00.000 +0000 - for _, layout := range []string{ - "2006-01-02 15:04:05 -0700", - "2006-01-02 15:04:5 -0700", - "2006-01-02 15:4:05 -0700", - "2006-01-02 15:4:5 -0700", - "2006-1-02 15:04:05 -0700", - "2006-1-02 15:4:05 -0700", - "2006-1-02 15:04:5 -0700", - "2006-1-02 15:4:5 -0700", - "2006-01-2 15:04:05 -0700", - "2006-01-2 15:04:5 -0700", - "2006-01-2 15:4:05 -0700", - "2006-01-2 15:4:5 -0700", - "2006-1-2 15:04:05 -0700", - "2006-1-2 15:04:5 -0700", - "2006-1-2 15:4:05 -0700", - "2006-1-2 15:4:5 -0700", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDashWsPeriodOffsetAlpha: - // 2012-08-03 18:31:59.257000000 +0000 UTC - // 2014-04-26 17:24:37.3186369 +0000 UTC - // 2017-01-27 00:07:31.945167 +0000 UTC - // 2016-03-14 00:00:00.000 +0000 UTC - for _, layout := range []string{ - "2006-01-02 15:04:05 -0700 UTC", - "2006-01-02 15:04:5 -0700 UTC", - "2006-01-02 15:4:05 -0700 UTC", - "2006-01-02 15:4:5 -0700 UTC", - "2006-1-02 15:04:05 -0700 UTC", - "2006-1-02 15:4:05 -0700 UTC", - "2006-1-02 15:04:5 -0700 UTC", - "2006-1-02 15:4:5 -0700 UTC", - "2006-01-2 15:04:05 -0700 UTC", - "2006-01-2 15:04:5 -0700 UTC", - "2006-01-2 15:4:05 -0700 UTC", - "2006-01-2 15:4:5 -0700 UTC", - "2006-1-2 15:04:05 -0700 UTC", - "2006-1-2 15:04:5 -0700 UTC", - "2006-1-2 15:4:05 -0700 UTC", - "2006-1-2 15:4:5 -0700 UTC", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitDotDot: - switch { - case len(datestr) == len("01.02.2006"): - return parse("01.02.2006", datestr, loc) - case len(datestr)-part2Len == 3: - for _, layout := range []string{"01.02.06", "1.02.06", "01.2.06", "1.2.06"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - default: - for _, layout := range []string{"1.02.2006", "01.2.2006", "1.2.2006"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - - case stateDigitWs: - // 18 January 2018 - // 8 January 2018 - if part1Len == 1 { - return parse("2 January 2006", datestr, loc) - } - return parse("02 January 2006", datestr, loc) - // 02 Jan 2018 23:59 - case stateDigitWsMoShortColon: + case dateDigitWsMoYear: + // 2 Jan 2018 + // 2 Jan 18 // 2 Jan 2018 23:59 // 02 Jan 2018 23:59 - if part1Len == 1 { - for _, layout := range []string{ - "2 Jan 2006 15:04", - "2 Jan 2006 15:4", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - - for _, layout := range []string{ - "02 Jan 2006 15:04", - "02 Jan 2006 15:4", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - case stateDigitWsMoShortColonColon: // 02 Jan 2018 23:59:45 - if part1Len == 1 { - for _, layout := range []string{ - "2 Jan 2006 15:04:05", - "2 Jan 2006 15:04:5", - "2 Jan 2006 15:4:5", - "2 Jan 2006 15:4:05", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - for _, layout := range []string{ - "2 Jan 2006 15:04:05", - "2 Jan 2006 15:04:5", - "2 Jan 2006 15:4:5", - "2 Jan 2006 15:4:05", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateDigitWsMoShortComma: // 12 Feb 2006, 19:17 // 12 Feb 2006, 19:17:22 - for _, layout := range []string{ - "02 Jan 2006, 15:04", - "02 Jan 2006, 15:4", - "2 Jan 2006, 15:04", - "2 Jan 2006, 15:4", - "02 Jan 2006, 15:04:05", - "02 Jan 2006, 15:4:05", - "02 Jan 2006, 15:4:5", - "02 Jan 2006, 15:04:5", - "2 Jan 2006, 15:04:05", - "2 Jan 2006, 15:04:5", - "2 Jan 2006, 15:4:5", - "2 Jan 2006, 15:4:05", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } + return p.parse() + + case dateDigitWsMolong: + // 18 January 2018 + // 8 January 2018 + if p.daylen == 2 { + return parse("02 January 2006", datestr, loc) } + return parse("2 January 2006", datestr, loc) - case stateAlphaWSAlphaColon: - // Mon Jan _2 15:04:05 2006 - return parse(time.ANSIC, datestr, loc) + case dateAlphaWsDigitCommaWs: + // oct 1, 1970 + p.yearlen = i - p.yeari + p.setYear() + return p.parse() - case stateAlphaWSAlphaColonOffset: - // Mon Jan 02 15:04:05 -0700 2006 - return parse(time.RubyDate, datestr, loc) + case dateAlphaWsDigitCommaWsYear: + // May 8, 2009 5:57:51 PM + return p.parse() - case stateAlphaWSAlphaColonAlpha: - // Mon Jan _2 15:04:05 MST 2006 - return parse(time.UnixDate, datestr, loc) + case dateAlphaWsAlpha: + return p.parse() - case stateAlphaWSAlphaColonAlphaOffset: - // Mon Aug 10 15:44:11 UTC+0100 2015 - return parse("Mon Jan 02 15:04:05 MST-0700 2006", datestr, loc) + case dateAlphaWsAlphaYearmaybe: + return p.parse() - case stateAlphaWSAlphaColonAlphaOffsetAlpha: - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - if len(datestr) > len("Mon Jan 02 2006 15:04:05 MST-0700") { - // What effing time stamp is this? - // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) - dateTmp := datestr[:33] - return parse("Mon Jan 02 2006 15:04:05 MST-0700", dateTmp, loc) - } - case stateDigitSlash: // starts digit then slash 02/ (but nothing else) + case dateDigitSlash: // 3/1/2014 // 10/13/2014 // 01/02/2006 // 2014/10/13 - if part1Len == 4 { - if len(datestr) == len("2006/01/02") { - return parse("2006/01/02", datestr, loc) - } - return parse("2006/1/2", datestr, loc) - } - for _, parseFormat := range shortDates { - if t, err := parse(parseFormat, datestr, loc); err == nil { - return t, nil - } - } + return p.parse() - case stateDigitSlashWSColon: // starts digit then slash 02/ more digits/slashes then whitespace - // 4/8/2014 22:05 - // 04/08/2014 22:05 - // 2014/4/8 22:05 - // 2014/04/08 22:05 - - if part1Len == 4 { - for _, layout := range []string{"2006/01/02 15:04", "2006/1/2 15:04", "2006/01/2 15:04", "2006/1/02 15:04", "2006/01/02 15:4", "2006/1/2 15:4", "2006/01/2 15:4", "2006/1/02 15:4"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } else { - for _, layout := range []string{"01/02/2006 15:4", "01/2/2006 15:4", "1/02/2006 15:4", "1/2/2006 15:4", "1/2/06 15:4", "01/02/06 15:4", "01/02/2006 15:04", "01/2/2006 15:04", "1/02/2006 15:04", "1/2/2006 15:04", "1/2/06 15:04", "01/02/06 15:04"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - - case stateDigitSlashWSColonAMPM: // starts digit then slash 02/ more digits/slashes then whitespace - // 4/8/2014 22:05 PM - // 04/08/2014 22:05 PM - // 04/08/2014 1:05 PM - // 2014/4/8 22:05 PM - // 2014/04/08 22:05 PM - - if part1Len == 4 { - for _, layout := range []string{"2006/01/02 03:04 PM", "2006/01/2 03:04 PM", "2006/1/02 03:04 PM", "2006/1/2 03:04 PM", - "2006/01/02 3:04 PM", "2006/01/2 3:04 PM", "2006/1/02 3:04 PM", "2006/1/2 3:04 PM", "2006/01/02 3:4 PM", "2006/01/2 3:4 PM", "2006/1/02 3:4 PM", "2006/1/2 3:4 PM", - "2006/01/02 3:4 PM", "2006/01/2 3:4 PM", "2006/1/02 3:4 PM", "2006/1/2 3:4 PM"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } else { - for _, layout := range []string{"01/02/2006 03:04 PM", "01/2/2006 03:04 PM", "1/02/2006 03:04 PM", "1/2/2006 03:04 PM", - "01/02/2006 03:4 PM", "01/2/2006 03:4 PM", "1/02/2006 03:4 PM", "1/2/2006 03:4 PM", - "01/02/2006 3:04 PM", "01/2/2006 3:04 PM", "1/02/2006 3:04 PM", "1/2/2006 3:04 PM", - "01/02/2006 3:04 PM", "01/2/2006 3:04 PM", "1/02/2006 3:04 PM", "1/2/2006 3:04 PM", - "01/02/2006 3:4 PM", "01/2/2006 3:4 PM", "1/02/2006 3:4 PM", "1/2/2006 3:4 PM", - "01/02/2006 3:4 PM", "01/2/2006 3:4 PM", "1/02/2006 3:4 PM", "1/2/2006 3:4 PM"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - - } - } - - case stateDigitSlashWSColonColon: // starts digit then slash 02/ more digits/slashes then whitespace double colons - // 2014/07/10 06:55:38.156283 - // 03/19/2012 10:11:59 - // 3/1/2012 10:11:59 - // 03/1/2012 10:11:59 - // 3/01/2012 10:11:59 - // 4/8/14 22:05 - if part1Len == 4 { - for _, layout := range []string{"2006/01/02 15:04:05", "2006/1/02 15:04:05", "2006/01/2 15:04:05", "2006/1/2 15:04:05", - "2006/01/02 15:04:5", "2006/1/02 15:04:5", "2006/01/2 15:04:5", "2006/1/2 15:04:5", - "2006/01/02 15:4:05", "2006/1/02 15:4:05", "2006/01/2 15:4:05", "2006/1/2 15:4:05", - "2006/01/02 15:4:5", "2006/1/02 15:4:5", "2006/01/2 15:4:5", "2006/1/2 15:4:5"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } else { - for _, layout := range []string{"01/02/2006 15:04:05", "1/02/2006 15:04:05", "01/2/2006 15:04:05", "1/2/2006 15:04:05", - "01/02/2006 15:4:5", "1/02/2006 15:4:5", "01/2/2006 15:4:5", "1/2/2006 15:4:5", - "01/02/2006 15:4:05", "1/02/2006 15:4:05", "01/2/2006 15:4:05", "1/2/2006 15:4:05", - "01/02/2006 15:04:5", "1/02/2006 15:04:5", "01/2/2006 15:04:5", "1/2/2006 15:04:5"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - - case stateDigitSlashWSColonColonAMPM: // starts digit then slash 02/ more digits/slashes then whitespace double colons - // 2014/07/10 06:55:38.156283 PM - // 03/19/2012 10:11:59 PM - // 3/1/2012 10:11:59 PM - // 03/1/2012 10:11:59 PM - // 3/01/2012 10:11:59 PM - - if part1Len == 4 { - for _, layout := range []string{"2006/01/02 03:04:05 PM", "2006/1/02 03:04:05 PM", "2006/01/2 03:04:05 PM", "2006/1/2 03:04:05 PM", - "2006/01/02 03:4:5 PM", "2006/1/02 03:4:5 PM", "2006/01/2 03:4:5 PM", "2006/1/2 03:4:5 PM", - "2006/01/02 03:4:05 PM", "2006/1/02 03:4:05 PM", "2006/01/2 03:4:05 PM", "2006/1/2 03:4:05 PM", - "2006/01/02 03:04:5 PM", "2006/1/02 03:04:5 PM", "2006/01/2 03:04:5 PM", "2006/1/2 03:04:5 PM", - - "2006/01/02 3:4:5 PM", "2006/1/02 3:4:5 PM", "2006/01/2 3:4:5 PM", "2006/1/2 3:4:5 PM", - "2006/01/02 3:4:05 PM", "2006/1/02 3:4:05 PM", "2006/01/2 3:4:05 PM", "2006/1/2 3:4:05 PM", - "2006/01/02 3:04:5 PM", "2006/1/02 3:04:5 PM", "2006/01/2 3:04:5 PM", "2006/1/2 3:04:5 PM"} { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } else { - for _, layout := range []string{"01/02/2006 03:04:05 PM", "1/02/2006 03:04:05 PM", "01/2/2006 03:04:05 PM", "1/2/2006 03:04:05 PM", - "01/02/2006 03:4:05 PM", "1/02/2006 03:4:05 PM", "01/2/2006 03:4:05 PM", "1/2/2006 03:4:05 PM", - "01/02/2006 03:04:5 PM", "1/02/2006 03:04:5 PM", "01/2/2006 03:04:5 PM", "1/2/2006 03:04:5 PM", - "01/02/2006 03:4:5 PM", "1/02/2006 03:4:5 PM", "01/2/2006 03:4:5 PM", "1/2/2006 03:4:5 PM", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - } - case stateDigitChineseYear: - // stateDigitChineseYear + case dateDigitChineseYear: + // dateDigitChineseYear // 2014年04月08日 return parse("2006年01月02日", datestr, loc) - case stateDigitChineseYearWs: + + case dateDigitChineseYearWs: return parse("2006年01月02日 15:04:05", datestr, loc) - case stateWeekdayCommaOffset: + + case dateWeekdayComma: // Monday, 02 Jan 2006 15:04:05 -0700 // Monday, 02 Jan 2006 15:04:05 +0100 - for _, layout := range []string{ - "Monday, _2 Jan 2006 15:04:05 -0700", - "Monday, _2 Jan 2006 15:04:5 -0700", - "Monday, _2 Jan 2006 15:4:05 -0700", - "Monday, _2 Jan 2006 15:4:5 -0700", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateWeekdayCommaDash: // Monday, 02-Jan-06 15:04:05 MST - for _, layout := range []string{ - "Monday, 02-Jan-06 15:04:05 MST", - "Monday, 02-Jan-06 15:4:05 MST", - "Monday, 02-Jan-06 15:04:5 MST", - "Monday, 02-Jan-06 15:4:5 MST", - "Monday, 2-Jan-06 15:04:05 MST", - "Monday, 2-Jan-06 15:4:05 MST", - "Monday, 2-Jan-06 15:4:5 MST", - "Monday, 2-Jan-06 15:04:5 MST", - "Monday, 2-Jan-6 15:04:05 MST", - "Monday, 2-Jan-6 15:4:05 MST", - "Monday, 2-Jan-6 15:4:5 MST", - "Monday, 2-Jan-6 15:04:5 MST", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } + return p.parse() - case stateWeekdayAbbrevComma: // Starts alpha then comma + case dateWeekdayAbbrevComma: // Mon, 02-Jan-06 15:04:05 MST // Mon, 02 Jan 2006 15:04:05 MST - for _, layout := range []string{ - "Mon, _2 Jan 2006 15:04:05 MST", - "Mon, _2 Jan 2006 15:04:5 MST", - "Mon, _2 Jan 2006 15:4:5 MST", - "Mon, _2 Jan 2006 15:4:05 MST", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } + return p.parse() - case stateWeekdayAbbrevCommaDash: - // Mon, 02-Jan-06 15:04:05 MST - // Mon, 2-Jan-06 15:04:05 MST - for _, layout := range []string{ - "Mon, 02-Jan-06 15:04:05 MST", - "Mon, 02-Jan-06 15:4:05 MST", - "Mon, 02-Jan-06 15:04:5 MST", - "Mon, 02-Jan-06 15:4:5 MST", - "Mon, 2-Jan-06 15:04:05 MST", - "Mon, 2-Jan-06 15:4:05 MST", - "Mon, 2-Jan-06 15:4:5 MST", - "Mon, 2-Jan-06 15:04:5 MST", - "Mon, 2-Jan-6 15:04:05 MST", - "Mon, 2-Jan-6 15:4:05 MST", - "Mon, 2-Jan-6 15:4:5 MST", - "Mon, 2-Jan-6 15:04:5 MST", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateWeekdayAbbrevCommaOffset: - // Mon, 02 Jan 2006 15:04:05 -0700 - // Thu, 13 Jul 2017 08:58:40 +0100 - // RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone - // - // Thu, 4 Jan 2018 17:53:36 +0000 - for _, layout := range []string{ - "Mon, _2 Jan 2006 15:04:05 -0700", - "Mon, _2 Jan 2006 15:4:05 -0700", - "Mon, _2 Jan 2006 15:4:5 -0700", - "Mon, _2 Jan 2006 15:04:5 -0700", - } { - if t, err := parse(layout, datestr, loc); err == nil { - return t, nil - } - } - - case stateWeekdayAbbrevCommaOffsetZone: - // Tue, 11 Jul 2017 16:28:13 +0200 (CEST) - if part3Len == 1 { - return parse("Mon, 2 Jan 2006 15:04:05 -0700 (MST)", datestr, loc) - } - return parse("Mon, _2 Jan 2006 15:04:05 -0700 (MST)", datestr, loc) } return time.Time{}, fmt.Errorf("Could not find date format for %s", datestr) diff --git a/parseany_test.go b/parseany_test.go index 0aeeade..f97490b 100644 --- a/parseany_test.go +++ b/parseany_test.go @@ -51,6 +51,13 @@ func TestInLocation(t *testing.T) { assert.Equal(t, "MST", zone, "Should have found zone = MST %v", zone) assert.Equal(t, "2013-02-01 07:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) + ts, err = ParseIn("18 January 2018", denverLoc) + assert.Equal(t, nil, err) + zone, offset = ts.Zone() + assert.Equal(t, -25200, offset, "Should have found offset = 0 %v", offset) + assert.Equal(t, "MST", zone, "Should have found zone = UTC %v", zone) + assert.Equal(t, "2018-01-18 07:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) + // Now we are going to use ParseLocal() and see that it gives same // answer as ParseIn when we have time.Local set to a location time.Local = denverLoc @@ -106,6 +113,304 @@ func TestInLocation(t *testing.T) { assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) } +func TestOne(t *testing.T) { + time.Local = time.UTC + var ts time.Time + ts = MustParse("2014-05-11 08:20:13,787") + assert.Equal(t, "2014-05-11 08:20:13.787 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) +} + +type dateTest struct { + in, out, loc string +} + +// {in: , out: }, + +var testInputs = []dateTest{ + {in: "oct 7, 1970", out: "1970-10-07 00:00:00 +0000 UTC"}, + {in: "oct 7, '70", out: "1970-10-07 00:00:00 +0000 UTC"}, + {in: "Oct 7, '70", out: "1970-10-07 00:00:00 +0000 UTC"}, + {in: "Feb 8, 2009 5:57:51 AM", out: "2009-02-08 05:57:51 +0000 UTC"}, + {in: "May 8, 2009 5:57:51 PM", out: "2009-05-08 17:57:51 +0000 UTC"}, + {in: "May 8, 2009 5:57:1 PM", out: "2009-05-08 17:57:01 +0000 UTC"}, + {in: "May 8, 2009 5:7:51 PM", out: "2009-05-08 17:07:51 +0000 UTC"}, + {in: "7 oct 70", out: "1970-10-07 00:00:00 +0000 UTC"}, + {in: "7 oct 1970", out: "1970-10-07 00:00:00 +0000 UTC"}, + // ANSIC = "Mon Jan _2 15:04:05 2006" + {in: "Mon Jan 2 15:04:05 2006", out: "2006-01-02 15:04:05 +0000 UTC"}, + {in: "Thu May 8 17:57:51 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, + {in: "Thu May 8 17:57:51 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, + // RubyDate = "Mon Jan 02 15:04:05 -0700 2006" + {in: "Mon Jan 02 15:04:05 -0700 2006", out: "2006-01-02 22:04:05 +0000 UTC"}, + {in: "Thu May 08 11:57:51 -0700 2009", out: "2009-05-08 18:57:51 +0000 UTC"}, + // UnixDate = "Mon Jan _2 15:04:05 MST 2006" + {in: "Mon Jan 2 15:04:05 MST 2006", out: "2006-01-02 15:04:05 +0000 UTC"}, + {in: "Thu May 8 17:57:51 MST 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, + {in: "Thu May 8 17:57:51 PST 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, + {in: "Thu May 08 17:57:51 PST 2009", out: "2009-05-08 17:57:51 +0000 UTC"}, + {in: "Thu May 08 05:05:07 PST 2009", out: "2009-05-08 05:05:07 +0000 UTC"}, + {in: "Thu May 08 5:5:7 PST 2009", out: "2009-05-08 05:05:07 +0000 UTC"}, + // ?? + {in: "Mon Aug 10 15:44:11 UTC+0000 2015", out: "2015-08-10 15:44:11 +0000 UTC"}, + {in: "Mon Aug 10 15:44:11 PST-0700 2015", out: "2015-08-10 22:44:11 +0000 UTC"}, + {in: "Mon Aug 10 15:44:11 CEST+0200 2015", out: "2015-08-10 13:44:11 +0000 UTC"}, + {in: "Mon Aug 1 15:44:11 CEST+0200 2015", out: "2015-08-01 13:44:11 +0000 UTC"}, + {in: "Mon Aug 1 5:44:11 CEST+0200 2015", out: "2015-08-01 03:44:11 +0000 UTC"}, + // ?? + {in: "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)", out: "2015-07-03 17:04:07 +0000 UTC"}, + {in: "Fri Jul 3 2015 06:04:07 GMT+0100 (GMT Daylight Time)", out: "2015-07-03 05:04:07 +0000 UTC"}, + {in: "Fri Jul 3 2015 06:04:07 PST-0700 (Pacific Daylight Time)", out: "2015-07-03 13:04:07 +0000 UTC"}, + // ? + {in: "Fri, 03 Jul 2015 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 03 Jul 2015 08:08:08 PST", out: "2015-07-03 15:08:08 +0000 UTC", loc: "America/Los_Angeles"}, + {in: "Fri, 03 Jul 2015 08:08:08 PST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 3 Jul 2015 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 03 Jul 2015 8:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 03 Jul 2015 8:8:8 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + // ? + {in: "Thu, 03 Jul 2017 08:08:04 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, + {in: "Thu, 03 Jul 2017 08:08:04 -0100", out: "2017-07-03 09:08:04 +0000 UTC"}, + {in: "Thu, 3 Jul 2017 08:08:04 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, + {in: "Thu, 03 Jul 2017 8:08:04 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, + {in: "Thu, 03 Jul 2017 8:8:4 +0100", out: "2017-07-03 07:08:04 +0000 UTC"}, + // + {in: "Tue, 11 Jul 2017 04:08:03 +0200 (CEST)", out: "2017-07-11 02:08:03 +0000 UTC"}, + {in: "Tue, 5 Jul 2017 04:08:03 -0700 (CEST)", out: "2017-07-05 11:08:03 +0000 UTC"}, + {in: "Tue, 11 Jul 2017 04:08:03 +0200 (CEST)", out: "2017-07-11 02:08:03 +0000 UTC", loc: "Europe/Berlin"}, + // day, dd-Mon-yy hh:mm:zz TZ + {in: "Fri, 03-Jul-15 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 03-Jul-15 08:08:08 PST", out: "2015-07-03 15:08:08 +0000 UTC", loc: "America/Los_Angeles"}, + {in: "Fri, 03-Jul 2015 08:08:08 PST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 3-Jul-15 08:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 03-Jul-15 8:08:08 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + {in: "Fri, 03-Jul-15 8:8:8 MST", out: "2015-07-03 08:08:08 +0000 UTC"}, + // RFC850 = "Monday, 02-Jan-06 15:04:05 MST" + {in: "Wednesday, 07-May-09 08:00:43 MST", out: "2009-05-07 08:00:43 +0000 UTC"}, + {in: "Wednesday, 28-Feb-18 09:01:00 MST", out: "2018-02-28 09:01:00 +0000 UTC"}, + {in: "Wednesday, 28-Feb-18 09:01:00 MST", out: "2018-02-28 16:01:00 +0000 UTC", loc: "America/Denver"}, + // with offset then with variations on non-zero filled stuff + {in: "Monday, 02 Jan 2006 15:04:05 +0100", out: "2006-01-02 14:04:05 +0000 UTC"}, + {in: "Wednesday, 28 Feb 2018 09:01:00 -0300", out: "2018-02-28 12:01:00 +0000 UTC"}, + {in: "Wednesday, 2 Feb 2018 09:01:00 -0300", out: "2018-02-02 12:01:00 +0000 UTC"}, + {in: "Wednesday, 2 Feb 2018 9:01:00 -0300", out: "2018-02-02 12:01:00 +0000 UTC"}, + {in: "Wednesday, 2 Feb 2018 09:1:00 -0300", out: "2018-02-02 12:01:00 +0000 UTC"}, + // 12 Feb 2006, 19:17:08 + {in: "07 Feb 2004, 09:07", out: "2004-02-07 09:07:00 +0000 UTC"}, + {in: "07 Feb 2004, 09:07:07", out: "2004-02-07 09:07:07 +0000 UTC"}, + {in: "7 Feb 2004, 09:07:07", out: "2004-02-07 09:07:07 +0000 UTC"}, + {in: "07 Feb 2004, 9:7:7", out: "2004-02-07 09:07:07 +0000 UTC"}, + // 12 Feb 2006, 19:17:08 GMT + {in: "07 Feb 2004, 09:07:07 GMT", out: "2004-02-07 09:07:07 +0000 UTC"}, + // 12 Feb 2006, 19:17:08 +0100 + {in: "07 Feb 2004, 09:07:07 +0100", out: "2004-02-07 08:07:07 +0000 UTC"}, + // 2013-Feb-03 + {in: "2013-Feb-03", out: "2013-02-03 00:00:00 +0000 UTC"}, + // 03 February 2013 + {in: "03 February 2013", out: "2013-02-03 00:00:00 +0000 UTC"}, + {in: "3 February 2013", out: "2013-02-03 00:00:00 +0000 UTC"}, + // Chinese 2014年04月18日 + {in: "2014年04月08日", out: "2014-04-08 00:00:00 +0000 UTC"}, + {in: "2014年04月08日 19:17:22", out: "2014-04-08 19:17:22 +0000 UTC"}, + // mm/dd/yyyy + {in: "03/31/2014", out: "2014-03-31 00:00:00 +0000 UTC"}, + {in: "3/31/2014", out: "2014-03-31 00:00:00 +0000 UTC"}, + {in: "3/5/2014", out: "2014-03-05 00:00:00 +0000 UTC"}, + // mm/dd/yy + {in: "08/08/71", out: "1971-08-08 00:00:00 +0000 UTC"}, + {in: "8/8/71", out: "1971-08-08 00:00:00 +0000 UTC"}, + // mm/dd/yy hh:mm:ss + {in: "04/02/2014 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "4/2/2014 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "04/02/2014 4:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "04/02/2014 4:8:9", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "04/02/2014 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "04/02/2014 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "04/02/2014 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, + {in: "04/02/2014 04:08:09.12312", out: "2014-04-02 04:08:09.12312 +0000 UTC"}, + {in: "04/02/2014 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, + // mm/dd/yy hh:mm:ss AM + {in: "04/02/2014 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "04/02/2014 04:08:09 PM", out: "2014-04-02 16:08:09 +0000 UTC"}, + {in: "04/02/2014 04:08 AM", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "04/02/2014 04:08 PM", out: "2014-04-02 16:08:00 +0000 UTC"}, + {in: "04/02/2014 4:8 AM", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "04/02/2014 4:8 PM", out: "2014-04-02 16:08:00 +0000 UTC"}, + {in: "04/02/2014 04:08:09.123 AM", out: "2014-04-02 04:08:09.123 +0000 UTC"}, + {in: "04/02/2014 04:08:09.123 PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, + // yyyy/mm/dd + {in: "2014/04/02", out: "2014-04-02 00:00:00 +0000 UTC"}, + {in: "2014/03/31", out: "2014-03-31 00:00:00 +0000 UTC"}, + {in: "2014/4/2", out: "2014-04-02 00:00:00 +0000 UTC"}, + // yyyy/mm/dd hh:mm:ss AM + {in: "2014/04/02 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "2014/03/31 04:08", out: "2014-03-31 04:08:00 +0000 UTC"}, + {in: "2014/4/2 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "2014/04/02 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "2014/04/02 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014/03/31 04:08:09", out: "2014-03-31 04:08:09 +0000 UTC"}, + {in: "2014/4/2 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014/04/02 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, + {in: "2014/04/02 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, + {in: "2014/04/02 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014/03/31 04:08:09 AM", out: "2014-03-31 04:08:09 +0000 UTC"}, + {in: "2014/4/2 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014/04/02 04:08:09.123 AM", out: "2014-04-02 04:08:09.123 +0000 UTC"}, + {in: "2014/04/02 04:08:09.123 PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, + // yyyy-mm-dd + {in: "2014-04-02", out: "2014-04-02 00:00:00 +0000 UTC"}, + {in: "2014-03-31", out: "2014-03-31 00:00:00 +0000 UTC"}, + {in: "2014-4-2", out: "2014-04-02 00:00:00 +0000 UTC"}, + // yyyy-mm + {in: "2014-04", out: "2014-04-01 00:00:00 +0000 UTC"}, + // yyyy-mm-dd hh:mm:ss AM + {in: "2014-04-02 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "2014-03-31 04:08", out: "2014-03-31 04:08:00 +0000 UTC"}, + {in: "2014-4-2 04:08", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "2014-04-02 4:8", out: "2014-04-02 04:08:00 +0000 UTC"}, + {in: "2014-04-02 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014-03-31 04:08:09", out: "2014-03-31 04:08:09 +0000 UTC"}, + {in: "2014-4-2 04:08:09", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014-04-02 04:08:09.123", out: "2014-04-02 04:08:09.123 +0000 UTC"}, + {in: "2014-04-02 04:08:09.123123", out: "2014-04-02 04:08:09.123123 +0000 UTC"}, + {in: "2014-04-02 04:08:09.12312312", out: "2014-04-02 04:08:09.12312312 +0000 UTC"}, + {in: "2014-04-02 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014-03-31 04:08:09 AM", out: "2014-03-31 04:08:09 +0000 UTC"}, + {in: "2014-04-26 05:24:37 PM", out: "2014-04-26 17:24:37 +0000 UTC"}, + {in: "2014-4-2 04:08:09 AM", out: "2014-04-02 04:08:09 +0000 UTC"}, + {in: "2014-04-02 04:08:09.123 AM", out: "2014-04-02 04:08:09.123 +0000 UTC"}, + {in: "2014-04-02 04:08:09.123 PM", out: "2014-04-02 16:08:09.123 +0000 UTC"}, + // yyyy-mm-dd hh:mm:ss,000 + {in: "2014-05-11 08:20:13,787", out: "2014-05-11 08:20:13.787 +0000 UTC"}, + // yyyy-mm-dd hh:mm:ss +0000 + {in: "2012-08-03 18:31:59 +0000", out: "2012-08-03 18:31:59 +0000 UTC"}, + {in: "2012-08-03 13:31:59 -0600", out: "2012-08-03 19:31:59 +0000 UTC"}, + {in: "2012-08-03 18:31:59.257000000 +0000", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-08-03 8:1:59.257000000 +0000", out: "2012-08-03 08:01:59.257 +0000 UTC"}, + {in: "2012-8-03 18:31:59.257000000 +0000", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-8-3 18:31:59.257000000 +0000", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2014-04-26 17:24:37.123456 +0000", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, + {in: "2014-04-26 17:24:37.12 +0000", out: "2014-04-26 17:24:37.12 +0000 UTC"}, + {in: "2014-04-26 17:24:37.1 +0000", out: "2014-04-26 17:24:37.1 +0000 UTC"}, + {in: "2014-05-11 08:20:13 +0000", out: "2014-05-11 08:20:13 +0000 UTC"}, + + // 13:31:51.999 -07:00 MST + // yyyy-mm-dd hh:mm:ss +00:00 + {in: "2012-08-03 18:31:59 +00:00", out: "2012-08-03 18:31:59 +0000 UTC"}, + {in: "2014-05-01 08:02:13 +00:00", out: "2014-05-01 08:02:13 +0000 UTC"}, + {in: "2014-5-01 08:02:13 +00:00", out: "2014-05-01 08:02:13 +0000 UTC"}, + {in: "2014-05-1 08:02:13 +00:00", out: "2014-05-01 08:02:13 +0000 UTC"}, + {in: "2012-08-03 13:31:59 -06:00", out: "2012-08-03 19:31:59 +0000 UTC"}, + {in: "2012-08-03 18:31:59.257000000 +00:00", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-08-03 8:1:59.257000000 +00:00", out: "2012-08-03 08:01:59.257 +0000 UTC"}, + {in: "2012-8-03 18:31:59.257000000 +00:00", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-8-3 18:31:59.257000000 +00:00", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2014-04-26 17:24:37.123456 +00:00", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, + {in: "2014-04-26 17:24:37.12 +00:00", out: "2014-04-26 17:24:37.12 +0000 UTC"}, + {in: "2014-04-26 17:24:37.1 +00:00", out: "2014-04-26 17:24:37.1 +0000 UTC"}, + // yyyy-mm-dd hh:mm:ss +0000 TZ + // Golang Native Format + {in: "2012-08-03 18:31:59 +0000 UTC", out: "2012-08-03 18:31:59 +0000 UTC"}, + {in: "2012-08-03 13:31:59 -0600 MST", out: "2012-08-03 19:31:59 +0000 UTC", loc: "America/Denver"}, + {in: "2015-02-18 00:12:00 +0000 UTC", out: "2015-02-18 00:12:00 +0000 UTC"}, + {in: "2015-02-18 00:12:00 +0000 GMT", out: "2015-02-18 00:12:00 +0000 UTC"}, + {in: "2015-02-08 03:02:00 +0200 CEST", out: "2015-02-08 01:02:00 +0000 UTC", loc: "Europe/Berlin"}, + {in: "2015-02-08 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC"}, + {in: "2015-2-08 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC"}, + {in: "2015-02-8 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC"}, + {in: "2015-2-8 03:02:00 +0300 MSK", out: "2015-02-08 00:02:00 +0000 UTC"}, + {in: "2012-08-03 18:31:59.257000000 +0000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-08-03 8:1:59.257000000 +0000 UTC", out: "2012-08-03 08:01:59.257 +0000 UTC"}, + {in: "2012-8-03 18:31:59.257000000 +0000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-8-3 18:31:59.257000000 +0000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2014-04-26 17:24:37.123456 +0000 UTC", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, + {in: "2014-04-26 17:24:37.12 +0000 UTC", out: "2014-04-26 17:24:37.12 +0000 UTC"}, + {in: "2014-04-26 17:24:37.1 +0000 UTC", out: "2014-04-26 17:24:37.1 +0000 UTC"}, + // yyyy-mm-dd hh:mm:ss TZ + {in: "2012-08-03 18:31:59 UTC", out: "2012-08-03 18:31:59 +0000 UTC"}, + {in: "2014-12-16 06:20:00 GMT", out: "2014-12-16 06:20:00 +0000 UTC"}, + {in: "2012-08-03 13:31:59 MST", out: "2012-08-03 20:31:59 +0000 UTC", loc: "America/Denver"}, + {in: "2012-08-03 18:31:59.257000000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-08-03 8:1:59.257000000 UTC", out: "2012-08-03 08:01:59.257 +0000 UTC"}, + {in: "2012-8-03 18:31:59.257000000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-8-3 18:31:59.257000000 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2014-04-26 17:24:37.123456 UTC", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, + {in: "2014-04-26 17:24:37.12 UTC", out: "2014-04-26 17:24:37.12 +0000 UTC"}, + {in: "2014-04-26 17:24:37.1 UTC", out: "2014-04-26 17:24:37.1 +0000 UTC"}, + // This one is pretty special, it is TIMEZONE based but starts with P to emulate collions with PM + {in: "2014-04-26 05:24:37 PST", out: "2014-04-26 05:24:37 +0000 UTC"}, + {in: "2014-04-26 05:24:37 PST", out: "2014-04-26 12:24:37 +0000 UTC", loc: "America/Los_Angeles"}, + // yyyy-mm-dd hh:mm:ss+00:00 + {in: "2012-08-03 18:31:59+00:00", out: "2012-08-03 18:31:59 +0000 UTC"}, + {in: "2017-07-19 03:21:51+00:00", out: "2017-07-19 03:21:51 +0000 UTC"}, + // yyyy-mm-dd hh:mm:ss.000+00:00 PST + {in: "2012-08-03 18:31:59.000+00:00 PST", out: "2012-08-03 18:31:59 +0000 UTC", loc: "America/Los_Angeles"}, + // yyyy-mm-dd hh:mm:ss +00:00 TZ + {in: "2012-08-03 18:31:59 +00:00 UTC", out: "2012-08-03 18:31:59 +0000 UTC"}, + {in: "2012-08-03 13:31:51 -07:00 MST", out: "2012-08-03 20:31:51 +0000 UTC", loc: "America/Denver"}, + {in: "2012-08-03 18:31:59.257000000 +00:00 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {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"}, + {in: "2012-08-03 13:31:51.123 +02:00 CEST", out: "2012-08-03 11:31:51.123 +0000 UTC", loc: "Europe/Berlin"}, + {in: "2012-08-03 8:1:59.257000000 +00:00 UTC", out: "2012-08-03 08:01:59.257 +0000 UTC"}, + {in: "2012-8-03 18:31:59.257000000 +00:00 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2012-8-3 18:31:59.257000000 +00:00 UTC", out: "2012-08-03 18:31:59.257 +0000 UTC"}, + {in: "2014-04-26 17:24:37.123456 +00:00 UTC", out: "2014-04-26 17:24:37.123456 +0000 UTC"}, + {in: "2014-04-26 17:24:37.12 +00:00 UTC", out: "2014-04-26 17:24:37.12 +0000 UTC"}, + {in: "2014-04-26 17:24:37.1 +00:00 UTC", out: "2014-04-26 17:24:37.1 +0000 UTC"}, + // yyyy-mm-ddThh:mm:ss + {in: "2009-08-12T22:15:09", out: "2009-08-12 22:15:09 +0000 UTC"}, + {in: "2009-08-08T02:08:08", out: "2009-08-08 02:08:08 +0000 UTC"}, + {in: "2009-08-08T2:8:8", out: "2009-08-08 02:08:08 +0000 UTC"}, + {in: "2009-08-12T22:15:09.123", out: "2009-08-12 22:15:09.123 +0000 UTC"}, + {in: "2009-08-12T22:15:09.123456", out: "2009-08-12 22:15:09.123456 +0000 UTC"}, + {in: "2009-08-12T22:15:09.12", out: "2009-08-12 22:15:09.12 +0000 UTC"}, + {in: "2009-08-12T22:15:09.1", out: "2009-08-12 22:15:09.1 +0000 UTC"}, + {in: "2014-04-26 17:24:37.3186369", out: "2014-04-26 17:24:37.3186369 +0000 UTC"}, + // yyyy-mm-ddThh:mm:ss-07:00 + {in: "2009-08-12T22:15:09-07:00", out: "2009-08-13 05:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:09-03:00", out: "2009-08-13 01:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:9-07:00", out: "2009-08-13 05:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:09.123-07:00", out: "2009-08-13 05:15:09.123 +0000 UTC"}, + {in: "2016-06-21T19:55:00+01:00", out: "2016-06-21 18:55:00 +0000 UTC"}, + {in: "2016-06-21T19:55:00.799+01:00", out: "2016-06-21 18:55:00.799 +0000 UTC"}, + // yyyy-mm-ddThh:mm:ss-0700 + {in: "2009-08-12T22:15:09-0700", out: "2009-08-13 05:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:09-0300", out: "2009-08-13 01:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:9-0700", out: "2009-08-13 05:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:09.123-0700", out: "2009-08-13 05:15:09.123 +0000 UTC"}, + {in: "2016-06-21T19:55:00+0100", out: "2016-06-21 18:55:00 +0000 UTC"}, + {in: "2016-06-21T19:55:00.799+0100", out: "2016-06-21 18:55:00.799 +0000 UTC"}, + {in: "2016-06-21T19:55:00+0100", out: "2016-06-21 18:55:00 +0000 UTC"}, + {in: "2016-06-21T19:55:00-0700", out: "2016-06-22 02:55:00 +0000 UTC"}, + {in: "2016-06-21T19:55:00.799+0100", out: "2016-06-21 18:55:00.799 +0000 UTC"}, + // yyyy-mm-ddThh:mm:ssZ + {in: "2009-08-12T22:15Z", out: "2009-08-12 22:15:00 +0000 UTC"}, + {in: "2009-08-12T22:15:09Z", out: "2009-08-12 22:15:09 +0000 UTC"}, + {in: "2009-08-12T22:15:09.99Z", out: "2009-08-12 22:15:09.99 +0000 UTC"}, + {in: "2009-08-12T22:15:09.9999Z", out: "2009-08-12 22:15:09.9999 +0000 UTC"}, + {in: "2009-08-12T22:15:09.99999999Z", out: "2009-08-12 22:15:09.99999999 +0000 UTC"}, + {in: "2009-08-12T22:15:9.99999999Z", out: "2009-08-12 22:15:09.99999999 +0000 UTC"}, + // mm.dd.yyyy + {in: "3.31.2014", out: "2014-03-31 00:00:00 +0000 UTC"}, + {in: "3.3.2014", out: "2014-03-03 00:00:00 +0000 UTC"}, + {in: "03.31.2014", out: "2014-03-31 00:00:00 +0000 UTC"}, + // mm.dd.yy + {in: "08.21.71", out: "1971-08-21 00:00:00 +0000 UTC"}, + // yyyymmdd and similar + {in: "2014", out: "2014-01-01 00:00:00 +0000 UTC"}, + {in: "20140601", out: "2014-06-01 00:00:00 +0000 UTC"}, + // all digits: unix secs, ms etc + {in: "1332151919", out: "2012-03-19 10:11:59 +0000 UTC"}, + {in: "1332151919", out: "2012-03-19 10:11:59 +0000 UTC", loc: "America/Denver"}, + {in: "1384216367111", out: "2013-11-12 00:32:47.111 +0000 UTC"}, + {in: "1384216367111222", out: "2013-11-12 00:32:47.111222 +0000 UTC"}, + {in: "1384216367111222333", out: "2013-11-12 00:32:47.111222333 +0000 UTC"}, +} + +/* + {in: , out: }, + + +*/ func TestParse(t *testing.T) { // Lets ensure we are operating on UTC @@ -117,500 +422,45 @@ func TestParse(t *testing.T) { assert.NotEqual(t, nil, err) assert.Equal(t, true, testDidPanic("NOT GONNA HAPPEN")) - - // TODO: Is a utf8 date valid? - // ts = MustParse("2014-04\u221226") - // assert.Equal(t, "2014-04-26 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("May 8, 2009 5:57:51 PM") - assert.Equal(t, "2009-05-08 17:57:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("May 8, 2009 5:57:1 PM") - assert.Equal(t, "2009-05-08 17:57:01 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("May 8, 2009 5:7:51 PM") - assert.Equal(t, "2009-05-08 17:07:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // ANSIC = "Mon Jan _2 15:04:05 2006" - ts = MustParse("Mon Jan 2 15:04:05 2006") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // RubyDate = "Mon Jan 02 15:04:05 -0700 2006" - ts = MustParse("Mon Jan 02 15:04:05 -0700 2006") - assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)), "%v") - - // UnixDate = "Mon Jan _2 15:04:05 MST 2006" - ts = MustParse("Mon Jan 2 15:04:05 MST 2006") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // RFC850 = "Monday, 02-Jan-06 15:04:05 MST" - ts = MustParse("Monday, 02-Jan-06 15:04:05 MST") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // ST_WEEKDAYCOMMADELTA - // Monday, 02 Jan 2006 15:04:05 -0700 - // Monday, 02 Jan 2006 15:04:05 +0100 - ts = MustParse("Monday, 02 Jan 2006 15:04:05 +0100") - assert.Equal(t, "2006-01-02 14:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("Monday, 02 Jan 2006 15:04:5 +0100") - assert.Equal(t, "2006-01-02 14:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("Monday, 02 Jan 2006 15:4:05 +0100") - assert.Equal(t, "2006-01-02 14:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("Monday, 02 Jan 2006 15:04:05 -0100") - assert.Equal(t, "2006-01-02 16:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // Another weird one, year on the end after UTC? - ts = MustParse("Mon Aug 10 15:44:11 UTC+0100 2015") - assert.Equal(t, "2015-08-10 15:44:11 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // Easily the worst Date format i have ever seen - // "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)" - ts = MustParse("Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)") - assert.Equal(t, "2015-07-03 17:04:07 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Mon, 02 Jan 2006 15:04:05 MST") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Mon, 2 Jan 2006 15:4:05 MST") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Mon, 2 Jan 2006 15:4:5 MST") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Mon, 02-Jan-06 15:04:05 MST") - assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Tue, 11 Jul 2017 16:28:13 +0200 (CEST)") - assert.Equal(t, "2017-07-11 14:28:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Tue, 5 Jul 2017 16:28:13 -0700 (CEST)") - assert.Equal(t, "2017-07-05 23:28:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Thu, 13 Jul 2017 08:58:40 +0100") - assert.Equal(t, "2017-07-13 07:58:40 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Mon, 02 Jan 2006 15:04:05 -0700") - assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("Mon, 02 Jan 2006 15:4:05 -0700") - assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("Mon, 02 Jan 2006 15:4:5 -0700") - assert.Equal(t, "2006-01-02 22:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("Thu, 4 Jan 2018 17:53:36 +0000") - assert.Equal(t, "2018-01-04 17:53:36 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // not sure if this is anything close to a standard, never seen it before - ts = MustParse("12 Feb 2006, 19:17") - assert.Equal(t, "2006-02-12 19:17:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2 Feb 2006, 19:17") - assert.Equal(t, "2006-02-02 19:17:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("12 Feb 2006, 19:17:22") - assert.Equal(t, "2006-02-12 19:17:22 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2 Feb 2006, 19:17:22") - assert.Equal(t, "2006-02-02 19:17:22 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("12 Feb 2006 19:17") - assert.Equal(t, "2006-02-12 19:17:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2 Feb 2006 19:17") - assert.Equal(t, "2006-02-02 19:17:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("12 Feb 2006 19:17:22") - assert.Equal(t, "2006-02-12 19:17:22 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2 Feb 2006 19:17:22") - assert.Equal(t, "2006-02-02 19:17:22 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2013-Feb-03") - assert.Equal(t, "2013-02-03 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("03 February 2013") - assert.Equal(t, "2013-02-03 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("3 February 2013") - assert.Equal(t, "2013-02-03 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - //--------------------------------------------- - // Chinese 2014年04月18日 - - ts = MustParse("2014年04月08日") - assert.Equal(t, "2014-04-08 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014年04月08日 19:17:22") - assert.Equal(t, "2014-04-08 19:17:22 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - //--------------------------------------------- - // mm/dd/yyyy ? - - ts = MustParse("3/31/2014") - assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("03/31/2014") - assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // what type of date is this? 08/21/71 - ts = MustParse("08/21/71") - assert.Equal(t, "1971-08-21 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // m/d/yy - ts = MustParse("8/1/71") - assert.Equal(t, "1971-08-01 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("4/8/2014 22:05") - assert.Equal(t, "2014-04-08 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("4/18/2014 22:05") - assert.Equal(t, "2014-04-18 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("04/08/2014 22:05") - assert.Equal(t, "2014-04-08 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("4/8/14 22:05") - assert.Equal(t, "2014-04-08 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("4/18/14 22:05") - assert.Equal(t, "2014-04-18 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("10/18/14 22:05") - assert.Equal(t, "2014-10-18 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("04/2/2014 4:00:51") - assert.Equal(t, "2014-04-02 04:00:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("8/8/1965 01:00:01 PM") - assert.Equal(t, "1965-08-08 13:00:01 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("8/8/1965 12:00:01 AM") - assert.Equal(t, "1965-08-08 00:00:01 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("8/8/1965 01:00 PM") - assert.Equal(t, "1965-08-08 13:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("08/8/1965 01:00 PM") - assert.Equal(t, "1965-08-08 13:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("8/08/1965 1:00 PM") - assert.Equal(t, "1965-08-08 13:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("8/8/1965 12:00 AM") - assert.Equal(t, "1965-08-08 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("8/13/1965 01:00 PM") - assert.Equal(t, "1965-08-13 13:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("4/02/2014 03:00:51") - assert.Equal(t, "2014-04-02 03:00:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("03/19/2012 10:11:59") - assert.Equal(t, "2012-03-19 10:11:59 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("03/19/2012 10:11:59.3186369") - assert.Equal(t, "2012-03-19 10:11:59.3186369 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - //--------------------------------------------- - // yyyy/mm/dd ? - - ts = MustParse("2014/3/31") - assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014/03/31") - assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014/4/8 22:05") - assert.Equal(t, "2014-04-08 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014/4/8 2:05") - assert.Equal(t, "2014-04-08 02:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014/04/08 22:05") - assert.Equal(t, "2014-04-08 22:05:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014/04/2 03:00:51") - assert.Equal(t, "2014-04-02 03:00:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014/4/02 03:00:51") - assert.Equal(t, "2014-04-02 03:00:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 10:11:59") - assert.Equal(t, "2012-03-19 10:11:59 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 10:11:59.318") - assert.Equal(t, "2012-03-19 10:11:59.318 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 10:11:59.3186369") - assert.Equal(t, "2012-03-19 10:11:59.3186369 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 10:11:59.318636945") - assert.Equal(t, "2012-03-19 10:11:59.318636945 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 10:11 PM") - assert.Equal(t, "2012-03-19 22:11:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 1:11 PM") - assert.Equal(t, "2012-03-19 13:11:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/3/19 10:11 PM") - assert.Equal(t, "2012-03-19 22:11:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/3/3 10:11 PM") - assert.Equal(t, "2012-03-03 22:11:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/19 10:11:59 PM") - assert.Equal(t, "2012-03-19 22:11:59 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/3/3 10:11:59 PM") - assert.Equal(t, "2012-03-03 22:11:59 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012/03/03 10:11:59.345 PM") - assert.Equal(t, "2012-03-03 22:11:59.345 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - //--------------------------------------------- - // yyyy-mm-dd ? - ts = MustParse("2009-08-12T22:15:09-07:00") - assert.Equal(t, "2009-08-13 05:15:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:9-07:00") - assert.Equal(t, "2009-08-13 05:15:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:09.123-07:00") - assert.Equal(t, "2009-08-13 05:15:09.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)), "%v", ts.In(time.UTC)) - - ts = MustParse("2009-08-12T22:15Z") - assert.Equal(t, "2009-08-12 22:15:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)), "%v", ts.In(time.UTC)) - - ts = MustParse("2009-08-12T22:15:09Z") - assert.Equal(t, "2009-08-12 22:15:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)), "%v", ts.In(time.UTC)) - - ts = MustParse("2009-08-12T22:15:09.99Z") - assert.Equal(t, "2009-08-12 22:15:09.99 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:09.9999Z") - assert.Equal(t, "2009-08-12 22:15:09.9999 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:09.99999999Z") - assert.Equal(t, "2009-08-12 22:15:09.99999999 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:9.99999999Z") - assert.Equal(t, "2009-08-12 22:15:09.99999999 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - // https://github.com/golang/go/issues/5294 _, err = ParseAny(time.RFC3339) assert.NotEqual(t, nil, err) - ts = MustParse("2009-08-12T22:15:09.123") - assert.Equal(t, "2009-08-12 22:15:09.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) + for _, th := range testInputs { + if len(th.loc) > 0 { + loc, err := time.LoadLocation(th.loc) + if err != nil { + t.Fatalf("Expected to load location %q but got %v", th.loc, err) + } + ts, err = ParseIn(th.in, loc) + if err != nil { + t.Fatalf("expected to parse %q but got %v", th.in, err) + } + got := fmt.Sprintf("%v", ts.In(time.UTC)) + assert.Equal(t, th.out, got, "Expected %q but got %q from %q", th.out, got, th.in) + if th.out != got { + panic("whoops") + } + } else { + ts = MustParse(th.in) + got := fmt.Sprintf("%v", ts.In(time.UTC)) + assert.Equal(t, th.out, got, "Expected %q but got %q from %q", th.out, got, th.in) + if th.out != got { + panic("whoops") + } + } + } - ts = MustParse("2009-08-12T22:15:09.123456") - assert.Equal(t, "2009-08-12 22:15:09.123456 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:09.12") - assert.Equal(t, "2009-08-12 22:15:09.12 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:09.1") - assert.Equal(t, "2009-08-12 22:15:09.1 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2009-08-12T22:15:09") - assert.Equal(t, "2009-08-12 22:15:09 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.3186369") - assert.Equal(t, "2014-04-26 17:24:37.3186369 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // 2015-06-25 01:25:37.115208593 +0000 UTC - ts = MustParse("2012-08-03 18:31:59.257000000 +0000 UTC") - assert.Equal(t, "2012-08-03 18:31:59.257 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012-08-03 8:1:59.257000000 +0000 UTC") - assert.Equal(t, "2012-08-03 08:01:59.257 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012-8-03 18:31:59.257000000 +0000 UTC") - assert.Equal(t, "2012-08-03 18:31:59.257 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012-8-3 18:31:59.257000000 +0000 UTC") - assert.Equal(t, "2012-08-03 18:31:59.257 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2015-09-30 18:48:56.35272715 +0000 UTC") - assert.Equal(t, "2015-09-30 18:48:56.35272715 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2017-01-27 00:07:31.945167") - assert.Equal(t, "2017-01-27 00:07:31.945167 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2012-08-03 18:31:59.257000000") - assert.Equal(t, "2012-08-03 18:31:59.257 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2013-04-01 22:43") - assert.Equal(t, "2013-04-01 22:43:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2013-04-01 22:43:22") - assert.Equal(t, "2013-04-01 22:43:22 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123") - assert.Equal(t, "2014-04-26 17:24:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123456 +0000 UTC") - assert.Equal(t, "2014-04-26 17:24:37.123456 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123456 UTC") - assert.Equal(t, "2014-04-26 17:24:37.123456 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123 UTC") - assert.Equal(t, "2014-04-26 17:24:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.12 UTC") - assert.Equal(t, "2014-04-26 17:24:37.12 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.1 UTC") - assert.Equal(t, "2014-04-26 17:24:37.1 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 09:04:37.123 +0800") - assert.Equal(t, "2014-04-26 01:04:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2014-04-26 9:04:37.123 +0800") - assert.Equal(t, "2014-04-26 01:04:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2014-04-26 09:4:37.123 +0800") - assert.Equal(t, "2014-04-26 01:04:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2014-04-26 9:4:37.123 +0800") - assert.Equal(t, "2014-04-26 01:04:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123 -0800") - assert.Equal(t, "2014-04-27 01:24:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123456 +0800") - assert.Equal(t, "2014-04-26 09:24:37.123456 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 17:24:37.123456 -0800") - assert.Equal(t, "2014-04-27 01:24:37.123456 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2017-07-19 03:21:51+00:00") - assert.Equal(t, "2017-07-19 03:21:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2017-07-09 03:01:51 +00:00 UTC") - assert.Equal(t, "2017-07-09 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2017-7-09 03:01:51 +00:00 UTC") - assert.Equal(t, "2017-07-09 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2017-07-9 03:01:51 +00:00 UTC") - assert.Equal(t, "2017-07-09 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2017-7-9 03:01:51 +00:00 UTC") - assert.Equal(t, "2017-07-09 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2017-07-19 03:01:51 +00:00 UTC") - assert.Equal(t, "2017-07-19 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2017-07-19 3:01:51 +00:00 UTC") - assert.Equal(t, "2017-07-19 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2017-07-19 03:1:51 +00:00 UTC") - assert.Equal(t, "2017-07-19 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2017-07-19 3:1:51 +00:00 UTC") - assert.Equal(t, "2017-07-19 03:01:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // Golang Native Format - ts = MustParse("2015-02-18 00:12:00 +0000 UTC") - assert.Equal(t, "2015-02-18 00:12:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2015-02-18 00:12:00 +0000 GMT") - assert.Equal(t, "2015-02-18 00:12:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2015-02-08 03:02:00 +0300 MSK") - assert.Equal(t, "2015-02-08 00:02:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2015-2-08 03:02:00 +0300 MSK") - assert.Equal(t, "2015-02-08 00:02:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2015-02-8 03:02:00 +0300 MSK") - assert.Equal(t, "2015-02-08 00:02:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2015-2-8 03:02:00 +0300 MSK") - assert.Equal(t, "2015-02-08 00:02:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-12-16 06:20:00 UTC") - assert.Equal(t, "2014-12-16 06:20:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-12-16 06:20:00 GMT") - assert.Equal(t, "2014-12-16 06:20:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-12-16 06:20:00 +0000 UTC") - assert.Equal(t, "2014-12-16 06:20:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26 05:24:37 PM") - assert.Equal(t, "2014-04-26 17:24:37 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // This one is pretty special, it is TIMEZONE based but starts with P to emulate collions with PM - ts = MustParse("2014-04-26 05:24:37 PST") - assert.Equal(t, "2014-04-26 05:24:37 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04-26") - assert.Equal(t, "2014-04-26 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-04") - assert.Equal(t, "2014-04-01 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-05-11 08:20:13,787") - assert.Equal(t, "2014-05-11 08:20:13.787 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - _, err = ParseAny("2014-13-13 08:20:13,787") // month 13 doesn't exist so error - assert.NotEqual(t, nil, err) - - ts = MustParse("2014-05-01 08:02:13 +00:00") - assert.Equal(t, "2014-05-01 08:02:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2014-5-01 08:02:13 +00:00") - assert.Equal(t, "2014-05-01 08:02:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2014-05-1 08:02:13 +00:00") - assert.Equal(t, "2014-05-01 08:02:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - ts = MustParse("2014-5-1 08:02:13 +00:00") - assert.Equal(t, "2014-05-01 08:02:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2014-05-11 08:20:13 +0000") - assert.Equal(t, "2014-05-11 08:20:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2016-06-21T19:55:00+01:00") - assert.Equal(t, "2016-06-21 18:55:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2016-06-21T19:55:00.799+01:00") - assert.Equal(t, "2016-06-21 18:55:00.799 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2016-06-21T19:55:00+0100") - assert.Equal(t, "2016-06-21 18:55:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2016-06-21T19:55:00-0700") - assert.Equal(t, "2016-06-22 02:55:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("2016-06-21T19:55:00.799+0100") - assert.Equal(t, "2016-06-21 18:55:00.799 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - //--------------------------------------------- - // mm.dd.yyyy - // mm.dd.yy - - ts = MustParse("3.31.2014") - assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("03.31.2014") - assert.Equal(t, "2014-03-31 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("08.21.71") - assert.Equal(t, "1971-08-21 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - //--------------------------------------------- - - // yyyymmdd and similar - ts = MustParse("2014") - assert.Equal(t, "2014-01-01 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("20140601") - assert.Equal(t, "2014-06-01 00:00:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("1332151919") - assert.Equal(t, "2012-03-19 10:11:59 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("1384216367111") - assert.Equal(t, "2013-11-12 00:32:47.111 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts, _ = ParseIn("1384216367111", time.UTC) - assert.Equal(t, "2013-11-12 00:32:47.111 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - ts = MustParse("1384216367111222") - assert.Equal(t, "2013-11-12 00:32:47.111222 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) - - // Nanoseconds - ts = MustParse("1384216367111222333") - assert.Equal(t, "2013-11-12 00:32:47.111222333 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) + // some errors _, err = ParseAny("138421636711122233311111") // too many digits assert.NotEqual(t, nil, err) _, err = ParseAny("-1314") assert.NotEqual(t, nil, err) + + _, err = ParseAny("2014-13-13 08:20:13,787") // month 13 doesn't exist so error + assert.NotEqual(t, nil, err) } func testDidPanic(datestr string) (paniced bool) { @@ -622,3 +472,22 @@ func testDidPanic(datestr string) (paniced bool) { MustParse(datestr) return false } + +func TestPStruct(t *testing.T) { + + denverLoc, err := time.LoadLocation("America/Denver") + assert.Equal(t, nil, err) + + p := newParser("08.21.71", denverLoc) + + p.setMonth() + assert.Equal(t, 0, p.moi) + p.setDay() + assert.Equal(t, 0, p.dayi) + p.set(-1, "not") + p.set(15, "not") + assert.Equal(t, "08.21.71", p.datestr) + assert.Equal(t, "08.21.71", string(p.format)) + assert.True(t, len(p.ds()) > 0) + assert.True(t, len(p.ts()) > 0) +}