Skip to content

Commit 00672cf

Browse files
committed
Supported extra whitespaces and many other changes
Ref: araddon/pull/151
1 parent f0cdec5 commit 00672cf

2 files changed

Lines changed: 523 additions & 487 deletions

File tree

parseany.go

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,12 @@ const (
137137
var (
138138
// ErrAmbiguousMMDD for date formats such as 04/02/2014 the MM/dd vs dd/MM are
139139
// ambiguous, so it is an error for strict parse rules.
140-
ErrAmbiguousMMDD = fmt.Errorf("this date has ambiguous MM/dd vs dd/MM type format")
140+
ErrAmbiguousMMDD = fmt.Errorf("this date has ambiguous MM/dd vs dd/MM type format")
141+
ErrCouldNotFindFormat = fmt.Errorf("could not find format for")
141142
)
142143

143144
func unknownErr(datestr string) error {
144-
return fmt.Errorf("could not find format for %q", datestr)
145+
return fmt.Errorf("%w %q", ErrCouldNotFindFormat, datestr)
145146
}
146147

147148
// ParseAny parse an unknown date format, detect the layout.
@@ -236,7 +237,10 @@ func ParseStrict(datestr string, opts ...ParserOption) (time.Time, error) {
236237

237238
func parseTime(datestr string, loc *time.Location, opts ...ParserOption) (p *parser, err error) {
238239

239-
p = newParser(datestr, loc, opts...)
240+
p, err = newParser(datestr, loc, opts...)
241+
if err != nil {
242+
return
243+
}
240244
if p.retryAmbiguousDateWithSwap {
241245
// month out of range signifies that a day/month swap is the correct solution to an ambiguous date
242246
// this is because it means that a day is being interpreted as a month and overflowing the valid value for that
@@ -252,7 +256,7 @@ func parseTime(datestr string, loc *time.Location, opts ...ParserOption) (p *par
252256
// turn off the retry to avoid endless recursion
253257
retryAmbiguousDateWithSwap := RetryAmbiguousDateWithSwap(false)
254258
modifiedOpts := append(opts, preferMonthFirst, retryAmbiguousDateWithSwap)
255-
p, err = parseTime(datestr, time.Local, modifiedOpts...)
259+
p, _ = parseTime(datestr, time.Local, modifiedOpts...)
256260
}
257261
}
258262

@@ -1185,20 +1189,27 @@ iterRunes:
11851189
// Thu, 4 Jan 2018 17:53:36 +0000
11861190
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
11871191
// Mon, 02-Jan-06 15:04:05 MST
1192+
var offset int
11881193
switch r {
1189-
case ' ', '-':
1194+
case ' ':
1195+
for i+1 < len(datestr) && datestr[i+1] == ' ' {
1196+
i++
1197+
offset++
1198+
}
1199+
fallthrough
1200+
case '-':
11901201
if p.dayi == 0 {
11911202
p.dayi = i + 1
11921203
} else if p.moi == 0 {
11931204
p.daylen = i - p.dayi
11941205
p.setDay()
11951206
p.moi = i + 1
11961207
} else if p.yeari == 0 {
1197-
p.molen = i - p.moi
1208+
p.molen = i - p.moi - offset
11981209
p.set(p.moi, "Jan")
11991210
p.yeari = i + 1
12001211
} else {
1201-
p.yearlen = i - p.yeari
1212+
p.yearlen = i - p.yeari - offset
12021213
p.setYear()
12031214
p.stateTime = timeStart
12041215
break iterRunes
@@ -1421,7 +1432,12 @@ iterRunes:
14211432
// 15:44:11 UTC+0100 2015
14221433
switch r {
14231434
case '+', '-':
1424-
p.tzlen = i - p.tzi
1435+
if datestr[p.tzi:i] == "GMT" {
1436+
p.tzi = 0
1437+
p.tzlen = 0
1438+
} else {
1439+
p.tzlen = i - p.tzi
1440+
}
14251441
if p.tzlen == 4 {
14261442
p.set(p.tzi, " MST")
14271443
} else if p.tzlen == 3 {
@@ -1532,7 +1548,6 @@ iterRunes:
15321548
if datestr[i-1] == 'm' {
15331549
p.extra = i - 2
15341550
p.trimExtra()
1535-
break
15361551
}
15371552
case '+', '-', '(':
15381553
// This really doesn't seem valid, but for some reason when round-tripping a go date
@@ -1542,7 +1557,6 @@ iterRunes:
15421557
p.extra = i - 1
15431558
p.stateTime = timeWsOffset
15441559
p.trimExtra()
1545-
break
15461560
default:
15471561
switch {
15481562
case unicode.IsDigit(r):
@@ -1689,7 +1703,6 @@ iterRunes:
16891703
// 00:00:00.000 +0300 +0300
16901704
p.extra = i - 1
16911705
p.trimExtra()
1692-
break
16931706
default:
16941707
if unicode.IsLetter(r) {
16951708
// 00:07:31.945167 +0000 UTC
@@ -1758,10 +1771,13 @@ iterRunes:
17581771
p.trimExtra()
17591772
case timeWsAlphaZoneOffset:
17601773
// 06:20:00 UTC-05
1761-
if i-p.offseti < 4 {
1774+
switch i - p.offseti {
1775+
case 2, 3, 4:
17621776
p.set(p.offseti, "-07")
1763-
} else {
1777+
case 5:
17641778
p.set(p.offseti, "-0700")
1779+
case 6:
1780+
p.set(p.offseti, "-07:00")
17651781
}
17661782

17671783
case timePeriod:
@@ -2135,7 +2151,7 @@ func RetryAmbiguousDateWithSwap(retryAmbiguousDateWithSwap bool) ParserOption {
21352151
}
21362152
}
21372153

2138-
func newParser(dateStr string, loc *time.Location, opts ...ParserOption) *parser {
2154+
func newParser(dateStr string, loc *time.Location, opts ...ParserOption) (*parser, error) {
21392155
p := &parser{
21402156
stateDate: dateStart,
21412157
stateTime: timeIgnore,
@@ -2148,9 +2164,11 @@ func newParser(dateStr string, loc *time.Location, opts ...ParserOption) *parser
21482164

21492165
// allow the options to mutate the parser fields from their defaults
21502166
for _, option := range opts {
2151-
_ = option(p)
2167+
if err := option(p); err != nil {
2168+
return nil, fmt.Errorf("option error: %w", err)
2169+
}
21522170
}
2153-
return p
2171+
return p, nil
21542172
}
21552173

21562174
func (p *parser) nextIs(i int, b byte) bool {
@@ -2268,17 +2286,6 @@ func (p *parser) trimExtra() {
22682286
}
22692287
}
22702288

2271-
// func (p *parser) remove(i, length int) {
2272-
// if len(p.format) > i+length {
2273-
// //append(a[:i], a[j:]...)
2274-
// p.format = append(p.format[0:i], p.format[i+length:]...)
2275-
// }
2276-
// if len(p.datestr) > i+length {
2277-
// //append(a[:i], a[j:]...)
2278-
// p.datestr = fmt.Sprintf("%s%s", p.datestr[0:i], p.datestr[i+length:])
2279-
// }
2280-
// }
2281-
22822289
func (p *parser) parse() (time.Time, error) {
22832290
if p.t != nil {
22842291
return *p.t, nil

0 commit comments

Comments
 (0)