Fix a bad parse date, closes #40

This commit is contained in:
Aaron Raddon 2018-02-13 20:44:26 -08:00
parent 036f821411
commit 3fd9518a70
2 changed files with 172 additions and 82 deletions

View File

@ -129,7 +129,7 @@ func parseTime(datestr string, loc *time.Location) (time.Time, error) {
part1Len := 0 part1Len := 0
part2Len := 0 part2Len := 0
dayLen := 0 part3Len := 0
// General strategy is to read rune by rune through the date looking for // General strategy is to read rune by rune through the date looking for
// certain hints of what type of date we are dealing with. // certain hints of what type of date we are dealing with.
@ -162,6 +162,7 @@ iterRunes:
switch r { switch r {
case '-', '\u2212': case '-', '\u2212':
state = stateDigitDash state = stateDigitDash
part1Len = i
case '/': case '/':
state = stateDigitSlash state = stateDigitSlash
part1Len = i part1Len = i
@ -174,22 +175,28 @@ iterRunes:
} }
case stateDigitDash: // starts digit then dash 02- case stateDigitDash: // starts digit then dash 02-
// 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
// 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
// 2006-01-02 // 2006-01-02
// 2013-04-01 22:43:22 // stateDigitDashT
// 2014-04-26 05:24:37 PM // 2006-01-02T15:04:05Z07:00
// 2013-Feb-03 // 2017-06-25T17:46:57.45706582-07:00
// 2006-01-02T15:04:05.999999999Z07:00
// 2006-01-02T15:04:05+0000
// stateDigitDashWs
// 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
// stateDigitDashAlpha
// 2013-Feb-03
switch { switch {
case r == '-':
part2Len = i - part1Len - 1
case r == ' ': case r == ' ':
part3Len = i - part1Len - part2Len - 1 - 1
state = stateDigitDashWs state = stateDigitDashWs
case r == 'T': case r == 'T':
state = stateDigitDashT state = stateDigitDashT
@ -555,8 +562,8 @@ iterRunes:
// stateWeekdayAbbrevCommaOffsetZone // stateWeekdayAbbrevCommaOffsetZone
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST) // Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
switch { switch {
case r == ' ' && dayLen == 0: case r == ' ' && part3Len == 0:
dayLen = i - part1Len - 2 part3Len = i - part1Len - 2
case r == '-': case r == '-':
if i < 15 { if i < 15 {
state = stateWeekdayAbbrevCommaDash state = stateWeekdayAbbrevCommaDash
@ -915,69 +922,116 @@ iterRunes:
case stateDigitDashWsWsOffsetColon: case stateDigitDashWsWsOffsetColon:
// 2006-01-02 15:04:05 -07:00 // 2006-01-02 15:04:05 -07:00
for _, layout := range []string{ switch {
"2006-01-02 15:04:05 -07:00", case part2Len == 2 && part3Len == 2:
"2006-01-02 15:04:5 -07:00", for _, layout := range []string{
"2006-01-02 15:4:05 -07:00", "2006-01-02 15:04:05 -07:00",
"2006-01-02 15:4:5 -07:00", "2006-01-02 15:04:5 -07:00",
"2006-1-02 15:04:05 -07:00", "2006-01-02 15:4:05 -07:00",
"2006-1-02 15:4:05 -07:00", "2006-01-02 15:4:5 -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 {
"2006-01-2 15:04:05 -07:00", return t, nil
"2006-01-2 15:04:5 -07:00", }
"2006-01-2 15:4:05 -07:00", }
"2006-01-2 15:4:5 -07:00", case part2Len == 2 && part3Len == 1:
"2006-1-2 15:04:05 -07:00", for _, layout := range []string{
"2006-1-2 15:04:5 -07:00", "2006-01-2 15:04:05 -07:00",
"2006-1-2 15:4:05 -07:00", "2006-01-2 15:04:5 -07:00",
"2006-1-2 15:4: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 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 stateDigitDashWsWsOffsetAlpha: case stateDigitDashWsWsOffsetAlpha:
// 2015-02-18 00:12:00 +0000 UTC // 2015-02-18 00:12:00 +0000 UTC
for _, layout := range []string{ switch {
"2006-01-02 15:04:05 +0000 GMT", case part2Len == 2 && part3Len == 2:
"2006-01-02 15:04:5 +0000 GMT", for _, layout := range []string{
"2006-01-02 15:4:05 +0000 GMT", "2006-01-02 15:04:05 -0700 MST",
"2006-01-02 15:4:5 +0000 GMT", "2006-01-02 15:04:5 -0700 MST",
"2006-1-02 15:04:05 +0000 GMT", "2006-01-02 15:4:05 -0700 MST",
"2006-1-02 15:4:05 +0000 GMT", "2006-01-02 15:4:5 -0700 MST",
"2006-1-02 15:04:5 +0000 GMT", "2006-01-02 15:04:05 +0000 GMT",
"2006-1-02 15:4:5 +0000 GMT", "2006-01-02 15:04:5 +0000 GMT",
"2006-01-2 15:04:05 +0000 GMT", "2006-01-02 15:4:05 +0000 GMT",
"2006-01-2 15:04:5 +0000 GMT", "2006-01-02 15:4: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 {
"2006-1-2 15:04:05 +0000 GMT", return t, nil
"2006-1-2 15:04:5 +0000 GMT", }
"2006-1-2 15:4:05 +0000 GMT", }
"2006-1-2 15:4:5 +0000 GMT", case part2Len == 2 && part3Len == 1:
for _, layout := range []string{
"2006-01-02 15:04:05 -0700 UTC", "2006-01-2 15:04:05 -0700 MST",
"2006-01-02 15:04:5 -0700 UTC", "2006-01-2 15:04:5 -0700 MST",
"2006-01-02 15:4:05 -0700 UTC", "2006-01-2 15:4:05 -0700 MST",
"2006-01-02 15:4:5 -0700 UTC", "2006-01-2 15:4:5 -0700 MST",
"2006-1-02 15:04:05 -0700 UTC", "2006-01-2 15:04:05 +0000 GMT",
"2006-1-02 15:4:05 -0700 UTC", "2006-01-2 15:04:5 +0000 GMT",
"2006-1-02 15:04:5 -0700 UTC", "2006-01-2 15:4:05 +0000 GMT",
"2006-1-02 15:4:5 -0700 UTC", "2006-01-2 15:4:5 +0000 GMT",
"2006-01-2 15:04:05 -0700 UTC", } {
"2006-01-2 15:04:5 -0700 UTC", if t, err := parse(layout, datestr, loc); err == nil {
"2006-01-2 15:4:05 -0700 UTC", return t, nil
"2006-01-2 15:4:5 -0700 UTC", }
"2006-1-2 15:04:05 -0700 UTC", }
"2006-1-2 15:04:5 -0700 UTC", case part2Len == 1 && part3Len == 2:
"2006-1-2 15:4:05 -0700 UTC", for _, layout := range []string{
"2006-1-2 15:4:5 -0700 UTC", "2006-1-02 15:04:05 -0700 MST",
} { "2006-1-02 15:4:05 -0700 MST",
if t, err := parse(layout, datestr, loc); err == nil { "2006-1-02 15:04:5 -0700 MST",
return t, nil "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
}
} }
} }
@ -1530,7 +1584,7 @@ iterRunes:
case stateWeekdayAbbrevCommaOffsetZone: case stateWeekdayAbbrevCommaOffsetZone:
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST) // Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
if dayLen == 1 { 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 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)

View File

@ -458,8 +458,14 @@ func TestParse(t *testing.T) {
ts = MustParse("2014-04-26 17:24:37.1 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))) assert.Equal(t, "2014-04-26 17:24:37.1 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
ts = MustParse("2014-04-26 17:24:37.123 +0800") ts = MustParse("2014-04-26 09:04:37.123 +0800")
assert.Equal(t, "2014-04-26 09:24:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 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") 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))) assert.Equal(t, "2014-04-27 01:24:37.123 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
@ -473,16 +479,40 @@ func TestParse(t *testing.T) {
ts = MustParse("2017-07-19 03:21:51+00:00") 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))) assert.Equal(t, "2017-07-19 03:21:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
ts = MustParse("2017-07-19 03:21:51 +00:00 UTC") ts = MustParse("2017-07-09 03:01:51 +00:00 UTC")
assert.Equal(t, "2017-07-19 03:21:51 +0000 UTC", fmt.Sprintf("%v", ts.In(time.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("2015-02-18 00:12:00 +0000 GMT") ts = MustParse("2017-07-19 03:01:51 +00:00 UTC")
assert.Equal(t, "2015-02-18 00:12:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.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 // Golang Native Format
ts = MustParse("2015-02-18 00:12:00 +0000 UTC") 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))) 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") 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))) assert.Equal(t, "2014-12-16 06:20:00 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
@ -511,8 +541,14 @@ func TestParse(t *testing.T) {
_, err = ParseAny("2014-13-13 08:20:13,787") // month 13 doesn't exist so error _, err = ParseAny("2014-13-13 08:20:13,787") // month 13 doesn't exist so error
assert.NotEqual(t, nil, err) assert.NotEqual(t, nil, err)
ts = MustParse("2014-05-11 08:20:13 +00:00") ts = MustParse("2014-05-01 08:02:13 +00:00")
assert.Equal(t, "2014-05-11 08:20:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) 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") 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))) assert.Equal(t, "2014-05-11 08:20:13 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))