@@ -137,11 +137,12 @@ const (
137137var (
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
143144func 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
237238func 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
21562174func (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-
22822289func (p * parser ) parse () (time.Time , error ) {
22832290 if p .t != nil {
22842291 return * p .t , nil
0 commit comments