Complete refactor for re-usable time parse

This commit is contained in:
Aaron Raddon 2018-03-10 11:50:19 -08:00
parent e152c5aaf6
commit 163a0a8ac8
2 changed files with 106 additions and 304 deletions

View File

@ -9,15 +9,8 @@ import (
"time" "time"
"unicode" "unicode"
"unicode/utf8" "unicode/utf8"
u "github.com/araddon/gou"
) )
func init() {
u.SetupLogging("debug")
u.SetColorOutput()
}
type dateState uint8 type dateState uint8
type timeState uint8 type timeState uint8
@ -32,11 +25,6 @@ const (
dateDigitDot dateDigitDot
dateDigitDotDot dateDigitDotDot
dateDigitSlash dateDigitSlash
dateDigitSlashWs
dateDigitSlashWsColon
dateDigitSlashWsColonAMPM
dateDigitSlashWsColonColon
dateDigitSlashWsColonColonAMPM
dateDigitChineseYear dateDigitChineseYear
dateDigitChineseYearWs dateDigitChineseYearWs
dateDigitWs dateDigitWs
@ -51,12 +39,8 @@ const (
dateAlphaWsAlpha dateAlphaWsAlpha
dateAlphaWsAlphaYearmaybe dateAlphaWsAlphaYearmaybe
dateWeekdayComma dateWeekdayComma
dateWeekdayCommaDash
dateWeekdayCommaOffset
dateWeekdayAbbrevComma dateWeekdayAbbrevComma
dateWeekdayAbbrevCommaDash dateWeekdayAbbrevCommaDash
dateWeekdayAbbrevCommaOffset
dateWeekdayAbbrevCommaOffsetZone
) )
const ( const (
// Time state // Time state
@ -155,8 +139,6 @@ type parser struct {
skip int skip int
extra int extra int
part1Len int part1Len int
part2Len int
part3Len int
yeari int yeari int
yearlen int yearlen int
moi int moi int
@ -183,6 +165,7 @@ func newParser(dateStr string, loc *time.Location) *parser {
stateTime: timeIgnore, stateTime: timeIgnore,
datestr: dateStr, datestr: dateStr,
loc: loc, loc: loc,
preferMonthFirst: true,
} }
p.format = []byte(dateStr) p.format = []byte(dateStr)
return &p return &p
@ -192,8 +175,6 @@ func (p *parser) set(start int, val string) {
return return
} }
if len(p.format) < start+len(val) { if len(p.format) < start+len(val) {
u.Warnf("not enough space %d %d", len(p.format), start+len(val))
u.Warnf("%s", p.format[start:])
return return
} }
for i, r := range val { for i, r := range val {
@ -238,7 +219,12 @@ func (p *parser) coalesceDate(end int) {
p.setDay() 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) { func (p *parser) coalesceTime(end int) {
// 03:04:05 // 03:04:05
// 15:04:05 // 15:04:05
@ -249,7 +235,6 @@ func (p *parser) coalesceTime(end int) {
if p.hourlen == 2 { if p.hourlen == 2 {
p.set(p.houri, "15") p.set(p.houri, "15")
} else if p.hourlen == 1 { } else if p.hourlen == 1 {
u.Warnf("WTF houri is wrong? houri=%d hourlen=%d", p.houri, p.hourlen)
p.set(p.houri, "3") p.set(p.houri, "3")
} }
} }
@ -266,7 +251,6 @@ func (p *parser) coalesceTime(end int) {
if p.seci > 0 { if p.seci > 0 {
if p.seclen == 0 { if p.seclen == 0 {
p.seclen = end - p.seci p.seclen = end - p.seci
//u.Infof("fixing seconds p.seci=%d seclen=%d end=%d", p.seci, p.seclen, end)
} }
if p.seclen == 2 { if p.seclen == 2 {
p.set(p.seci, "05") p.set(p.seci, "05")
@ -276,36 +260,24 @@ func (p *parser) coalesceTime(end int) {
} }
if p.msi > 0 { if p.msi > 0 {
// if p.mslen == 0 {
// p.mslen = end - p.msi
// //u.Warnf("set mslen??? %v", p.datestr)
// }
for i := 0; i < p.mslen; i++ { for i := 0; i < p.mslen; i++ {
p.format[p.msi+i] = '0' p.format[p.msi+i] = '0'
} }
} }
//u.Debugf("coalesce %+v", p)
} }
func (p *parser) trimExtra() { func (p *parser) trimExtra() {
if p.extra > 0 && len(p.format) > p.extra { if p.extra > 0 && len(p.format) > p.extra {
u.Debugf("trim extra %d", p.extra)
p.format = p.format[0:p.extra] p.format = p.format[0:p.extra]
p.datestr = p.datestr[0:p.extra] p.datestr = p.datestr[0:p.extra]
} }
} }
// func (p parser) fill(start, ct int, b byte) {
// for i := start; i < start+ct; i++ {
// p.format[i] = b
// }
// }
func (p *parser) parse() (time.Time, error) { func (p *parser) parse() (time.Time, error) {
if p.skip > 0 && len(p.format) > p.skip { if p.skip > 0 && len(p.format) > p.skip {
p.format = p.format[p.skip:] p.format = p.format[p.skip:]
p.datestr = p.datestr[p.skip:] p.datestr = p.datestr[p.skip:]
} }
u.Debugf("parse() loc=%v %50s AS %q", p.loc.String(), p.datestr, p.format)
if p.loc == nil { if p.loc == nil {
return time.Parse(string(p.format), p.datestr) return time.Parse(string(p.format), p.datestr)
} }
@ -351,7 +323,23 @@ iterRunes:
p.set(0, "2006") p.set(0, "2006")
} }
case '/': case '/':
// 03/31/2005
// 2014/02/24
p.stateDate = dateDigitSlash 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 '.': case '.':
// 3.31.2014 // 3.31.2014
p.moi = 0 p.moi = 0
@ -464,51 +452,36 @@ iterRunes:
switch r { switch r {
case ' ': case ' ':
p.stateDate = dateDigitSlashWs 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 '/': case '/':
continue 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: default:
// if unicode.IsDigit(r) || r == '/' { // if unicode.IsDigit(r) || r == '/' {
// continue // continue
// } // }
} }
case dateDigitSlashWs:
// 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 ':':
p.stateDate = dateDigitSlashWsColon
}
case dateDigitSlashWsColon:
// 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 ':':
p.stateDate = dateDigitSlashWsColonColon
case 'A', 'P':
p.stateDate = dateDigitSlashWsColonAMPM
}
case dateDigitSlashWsColonColon:
// 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':
p.stateDate = dateDigitSlashWsColonColonAMPM
}
case dateDigitWs: case dateDigitWs:
// 18 January 2018 // 18 January 2018
@ -582,26 +555,23 @@ iterRunes:
// //
// dateWeekdayComma // dateWeekdayComma
// Monday, 02 Jan 2006 15:04:05 MST // Monday, 02 Jan 2006 15:04:05 MST
// dateWeekdayCommaDash
// Monday, 02-Jan-06 15:04:05 MST // Monday, 02-Jan-06 15:04:05 MST
// dateWeekdayCommaOffset
// Monday, 02 Jan 2006 15:04:05 -0700 // Monday, 02 Jan 2006 15:04:05 -0700
// Monday, 02 Jan 2006 15:04:05 +0100 // Monday, 02 Jan 2006 15:04:05 +0100
// dateWeekdayAbbrevComma // dateWeekdayAbbrevComma
// Mon, 02 Jan 2006 15:04:05 MST // Mon, 02 Jan 2006 15:04:05 MST
// dateWeekdayAbbrevCommaDash
// Mon, 02-Jan-06 15:04:05 MST
// dateWeekdayAbbrevCommaOffset
// Mon, 02 Jan 2006 15:04:05 -0700 // Mon, 02 Jan 2006 15:04:05 -0700
// Thu, 13 Jul 2017 08:58:40 +0100 // Thu, 13 Jul 2017 08:58:40 +0100
// dateWeekdayAbbrevCommaOffsetZone
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST) // Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
// dateWeekdayAbbrevCommaDash
// Mon, 02-Jan-06 15:04:05 MST
switch { switch {
case r == ' ': case r == ' ':
p.stateDate = dateAlphaWs p.stateDate = dateAlphaWs
case r == ',': case r == ',':
p.moi = 0 // p.moi = 0
p.molen = i // p.molen = i
if i == 3 { if i == 3 {
p.stateDate = dateWeekdayAbbrevComma p.stateDate = dateWeekdayAbbrevComma
p.set(0, "Mon") p.set(0, "Mon")
@ -609,23 +579,21 @@ iterRunes:
p.stateDate = dateWeekdayComma p.stateDate = dateWeekdayComma
//p.set(0, "Monday") //p.set(0, "Monday")
p.skip = i + 2 p.skip = i + 2
i++
// TODO: lets just make this "skip" as we don't need // TODO: lets just make this "skip" as we don't need
// the mon, monday, they are all superfelous and not needed // the mon, monday, they are all superfelous and not needed
// just lay down the skip, no need to fill and then skip // just lay down the skip, no need to fill and then skip
} }
i++
} }
case dateWeekdayComma: // Starts alpha then comma case dateWeekdayComma:
// Monday, 02 Jan 2006 15:04:05 MST // Monday, 02 Jan 2006 15:04:05 MST
// dateWeekdayCommaDash
// Monday, 02-Jan-06 15:04:05 MST
// dateWeekdayCommaOffset
// Monday, 02 Jan 2006 15:04:05 -0700 // Monday, 02 Jan 2006 15:04:05 -0700
// Monday, 02 Jan 2006 15:04:05 +0100 // Monday, 02 Jan 2006 15:04:05 +0100
// Monday, 02-Jan-06 15:04:05 MST
if p.dayi == 0 { if p.dayi == 0 {
p.dayi = i p.dayi = i
} }
u.Debugf("weekday %d %q", i, string(r))
switch r { switch r {
case ' ', '-': case ' ', '-':
if p.moi == 0 { if p.moi == 0 {
@ -637,45 +605,42 @@ iterRunes:
p.yeari = i + 1 p.yeari = i + 1
p.molen = i - p.moi p.molen = i - p.moi
p.set(p.moi, "Jan") p.set(p.moi, "Jan")
u.Warnf("set month? %v %v", p.moi, p.molen)
} else { } else {
p.stateTime = timeStart p.stateTime = timeStart
break iterRunes break iterRunes
} }
//case r == '-': //case r == '-':
} }
case dateWeekdayAbbrevComma: // Starts alpha then comma case dateWeekdayAbbrevComma:
// Mon, 02 Jan 2006 15:04:05 MST // 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)
// dateWeekdayAbbrevCommaDash // dateWeekdayAbbrevCommaDash
// Mon, 02-Jan-06 15:04:05 MST // Mon, 02-Jan-06 15:04:05 MST
// dateWeekdayAbbrevCommaOffset
// Mon, 02 Jan 2006 15:04:05 -0700
// Thu, 13 Jul 2017 08:58:40 +0100
// Thu, 4 Jan 2018 17:53:36 +0000
// dateWeekdayAbbrevCommaOffsetZone
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
switch { switch {
case r == ' ' && p.part3Len == 0: case r == ' ':
p.part3Len = i - p.part1Len - 2 if p.dayi == 0 {
case r == '-': p.dayi = i + 1
if i < 15 { } else if p.moi == 0 {
p.stateDate = dateWeekdayAbbrevCommaDash 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 break iterRunes
} }
p.stateDate = dateWeekdayAbbrevCommaOffset
case r == '+':
p.stateDate = dateWeekdayAbbrevCommaOffset
}
case dateWeekdayAbbrevCommaOffset: case r == '-':
// dateWeekdayAbbrevCommaOffset p.stateDate = dateWeekdayAbbrevCommaDash
// Mon, 02 Jan 2006 15:04:05 -0700 break iterRunes
// Thu, 13 Jul 2017 08:58:40 +0100
// Thu, 4 Jan 2018 17:53:36 +0000
// dateWeekdayAbbrevCommaOffsetZone
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
if r == '(' {
p.stateDate = dateWeekdayAbbrevCommaOffsetZone
} }
case dateAlphaWs: case dateAlphaWs:
@ -687,10 +652,7 @@ iterRunes:
// Mon Aug 10 15:44:11 UTC+0100 2015 // Mon Aug 10 15:44:11 UTC+0100 2015
// dateAlphaWsDigit // dateAlphaWsDigit
// May 8, 2009 5:57:51 PM // May 8, 2009 5:57:51 PM
u.Infof("dateAlphaWs %s %d", string(r), i)
switch { switch {
// case r == ' ':
// p.part2Len = i - p.part1Len
case unicode.IsLetter(r): case unicode.IsLetter(r):
p.set(0, "Mon") p.set(0, "Mon")
p.stateDate = dateAlphaWsAlpha p.stateDate = dateAlphaWsAlpha
@ -700,32 +662,22 @@ iterRunes:
p.set(0, "Jan") p.set(0, "Jan")
p.stateDate = dateAlphaWsDigit p.stateDate = dateAlphaWsDigit
p.dayi = i p.dayi = i
default:
u.Warnf("what is this? case r=%s", string(r))
} }
case dateAlphaWsDigit: case dateAlphaWsDigit:
// dateAlphaWsDigit // dateAlphaWsDigit
// May 8, 2009 5:57:51 PM // May 8, 2009 5:57:51 PM
switch { if r == ',' {
case r == ',':
p.daylen = i - p.dayi p.daylen = i - p.dayi
p.setDay() p.setDay()
p.stateDate = dateAlphaWsDigitComma p.stateDate = dateAlphaWsDigitComma
case unicode.IsDigit(r):
p.stateDate = dateAlphaWsDigit
u.Warnf("wtf not possible? %s", datestr)
} }
case dateAlphaWsDigitComma: case dateAlphaWsDigitComma:
// x // x
// May 8, 2009 5:57:51 PM // May 8, 2009 5:57:51 PM
switch { if r == ' ' {
case r == ' ':
p.stateDate = dateAlphaWsDigitCommaWs p.stateDate = dateAlphaWsDigitCommaWs
p.yeari = i + 1 p.yeari = i + 1
default:
u.Warnf("hm, can we drop a case here? %v", string(r))
return time.Time{}, fmt.Errorf("could not find format for %v expected white-space after comma", datestr)
} }
case dateAlphaWsDigitCommaWs: case dateAlphaWsDigitCommaWs:
// x // x
@ -735,7 +687,6 @@ iterRunes:
p.yearlen = i - p.yeari p.yearlen = i - p.yeari
p.setYear() p.setYear()
p.stateTime = timeStart p.stateTime = timeStart
u.Debugf("here we are %s i=%d yeari=%d yearlen=%d", string(r), i, p.yeari, p.yearlen)
break iterRunes break iterRunes
} }
@ -745,13 +696,10 @@ iterRunes:
// Mon Jan _2 15:04:05 MST 2006 // Mon Jan _2 15:04:05 MST 2006
// Mon Aug 10 15:44:11 UTC+0100 2015 // Mon Aug 10 15:44:11 UTC+0100 2015
// Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)
u.Debugf("dateAlphaWsAlpha i=%d r=%s", i, string(r))
if r == ' ' { if r == ' ' {
if p.dayi > 0 { if p.dayi > 0 {
p.daylen = i - p.dayi p.daylen = i - p.dayi
u.Warnf("%s dayi=%v daylen=%v format=%s", datestr, p.dayi, p.daylen, string(p.format))
p.setDay() p.setDay()
u.Warnf("%s", string(p.format))
p.yeari = i + 1 p.yeari = i + 1
p.stateDate = dateAlphaWsAlphaYearmaybe p.stateDate = dateAlphaWsAlphaYearmaybe
p.stateTime = timeStart p.stateTime = timeStart
@ -759,14 +707,12 @@ iterRunes:
} else if unicode.IsDigit(r) { } else if unicode.IsDigit(r) {
if p.dayi == 0 { if p.dayi == 0 {
p.dayi = i p.dayi = i
u.Warnf("found dayi %d", p.dayi)
} }
} }
case dateAlphaWsAlphaYearmaybe: case dateAlphaWsAlphaYearmaybe:
// x // x
// Mon Jan _2 15:04:05 2006 // Mon Jan _2 15:04:05 2006
// Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time) // Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)
u.Warnf("%s i=%d yeari+3=%d", string(r), i, p.yeari+4)
if r == ':' { if r == ':' {
i = i - 3 i = i - 3
p.stateDate = dateAlphaWsAlpha p.stateDate = dateAlphaWsAlpha
@ -775,45 +721,15 @@ iterRunes:
} else if r == ' ' { } else if r == ' ' {
// must be year format, not 15:04 // must be year format, not 15:04
p.yearlen = i - p.yeari p.yearlen = i - p.yeari
u.Infof("yeari=%d yearlen=%d", p.yeari, p.yearlen)
p.setYear() p.setYear()
u.Debugf("format=%s", string(p.format))
break iterRunes break iterRunes
} }
/*
case dateAlphaWSAlphaColon:
// 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) {
p.stateDate = dateAlphaWSAlphaColonAlpha
} else if r == '-' || r == '+' {
p.stateDate = dateAlphaWSAlphaColonOffset
}
case dateAlphaWSAlphaColonAlpha:
// 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 == '+' {
p.stateDate = dateAlphaWSAlphaColonAlphaOffset
}
case dateAlphaWSAlphaColonAlphaOffset:
// 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) {
p.stateDate = dateAlphaWSAlphaColonAlphaOffsetAlpha
}
*/
default: default:
break iterRunes break iterRunes
} }
} }
u.Warnf("%s", string(p.format))
p.coalesceDate(i) p.coalesceDate(i)
u.Warnf("%s", string(p.format))
if p.stateTime == timeStart { if p.stateTime == timeStart {
// increment first one, since the i++ occurs at end of loop // increment first one, since the i++ occurs at end of loop
i++ i++
@ -822,10 +738,10 @@ iterRunes:
for ; i < len(datestr); i++ { for ; i < len(datestr); i++ {
r := rune(datestr[i]) r := rune(datestr[i])
u.Debugf("i=%d r=%s timeState=%d hi=%d hl=%d", i, string(r), p.stateTime, p.houri, p.hourlen)
switch p.stateTime { switch p.stateTime {
case timeStart: case timeStart:
// 22:43:22 // 22:43:22
// 22:43
// timeComma // timeComma
// 08:20:13,787 // 08:20:13,787
// timeWs // timeWs
@ -889,13 +805,12 @@ iterRunes:
p.seclen = i - p.seci p.seclen = i - p.seci
} }
case ' ': case ' ':
p.coalesceTime(i)
p.stateTime = timeWs p.stateTime = timeWs
p.seclen = i - p.seci
case ':': case ':':
if p.mini == 0 { if p.mini == 0 {
p.mini = i + 1 p.mini = i + 1
p.hourlen = i - p.houri p.hourlen = i - p.houri
u.Infof("hour i=%v l=%d", p.houri, p.hourlen)
} else if p.seci == 0 { } else if p.seci == 0 {
p.seci = i + 1 p.seci = i + 1
p.minlen = i - p.mini p.minlen = i - p.mini
@ -929,7 +844,6 @@ iterRunes:
// 00:12:00 2008 // 00:12:00 2008
// timeZ // timeZ
// 15:04:05.99Z // 15:04:05.99Z
u.Debugf("timeWs")
switch r { switch r {
case 'A', 'P': case 'A', 'P':
// Could be AM/PM or could be PST or similar // Could be AM/PM or could be PST or similar
@ -959,11 +873,9 @@ iterRunes:
// 18:04:07 GMT+0100 (GMT Daylight Time) // 18:04:07 GMT+0100 (GMT Daylight Time)
// timeWsAlphaZoneOffsetWsYear // timeWsAlphaZoneOffsetWsYear
// 15:44:11 UTC+0100 2015 // 15:44:11 UTC+0100 2015
u.Debugf("timeWsAlpha")
switch r { switch r {
case '+', '-': case '+', '-':
p.tzlen = i - p.tzi p.tzlen = i - p.tzi
u.Infof("tzi=%d tzlen=%d", p.tzi, p.tzlen)
if p.tzlen == 4 { if p.tzlen == 4 {
p.set(p.tzi, " MST") p.set(p.tzi, " MST")
} else if p.tzlen == 3 { } else if p.tzlen == 3 {
@ -979,7 +891,6 @@ iterRunes:
// 18:04:07 GMT+0100 (GMT Daylight Time) // 18:04:07 GMT+0100 (GMT Daylight Time)
// timeWsAlphaZoneOffsetWsYear // timeWsAlphaZoneOffsetWsYear
// 15:44:11 UTC+0100 2015 // 15:44:11 UTC+0100 2015
u.Debugf("timeWsAlphaZoneOffset")
switch r { switch r {
case ' ': case ' ':
p.set(p.offseti, "-0700") p.set(p.offseti, "-0700")
@ -992,13 +903,11 @@ iterRunes:
// 18:04:07 GMT+0100 (GMT Daylight Time) // 18:04:07 GMT+0100 (GMT Daylight Time)
// timeWsAlphaZoneOffsetWsYear // timeWsAlphaZoneOffsetWsYear
// 15:44:11 UTC+0100 2015 // 15:44:11 UTC+0100 2015
u.Debugf("timeWsAlphaZoneOffsetWs")
if unicode.IsDigit(r) { if unicode.IsDigit(r) {
p.stateTime = timeWsAlphaZoneOffsetWsYear p.stateTime = timeWsAlphaZoneOffsetWsYear
} else { } else {
p.extra = i - 1 p.extra = i - 1
p.stateTime = timeWsAlphaZoneOffsetWsExtra p.stateTime = timeWsAlphaZoneOffsetWsExtra
u.Warnf("going to chop some stuff off %d", p.extra)
} }
case timeWsAlphaZoneOffsetWsYear: case timeWsAlphaZoneOffsetWsYear:
// 15:44:11 UTC+0100 2015 // 15:44:11 UTC+0100 2015
@ -1008,7 +917,6 @@ iterRunes:
p.setYear() p.setYear()
} }
} }
u.Debugf("timeWsAlphaZoneOffsetWsYear yeari=%d yearlen=%d", p.yeari, p.yearlen)
case timeWsAMPMMaybe: case timeWsAMPMMaybe:
// timeWsAMPMMaybe // timeWsAMPMMaybe
// timeWsAMPM // timeWsAMPM
@ -1020,6 +928,11 @@ iterRunes:
//return parse("2006-01-02 03:04:05 PM", datestr, loc) //return parse("2006-01-02 03:04:05 PM", datestr, loc)
p.stateTime = timeWsAMPM p.stateTime = timeWsAMPM
p.set(i-1, "PM") 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 { } else {
p.stateTime = timeWsAlpha p.stateTime = timeWsAlpha
} }
@ -1104,16 +1017,8 @@ iterRunes:
// 19:55:00.799+0100 // 19:55:00.799+0100
// timePeriodOffsetColon // timePeriodOffsetColon
// 15:04:05.999-07:00 // 15:04:05.999-07:00
switch r { if r == ':' {
case ':':
p.stateTime = timePeriodOffsetColon p.stateTime = timePeriodOffsetColon
default:
if unicode.IsLetter(r) {
// 00:07:31.945167 +0000 UTC
// 00:00:00.000 +0000 UTC
p.stateTime = timePeriodWsOffsetWsAlpha
break iterTimeRunes
}
} }
case timePeriodOffsetColon: case timePeriodOffsetColon:
// timePeriodOffset // timePeriodOffset
@ -1160,8 +1065,6 @@ iterRunes:
switch r { switch r {
case ' ': case ' ':
p.set(p.offseti, "-0700") p.set(p.offseti, "-0700")
case ':':
u.Errorf("timePeriodWsOffset UNHANDLED COLON")
default: default:
if unicode.IsLetter(r) { if unicode.IsLetter(r) {
// 00:07:31.945167 +0000 UTC // 00:07:31.945167 +0000 UTC
@ -1186,34 +1089,23 @@ iterRunes:
} }
} }
u.Debugf("timestate = %d", p.stateTime)
switch p.stateTime { switch p.stateTime {
case timeWsAlpha: case timeWsAlpha:
u.Warnf("timeWsAlpha?")
case timeWsYear: case timeWsYear:
p.yearlen = i - p.yeari p.yearlen = i - p.yeari
u.Infof("got WsYear yeari=%d yearlen=%d", p.yeari, p.yearlen)
p.setYear() p.setYear()
case timeWsAlphaZoneOffsetWsExtra: case timeWsAlphaZoneOffsetWsExtra:
u.Warnf("%s", string(p.format))
p.trimExtra() p.trimExtra()
u.Warnf("%s", string(p.format))
case timePeriod: case timePeriod:
p.mslen = i - p.msi p.mslen = i - p.msi
case timeOffset: case timeOffset:
// 19:55:00+0100 // 19:55:00+0100
u.Warnf("offset?")
p.set(p.offseti, "-0700") p.set(p.offseti, "-0700")
case timeWsOffset: case timeWsOffset:
u.Warnf("timeWsOffset?")
p.set(p.offseti, "-0700") p.set(p.offseti, "-0700")
case timeOffsetColon: case timeOffsetColon:
// 15:04:05+07:00 // 15:04:05+07:00
p.set(p.offseti, "-07:00") p.set(p.offseti, "-07:00")
// case timeZ:
// u.Warnf("wtf? timeZ")
// case timeZDigit:
// u.Warnf("got timeZDigit Z00:00")
case timePeriodOffset: case timePeriodOffset:
// 19:55:00.799+0100 // 19:55:00.799+0100
p.set(p.offseti, "-0700") p.set(p.offseti, "-0700")
@ -1221,20 +1113,10 @@ iterRunes:
p.set(p.offseti, "-07:00") p.set(p.offseti, "-07:00")
case timePeriodWsOffset: case timePeriodWsOffset:
p.set(p.offseti, "-0700") p.set(p.offseti, "-0700")
// case timePeriodWsOffsetWsAlpha:
// u.Warnf("timePeriodWsOffsetAlpha")
// case timeWsOffsetAlpha:
// u.Warnf("timeWsOffsetAlpha offseti=%d", p.offseti)
default:
//u.Warnf("un-handled statetime: %d for %v", p.stateTime, p.datestr)
} }
u.Warnf("%s", string(p.format))
p.coalesceTime(i) p.coalesceTime(i)
u.Warnf("parse: %q AS %q", p.datestr, string(p.format))
} }
//u.Infof("%60s %q\n\t%+v", datestr, string(p.format), p)
switch p.stateDate { switch p.stateDate {
case dateDigit: case dateDigit:
// unixy timestamps ish // unixy timestamps ish
@ -1314,10 +1196,6 @@ iterRunes:
p.yearlen = i - p.yeari p.yearlen = i - p.yeari
return p.parse() return p.parse()
case dateDigitWs:
u.Warnf("what? %s", datestr)
return p.parse()
case dateDigitWsMoYear: case dateDigitWsMoYear:
// 2 Jan 2018 23:59 // 2 Jan 2018 23:59
// 02 Jan 2018 23:59 // 02 Jan 2018 23:59
@ -1342,36 +1220,7 @@ iterRunes:
case dateAlphaWsAlphaYearmaybe: case dateAlphaWsAlphaYearmaybe:
return p.parse() return p.parse()
case dateAlphaWsDigitCommaWs:
return p.parse()
/*
case dateAlphaWsAlphaWs:
case dateAlphaWSAlphaColon:
// Mon Jan _2 15:04:05 2006
return parse(time.ANSIC, datestr, loc)
case dateAlphaWSAlphaColonOffset:
// Mon Jan 02 15:04:05 -0700 2006
return parse(time.RubyDate, datestr, loc)
case dateAlphaWSAlphaColonAlpha:
// Mon Jan _2 15:04:05 MST 2006
return parse(time.UnixDate, datestr, loc)
case dateAlphaWSAlphaColonAlphaOffset:
// Mon Aug 10 15:44:11 UTC+0100 2015
return parse("Mon Jan 02 15:04:05 MST-0700 2006", datestr, loc)
case dateAlphaWSAlphaColonAlphaOffsetAlpha:
// 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 dateDigitSlash: // starts digit then slash 02/ (but nothing else) case dateDigitSlash: // starts digit then slash 02/ (but nothing else)
// 3/1/2014 // 3/1/2014
// 10/13/2014 // 10/13/2014
@ -1379,39 +1228,6 @@ iterRunes:
// 2014/10/13 // 2014/10/13
return p.parse() return p.parse()
case dateDigitSlashWsColon:
// 4/8/2014 22:05
// 04/08/2014 22:05
// 2014/4/8 22:05
// 2014/04/08 22:05
return p.parse()
case dateDigitSlashWsColonAMPM:
// 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
return p.parse()
case dateDigitSlashWsColonColon:
// 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
return p.parse()
case dateDigitSlashWsColonColonAMPM:
// 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
return p.parse()
case dateDigitChineseYear: case dateDigitChineseYear:
// dateDigitChineseYear // dateDigitChineseYear
// 2014年04月08日 // 2014年04月08日
@ -1426,10 +1242,6 @@ iterRunes:
// Monday, 02-Jan-06 15:04:05 MST // Monday, 02-Jan-06 15:04:05 MST
return p.parse() return p.parse()
// case dateWeekdayCommaDash:
//
// return p.parse()
case dateWeekdayAbbrevComma: // Starts alpha then comma case dateWeekdayAbbrevComma: // Starts alpha then comma
// Mon, 02-Jan-06 15:04:05 MST // Mon, 02-Jan-06 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 MST // Mon, 02 Jan 2006 15:04:05 MST
@ -1440,20 +1252,7 @@ iterRunes:
// Mon, 2-Jan-06 15:04:05 MST // Mon, 2-Jan-06 15:04:05 MST
return p.parse() return p.parse()
case dateWeekdayAbbrevCommaOffset:
// 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
return p.parse()
case dateWeekdayAbbrevCommaOffsetZone:
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
return p.parse()
} }
//u.Warnf("no format for %d %d %s", p.stateDate, p.stateTime, p.datestr)
return time.Time{}, fmt.Errorf("Could not find date format for %s", datestr) return time.Time{}, fmt.Errorf("Could not find date format for %s", datestr)
} }

View File

@ -184,14 +184,16 @@ func TestParse(t *testing.T) {
assert.Equal(t, "2015-08-10 15:44:11 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) assert.Equal(t, "2015-08-10 15:44:11 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
ts = MustParse("Mon Aug 10 15:44:11 PST-0700 2015") ts = MustParse("Mon Aug 10 15:44:11 PST-0700 2015")
assert.Equal(t, "2015-08-10 22:44:11 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) assert.Equal(t, "2015-08-10 22:44:11 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
ts = MustParse("Mon Aug 10 15:44:11 CEST+0200 2015")
assert.Equal(t, "2015-08-10 13:44:11 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
// Easily the worst Date format I have ever seen // Easily the worst Date format I have ever seen
// "Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)" // "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)") 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))) 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") ts = MustParse("Fri, 03 Jul 2015 13:04:07 MST")
assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC))) assert.Equal(t, "2015-07-03 13:04:07 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
ts = MustParse("Mon, 2 Jan 2006 15:4:05 MST") 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))) assert.Equal(t, "2006-01-02 15:04:05 +0000 UTC", fmt.Sprintf("%v", ts.In(time.UTC)))
@ -672,5 +674,6 @@ func TestPStruct(t *testing.T) {
p.set(15, "not") p.set(15, "not")
assert.Equal(t, "08.21.71", p.datestr) assert.Equal(t, "08.21.71", p.datestr)
assert.Equal(t, "08.21.71", string(p.format)) assert.Equal(t, "08.21.71", string(p.format))
assert.True(t, len(p.ds()) > 0)
assert.True(t, len(p.ts()) > 0)
} }