dateparse/parseany.go

873 lines
26 KiB
Go
Raw Normal View History

2017-10-04 18:50:25 +08:00
// Package dateparse parses date-strings without knowing the format
// in advance, using a fast lex based approach to eliminate shotgun
// attempts. It leans towards US style dates when there is a conflict.
2014-04-21 10:56:17 +08:00
package dateparse
import (
"fmt"
2014-04-26 07:59:10 +08:00
"strconv"
2014-04-21 10:56:17 +08:00
"time"
"unicode"
)
2017-07-27 09:27:53 +08:00
type dateState int
2014-05-21 13:08:25 +08:00
2014-04-21 10:56:17 +08:00
const (
2017-08-13 00:48:28 +08:00
stateStart dateState = iota
stateDigit
stateDigitDash
stateDigitDashAlpha
stateDigitDashWs
stateDigitDashWsWs
stateDigitDashWsWsAMPMMaybe
stateDigitDashWsWsOffset
stateDigitDashWsWsOffsetAlpha
stateDigitDashWsWsOffsetColonAlpha
stateDigitDashWsWsOffsetColon
stateDigitDashWsOffset
stateDigitDashWsWsAlpha
stateDigitDashWsPeriod
stateDigitDashWsPeriodAlpha
stateDigitDashWsPeriodOffset
stateDigitDashWsPeriodOffsetAlpha
stateDigitDashT
stateDigitDashTZ
stateDigitDashTZDigit
stateDigitDashTOffset
stateDigitDashTOffsetColon
stateDigitSlash
stateDigitSlashWS
stateDigitSlashWSColon
stateDigitSlashWSColonAMPM
stateDigitSlashWSColonColon
stateDigitSlashWSColonColonAMPM
stateDigitAlpha
stateAlpha
stateAlphaWS
stateAlphaWSDigitComma
stateAlphaWSAlpha
stateAlphaWSAlphaColon
stateAlphaWSAlphaColonOffset
stateAlphaWSAlphaColonAlpha
stateAlphaWSAlphaColonAlphaOffset
stateAlphaWSAlphaColonAlphaOffsetAlpha
stateWeekdayComma
stateWeekdayCommaOffset
stateWeekdayAbbrevComma
stateWeekdayAbbrevCommaOffset
stateWeekdayAbbrevCommaOffsetZone
2014-04-21 10:56:17 +08:00
)
var (
2017-07-14 00:11:41 +08:00
shortDates = []string{"01/02/2006", "1/2/2006", "06/01/02", "01/02/06", "1/2/06"}
)
2017-08-13 00:48:28 +08:00
// ParseAny parse an unknown date format, detect the layout, parse.
2017-07-27 13:39:44 +08:00
// Normal parse. Equivalent Timezone rules as time.Parse()
2014-05-07 12:15:43 +08:00
func ParseAny(datestr string) (time.Time, error) {
2017-07-27 07:42:12 +08:00
return parseTime(datestr, nil)
}
2017-08-13 00:48:28 +08:00
// ParseIn with Location, equivalent to time.ParseInLocation() timezone/offset
2017-07-27 13:37:37 +08:00
// rules. Using location arg, if timezone/offset info exists in the
// datestring, it uses the given location rules for any zone interpretation.
// That is, MST means one thing when using America/Denver and something else
// in other locations.
2017-07-27 07:42:12 +08:00
func ParseIn(datestr string, loc *time.Location) (time.Time, error) {
return parseTime(datestr, loc)
}
// ParseLocal Given an unknown date format, detect the layout,
// using time.Local, parse.
2017-07-27 08:08:58 +08:00
//
2017-07-27 13:37:37 +08:00
// Set Location to time.Local. Same as ParseIn Location but lazily uses
// the global time.Local variable for Location argument.
//
// denverLoc, _ := time.LoadLocation("America/Denver")
// time.Local = denverLoc
//
// t, err := dateparse.ParseLocal("3/1/2014")
//
// Equivalent to:
//
// t, err := dateparse.ParseIn("3/1/2014", denverLoc)
//
2017-07-27 07:42:12 +08:00
func ParseLocal(datestr string) (time.Time, error) {
return parseTime(datestr, time.Local)
}
2017-08-13 00:48:28 +08:00
// MustParse parse a date, and panic if it can't be parsed. Used for testing.
// Not recommended for most use-cases.
2017-07-27 13:39:44 +08:00
func MustParse(datestr string) time.Time {
t, err := parseTime(datestr, nil)
if err != nil {
panic(err.Error())
}
return t
}
2017-07-27 07:42:12 +08:00
func parse(layout, datestr string, loc *time.Location) (time.Time, error) {
if loc == nil {
return time.Parse(layout, datestr)
}
return time.ParseInLocation(layout, datestr, loc)
}
2014-04-21 10:56:17 +08:00
2017-07-27 07:42:12 +08:00
func parseTime(datestr string, loc *time.Location) (time.Time, error) {
2017-08-13 00:48:28 +08:00
state := stateStart
2014-04-21 10:56:17 +08:00
2014-07-11 06:25:23 +08:00
firstSlash := 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
2014-05-07 12:15:43 +08:00
iterRunes:
2014-04-21 10:56:17 +08:00
for i := 0; i < len(datestr); i++ {
2017-07-14 10:57:15 +08:00
r := rune(datestr[i])
// r, bytesConsumed := utf8.DecodeRuneInString(datestr[ri:])
// if bytesConsumed > 1 {
// ri += (bytesConsumed - 1)
// }
2014-05-07 12:15:43 +08:00
2014-04-21 10:56:17 +08:00
switch state {
2017-08-13 00:48:28 +08:00
case stateStart:
2014-05-07 12:15:43 +08:00
if unicode.IsDigit(r) {
2017-08-13 00:48:28 +08:00
state = stateDigit
2014-05-07 12:15:43 +08:00
} else if unicode.IsLetter(r) {
2017-08-13 00:48:28 +08:00
state = stateAlpha
2014-04-21 10:56:17 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigit: // starts digits
2014-05-07 12:15:43 +08:00
if unicode.IsDigit(r) {
continue
2017-02-06 02:04:03 +08:00
} else if unicode.IsLetter(r) {
2017-08-13 00:48:28 +08:00
state = stateDigitAlpha
2017-02-06 02:04:03 +08:00
continue
2014-04-21 10:56:17 +08:00
}
2014-05-07 12:15:43 +08:00
switch r {
2017-07-14 10:57:15 +08:00
case '-', '\u2212':
2017-08-13 00:48:28 +08:00
state = stateDigitDash
2014-05-07 12:15:43 +08:00
case '/':
2017-08-13 00:48:28 +08:00
state = stateDigitSlash
2014-07-11 06:25:23 +08:00
firstSlash = i
2014-04-25 08:51:56 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDash: // starts digit then dash 02-
2014-05-07 12:15:43 +08:00
// 2006-01-02T15:04:05Z07:00
2017-06-26 10:09:06 +08:00
// 2017-06-25T17:46:57.45706582-07:00
2014-05-07 12:15:43 +08:00
// 2006-01-02T15:04:05.999999999Z07:00
2017-07-18 05:46:18 +08:00
// 2006-01-02T15:04:05+0000
2014-05-12 09:08:56 +08:00
// 2012-08-03 18:31:59.257000000
2014-05-07 12:15:43 +08:00
// 2014-04-26 17:24:37.3186369
2017-01-31 09:18:48 +08:00
// 2017-01-27 00:07:31.945167
2014-05-07 12:15:43 +08:00
// 2016-03-14 00:00:00.000
2014-05-11 23:28:23 +08:00
// 2014-05-11 08:20:13,787
// 2017-07-19 03:21:51+00:00
2014-05-07 12:15:43 +08:00
// 2006-01-02
2014-05-12 09:22:16 +08:00
// 2013-04-01 22:43:22
2014-05-07 12:15:43 +08:00
// 2014-04-26 05:24:37 PM
2017-07-27 07:55:21 +08:00
// 2013-Feb-03
2014-05-07 12:15:43 +08:00
switch {
case r == ' ':
2017-08-13 00:48:28 +08:00
state = stateDigitDashWs
2014-05-07 12:15:43 +08:00
case r == 'T':
2017-08-13 00:48:28 +08:00
state = stateDigitDashT
2017-07-27 07:55:21 +08:00
default:
if unicode.IsLetter(r) {
2017-08-13 00:48:28 +08:00
state = stateDigitDashAlpha
2017-07-27 07:55:21 +08:00
break iterRunes
}
2014-04-25 08:51:56 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWs:
2014-05-12 09:22:16 +08:00
// 2013-04-01 22:43:22
2014-05-11 23:28:23 +08:00
// 2014-05-11 08:20:13,787
2017-08-13 00:48:28 +08:00
// 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
2017-08-13 00:48:28 +08:00
// stateDigitDashWsOffset
// 2017-07-19 03:21:51+00:00
2017-08-13 00:48:28 +08: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
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodOffset
// 2017-01-27 00:07:31.945167 +0000
// 2016-03-14 00:00:00.000 +0000
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodOffsetAlpha
// 2017-01-27 00:07:31.945167 +0000 UTC
// 2016-03-14 00:00:00.000 +0000 UTC
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodAlpha
// 2014-12-16 06:20:00.000 UTC
2014-05-07 12:15:43 +08:00
switch r {
2014-05-11 23:28:23 +08:00
case ',':
if len(datestr) == len("2014-05-11 08:20:13,787") {
2014-05-11 23:42:56 +08:00
// go doesn't seem to parse this one natively? or did i miss it?
2017-07-27 07:42:12 +08:00
t, err := parse("2006-01-02 03:04:05", datestr[:i], loc)
2017-07-14 10:57:15 +08:00
if err == nil {
2014-05-11 23:42:56 +08:00
ms, err := strconv.Atoi(datestr[i+1:])
if err == nil {
return time.Unix(0, t.UnixNano()+int64(ms)*1e6), nil
}
2014-05-11 23:28:23 +08:00
}
2017-07-14 10:57:15 +08:00
return t, err
2014-05-11 23:28:23 +08:00
}
case '-', '+':
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsOffset
2017-04-12 06:30:42 +08:00
case '.':
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsPeriod
case ' ':
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWs
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWs:
// stateDigitDashWsWsAlpha
// 2014-12-16 06:20:00 UTC
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsAMPMMaybe
// 2014-04-26 05:24:37 PM
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffset
// 2006-01-02 15:04:05 -0700
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetColon
// 2006-01-02 15:04:05 -07:00
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetColonAlpha
// 2015-02-18 00:12:00 +00:00 UTC
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetAlpha
// 2015-02-18 00:12:00 +0000 UTC
switch r {
case 'A', 'P':
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsAMPMMaybe
case '+', '-':
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsOffset
2014-12-03 06:57:00 +08:00
default:
if unicode.IsLetter(r) {
// 2014-12-16 06:20:00 UTC
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsAlpha
2014-12-03 06:57:00 +08:00
break iterRunes
}
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsAMPMMaybe:
if r == 'M' {
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 03:04:05 PM", datestr, loc)
}
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsAlpha
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsOffset:
// stateDigitDashWsWsOffset
// 2006-01-02 15:04:05 -0700
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetColon
// 2006-01-02 15:04:05 -07:00
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetColonAlpha
// 2015-02-18 00:12:00 +00:00 UTC
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetAlpha
// 2015-02-18 00:12:00 +0000 UTC
if r == ':' {
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsOffsetColon
} else if unicode.IsLetter(r) {
// 2015-02-18 00:12:00 +0000 UTC
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsOffsetAlpha
break iterRunes
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsOffsetColon:
// stateDigitDashWsWsOffsetColon
// 2006-01-02 15:04:05 -07:00
2017-08-13 00:48:28 +08:00
// stateDigitDashWsWsOffsetColonAlpha
// 2015-02-18 00:12:00 +00:00 UTC
if unicode.IsLetter(r) {
// 2015-02-18 00:12:00 +00:00 UTC
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsWsOffsetColonAlpha
break iterRunes
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWsPeriod:
2017-04-12 06:30:42 +08:00
// 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
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodOffset
// 2017-01-27 00:07:31.945167 +0000
// 2016-03-14 00:00:00.000 +0000
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodOffsetAlpha
// 2017-01-27 00:07:31.945167 +0000 UTC
// 2016-03-14 00:00:00.000 +0000 UTC
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodAlpha
// 2014-12-16 06:20:00.000 UTC
2017-04-12 06:30:42 +08:00
if unicode.IsLetter(r) {
// 2014-12-16 06:20:00.000 UTC
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsPeriodAlpha
2017-04-12 06:30:42 +08:00
break iterRunes
} else if r == '+' || r == '-' {
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsPeriodOffset
2017-04-12 06:30:42 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWsPeriodOffset:
// 2017-01-27 00:07:31.945167 +0000
// 2016-03-14 00:00:00.000 +0000
2017-08-13 00:48:28 +08:00
// stateDigitDashWsPeriodOffsetAlpha
// 2017-01-27 00:07:31.945167 +0000 UTC
// 2016-03-14 00:00:00.000 +0000 UTC
2017-04-12 06:30:42 +08:00
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
2017-08-13 00:48:28 +08:00
state = stateDigitDashWsPeriodOffsetAlpha
2017-04-12 06:30:42 +08:00
break iterRunes
}
2017-08-13 00:48:28 +08:00
case stateDigitDashT: // starts digit then dash 02- then T
// stateDigitDashT
2015-06-26 05:09:39 +08:00
// 2006-01-02T15:04:05
2017-08-13 00:48:28 +08:00
// stateDigitDashTZ
// 2006-01-02T15:04:05.999999999Z
// 2006-01-02T15:04:05.99999999Z
2014-10-03 05:47:22 +08:00
// 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
2017-08-13 00:48:28 +08:00
// stateDigitDashTZDigit
2017-06-26 10:09:06 +08:00
// 2006-01-02T15:04:05.999999999Z07:00
// 2006-01-02T15:04:05Z07:00
// With another dash aka time-zone at end
2017-08-13 00:48:28 +08:00
// stateDigitDashTOffset
// stateDigitDashTOffsetColon
2017-07-18 05:46:18 +08:00
// 2017-06-25T17:46:57.45706582-07:00
// 2017-06-25T17:46:57+04:00
// 2006-01-02T15:04:05+0000
2017-07-14 10:57:15 +08:00
switch r {
case '-', '+':
2017-08-13 00:48:28 +08:00
state = stateDigitDashTOffset
2017-07-14 10:57:15 +08:00
case 'Z':
2017-08-13 00:48:28 +08:00
state = stateDigitDashTZ
2017-06-26 10:09:06 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashTZ:
2017-06-26 10:09:06 +08:00
if unicode.IsDigit(r) {
2017-08-13 00:48:28 +08:00
state = stateDigitDashTZDigit
2014-05-07 03:32:49 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashTOffset:
2017-07-18 05:46:18 +08:00
if r == ':' {
2017-08-13 00:48:28 +08:00
state = stateDigitDashTOffsetColon
2017-07-18 05:46:18 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitSlash: // starts digit then slash 02/
2014-07-11 06:25:23 +08:00
// 2014/07/10 06:55:38.156283
2014-05-07 12:15:43 +08:00
// 03/19/2012 10:11:59
2014-05-12 04:33:13 +08:00
// 04/2/2014 03:00:37
2014-04-21 10:56:17 +08:00
// 3/1/2012 10:11:59
2014-04-28 04:26:17 +08:00
// 4/8/2014 22:05
2014-04-21 10:56:17 +08:00
// 3/1/2014
// 10/13/2014
// 01/02/2006
2016-01-06 03:34:31 +08:00
// 1/2/06
2014-05-07 12:15:43 +08:00
if unicode.IsDigit(r) || r == '/' {
continue
2014-04-28 05:33:33 +08:00
}
2014-05-07 12:15:43 +08:00
switch r {
case ' ':
2017-08-13 00:48:28 +08:00
state = stateDigitSlashWS
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitSlashWS: // starts digit then slash 02/ more digits/slashes then whitespace
2014-07-11 06:25:23 +08:00
// 2014/07/10 06:55:38.156283
2014-05-07 12:15:43 +08:00
// 03/19/2012 10:11:59
2014-05-12 04:33:13 +08:00
// 04/2/2014 03:00:37
2014-05-07 12:15:43 +08:00
// 3/1/2012 10:11:59
// 4/8/2014 22:05
2017-11-19 02:21:24 +08:00
// 4/8/14 22:05
2014-05-07 12:15:43 +08:00
switch r {
case ':':
2017-08-13 00:48:28 +08:00
state = stateDigitSlashWSColon
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitSlashWSColon: // starts digit then slash 02/ more digits/slashes then whitespace
2014-07-11 06:25:23 +08:00
// 2014/07/10 06:55:38.156283
2014-05-07 12:15:43 +08:00
// 03/19/2012 10:11:59
2014-05-21 13:08:25 +08:00
// 04/2/2014 03:00:37
2014-05-07 12:15:43 +08:00
// 3/1/2012 10:11:59
// 4/8/2014 22:05
2017-11-19 02:21:24 +08:00
// 4/8/14 22:05
2015-10-01 03:09:08 +08:00
// 3/1/2012 10:11:59 AM
2014-05-07 12:15:43 +08:00
switch r {
case ':':
2017-08-13 00:48:28 +08:00
state = stateDigitSlashWSColonColon
2017-02-14 10:39:03 +08:00
case 'A', 'P':
2017-08-13 00:48:28 +08:00
state = stateDigitSlashWSColonAMPM
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitSlashWSColonColon: // starts digit then slash 02/ more digits/slashes then whitespace
2015-10-01 03:09:08 +08:00
// 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
2017-11-19 02:21:24 +08:00
// 4/8/14 22:05
2015-10-01 03:09:08 +08:00
// 3/1/2012 10:11:59 AM
switch r {
2017-02-14 10:39:03 +08:00
case 'A', 'P':
2017-08-13 00:48:28 +08:00
state = stateDigitSlashWSColonColonAMPM
2015-10-01 03:09:08 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitAlpha:
2017-02-06 02:04:03 +08:00
// 12 Feb 2006, 19:17
// 12 Feb 2006, 19:17:22
switch {
case len(datestr) == len("02 Jan 2006, 15:04"):
2017-07-27 07:42:12 +08:00
return parse("02 Jan 2006, 15:04", datestr, loc)
2017-02-06 02:04:03 +08:00
case len(datestr) == len("02 Jan 2006, 15:04:05"):
2017-07-27 07:42:12 +08:00
return parse("02 Jan 2006, 15:04:05", datestr, loc)
2017-02-06 02:04:03 +08:00
}
2017-08-13 00:48:28 +08:00
case stateAlpha: // starts alpha
// stateAlphaWS
2017-07-14 00:11:41 +08:00
// 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)
2017-08-13 00:48:28 +08:00
// stateAlphaWSDigitComma
2017-07-14 00:11:41 +08:00
// May 8, 2009 5:57:51 PM
//
2017-08-13 00:48:28 +08:00
// stateWeekdayComma
2017-07-14 00:11:41 +08:00
// Monday, 02-Jan-06 15:04:05 MST
2017-08-13 00:48:28 +08:00
// stateWeekdayCommaOffset
2017-07-14 00:11:41 +08:00
// Monday, 02 Jan 2006 15:04:05 -0700
// Monday, 02 Jan 2006 15:04:05 +0100
2017-08-13 00:48:28 +08:00
// stateWeekdayAbbrevComma
2017-07-14 00:11:41 +08:00
// Mon, 02-Jan-06 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 MST
2017-08-13 00:48:28 +08:00
// stateWeekdayAbbrevCommaOffset
2017-07-14 00:11:41 +08:00
// Mon, 02 Jan 2006 15:04:05 -0700
// Thu, 13 Jul 2017 08:58:40 +0100
2017-08-13 00:48:28 +08:00
// stateWeekdayAbbrevCommaOffsetZone
2017-07-14 22:02:22 +08:00
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
2014-05-07 12:15:43 +08:00
switch {
2017-07-14 00:11:41 +08:00
case unicode.IsLetter(r):
continue
2014-05-07 12:15:43 +08:00
case r == ' ':
2017-08-13 00:48:28 +08:00
state = stateAlphaWS
2014-05-21 13:53:52 +08:00
case r == ',':
2017-07-14 00:11:41 +08:00
if i == 3 {
2017-08-13 00:48:28 +08:00
state = stateWeekdayAbbrevComma
2017-07-14 00:11:41 +08:00
} else {
2017-08-13 00:48:28 +08:00
state = stateWeekdayComma
}
}
2017-08-13 00:48:28 +08:00
case stateWeekdayComma: // Starts alpha then comma
2017-07-14 00:11:41 +08:00
// Mon, 02-Jan-06 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 MST
2017-08-13 00:48:28 +08:00
// stateWeekdayCommaOffset
2017-07-14 00:11:41 +08:00
// Monday, 02 Jan 2006 15:04:05 -0700
// Monday, 02 Jan 2006 15:04:05 +0100
switch {
case r == '-':
if i < 15 {
2017-07-27 07:42:12 +08:00
return parse("Monday, 02-Jan-06 15:04:05 MST", datestr, loc)
}
2017-08-13 00:48:28 +08:00
state = stateWeekdayCommaOffset
2017-07-14 00:11:41 +08:00
case r == '+':
2017-08-13 00:48:28 +08:00
state = stateWeekdayCommaOffset
}
2017-08-13 00:48:28 +08:00
case stateWeekdayAbbrevComma: // Starts alpha then comma
// Mon, 02-Jan-06 15:04:05 MST
2017-07-14 00:11:41 +08:00
// Mon, 02 Jan 2006 15:04:05 MST
2017-08-13 00:48:28 +08:00
// stateWeekdayAbbrevCommaOffset
2017-07-14 00:11:41 +08:00
// Mon, 02 Jan 2006 15:04:05 -0700
// Thu, 13 Jul 2017 08:58:40 +0100
2017-08-13 00:48:28 +08:00
// stateWeekdayAbbrevCommaOffsetZone
2017-07-14 22:02:22 +08:00
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
switch {
case r == '-':
if i < 15 {
2017-07-27 07:42:12 +08:00
return parse("Mon, 02-Jan-06 15:04:05 MST", datestr, loc)
}
2017-08-13 00:48:28 +08:00
state = stateWeekdayAbbrevCommaOffset
2017-07-14 00:11:41 +08:00
case r == '+':
2017-08-13 00:48:28 +08:00
state = stateWeekdayAbbrevCommaOffset
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
case stateWeekdayAbbrevCommaOffset:
// stateWeekdayAbbrevCommaOffset
2017-07-14 22:02:22 +08:00
// Mon, 02 Jan 2006 15:04:05 -0700
// Thu, 13 Jul 2017 08:58:40 +0100
2017-08-13 00:48:28 +08:00
// stateWeekdayAbbrevCommaOffsetZone
2017-07-14 22:02:22 +08:00
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
if r == '(' {
2017-08-13 00:48:28 +08:00
state = stateWeekdayAbbrevCommaOffsetZone
2017-07-14 22:02:22 +08:00
}
2017-08-13 00:48:28 +08:00
case stateAlphaWS: // Starts alpha then whitespace
2015-07-04 01:27:48 +08:00
// 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)
2015-08-11 01:54:01 +08:00
// Mon Aug 10 15:44:11 UTC+0100 2015
2014-05-07 12:15:43 +08:00
switch {
case unicode.IsLetter(r):
2017-08-13 00:48:28 +08:00
state = stateAlphaWSAlpha
2017-07-14 00:11:41 +08:00
case unicode.IsDigit(r):
2017-08-13 00:48:28 +08:00
state = stateAlphaWSDigitComma
2014-05-21 13:53:52 +08:00
}
2017-08-13 00:48:28 +08:00
case stateAlphaWSDigitComma: // Starts Alpha, whitespace, digit, comma
2014-05-07 12:15:43 +08:00
// May 8, 2009 5:57:51 PM
2017-07-27 07:42:12 +08:00
return parse("Jan 2, 2006 3:04:05 PM", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateAlphaWSAlpha: // Alpha, whitespace, alpha
2015-07-04 01:27:48 +08:00
// Mon Jan _2 15:04:05 2006
// Mon Jan 02 15:04:05 -0700 2006
2015-07-04 01:27:48 +08:00
// 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 == ':' {
2017-08-13 00:48:28 +08:00
state = stateAlphaWSAlphaColon
}
2017-08-13 00:48:28 +08:00
case stateAlphaWSAlphaColon: // Alpha, whitespace, alpha, :
// Mon Jan _2 15:04:05 2006
2015-07-04 01:27:48 +08:00
// Mon Jan 02 15:04:05 -0700 2006
// Mon Jan _2 15:04:05 MST 2006
2015-08-11 01:54:01 +08:00
// 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) {
2017-08-13 00:48:28 +08:00
state = stateAlphaWSAlphaColonAlpha
} else if r == '-' || r == '+' {
2017-08-13 00:48:28 +08:00
state = stateAlphaWSAlphaColonOffset
}
2017-08-13 00:48:28 +08:00
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 == '+' {
2017-08-13 00:48:28 +08:00
state = stateAlphaWSAlphaColonAlphaOffset
}
2017-08-13 00:48:28 +08:00
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) {
2017-08-13 00:48:28 +08:00
state = stateAlphaWSAlphaColonAlphaOffsetAlpha
2014-05-21 13:53:52 +08:00
}
2014-05-07 12:15:43 +08:00
default:
break iterRunes
2014-04-21 10:56:17 +08:00
}
2014-05-07 12:15:43 +08:00
}
switch state {
2017-08-13 00:48:28 +08:00
case stateDigit:
2014-05-07 12:15:43 +08:00
// unixy timestamps ish
2017-07-14 10:57:15 +08:00
// 1499979655583057426 nanoseconds
// 1499979795437000 micro-seconds
// 1499979795437 milliseconds
2015-08-19 06:50:04 +08:00
// 1384216367189
// 1332151919 seconds
// 20140601 yyyymmdd
2016-03-02 05:25:00 +08:00
// 2014 yyyy
t := time.Time{}
2017-07-14 10:57:15 +08:00
if len(datestr) > len("1499979795437000") {
2014-04-26 07:59:10 +08:00
if nanoSecs, err := strconv.ParseInt(datestr, 10, 64); err == nil {
t = time.Unix(0, nanoSecs)
2014-04-26 07:59:10 +08:00
}
2017-07-14 10:57:15 +08:00
} else if len(datestr) > len("1499979795437") {
2014-05-07 12:15:43 +08:00
if microSecs, err := strconv.ParseInt(datestr, 10, 64); err == nil {
t = time.Unix(0, microSecs*1000)
2014-05-07 12:15:43 +08:00
}
2017-07-14 10:57:15 +08:00
} else if len(datestr) > len("1332151919") {
2014-10-08 09:30:17 +08:00
if miliSecs, err := strconv.ParseInt(datestr, 10, 64); err == nil {
t = time.Unix(0, miliSecs*1000*1000)
2014-10-08 09:30:17 +08:00
}
2015-08-19 06:50:04 +08:00
} else if len(datestr) == len("20140601") {
2017-07-27 07:42:12 +08:00
return parse("20060102", datestr, loc)
2016-03-02 05:25:00 +08:00
} else if len(datestr) == len("2014") {
2017-07-27 07:42:12 +08:00
return parse("2006", datestr, loc)
2014-04-26 07:59:10 +08:00
}
if t.IsZero() {
if secs, err := strconv.ParseInt(datestr, 10, 64); err == nil {
2017-10-08 00:34:59 +08:00
if secs < 0 {
// Now, for unix-seconds we aren't going to guess a lot
// nothing before unix-epoch
} else {
t = time.Unix(secs, 0)
}
}
}
if !t.IsZero() {
if loc == nil {
return t, nil
}
return t.In(loc), nil
2017-08-13 00:48:28 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDash: // starts digit then dash 02-
2014-05-07 12:15:43 +08:00
// 2006-01-02
2016-03-02 05:25:00 +08:00
// 2006-01
2014-05-07 12:15:43 +08:00
if len(datestr) == len("2014-04-26") {
2017-07-27 07:42:12 +08:00
return parse("2006-01-02", datestr, loc)
2016-03-02 05:25:00 +08:00
} else if len(datestr) == len("2014-04") {
2017-07-27 07:42:12 +08:00
return parse("2006-01", datestr, loc)
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashAlpha:
2017-07-27 07:55:21 +08:00
// 2013-Feb-03
return parse("2006-Jan-02", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashTOffset:
2017-07-18 05:46:18 +08:00
// 2006-01-02T15:04:05+0000
2017-07-27 07:42:12 +08:00
return parse("2006-01-02T15:04:05-0700", datestr, loc)
2017-07-18 05:46:18 +08:00
2017-08-13 00:48:28 +08:00
case stateDigitDashTOffsetColon:
2017-07-12 04:40:58 +08:00
// With another +/- time-zone at end
2017-07-12 02:00:40 +08:00
// 2006-01-02T15:04:05.999999999+07:00
2017-07-12 04:40:58 +08:00
// 2006-01-02T15:04:05.999999999-07:00
2017-07-12 02:00:40 +08:00
// 2006-01-02T15:04:05.999999+07:00
2017-07-12 04:40:58 +08:00
// 2006-01-02T15:04:05.999999-07:00
2017-07-12 02:00:40 +08:00
// 2006-01-02T15:04:05.999+07:00
2017-07-12 04:40:58 +08:00
// 2006-01-02T15:04:05.999-07:00
2017-07-12 02:00:40 +08:00
// 2006-01-02T15:04:05+07:00
2017-07-12 04:40:58 +08:00
// 2006-01-02T15:04:05-07:00
2017-07-27 07:42:12 +08:00
return parse("2006-01-02T15:04:05-07:00", datestr, loc)
2017-07-14 10:57:15 +08:00
2017-08-13 00:48:28 +08:00
case stateDigitDashT: // starts digit then dash 02- then T
2017-06-26 10:09:06 +08:00
// 2006-01-02T15:04:05.999999
// 2006-01-02T15:04:05.999999
2017-07-27 07:42:12 +08:00
return parse("2006-01-02T15:04:05", datestr, loc)
2017-07-14 10:57:15 +08:00
2017-08-13 00:48:28 +08:00
case stateDigitDashTZDigit:
2017-07-14 10:57:15 +08:00
// 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)
2017-08-13 00:48:28 +08:00
case stateDigitDashTZ: // starts digit then dash 02- then T Then Z
2017-06-26 10:09:06 +08:00
// 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
switch len(datestr) {
case len("2009-08-12T22:15Z"):
2017-07-27 07:42:12 +08:00
return parse("2006-01-02T15:04Z", datestr, loc)
default:
2017-07-27 07:42:12 +08:00
return parse("2006-01-02T15:04:05Z", datestr, loc)
2017-06-26 10:09:06 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWs: // starts digit then dash 02- then whitespace 1 << 2 << 5 + 3
2014-05-12 09:22:16 +08:00
// 2013-04-01 22:43:22
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsOffset:
// 2006-01-02 15:04:05 -0700
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 -0700", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsOffsetColon:
// 2006-01-02 15:04:05 -07:00
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 -07:00", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsOffsetAlpha:
// 2015-02-18 00:12:00 +0000 UTC
2017-07-27 07:42:12 +08:00
t, err := parse("2006-01-02 15:04:05 -0700 UTC", datestr, loc)
if err == nil {
return t, nil
2014-05-07 12:15:43 +08:00
}
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 +0000 GMT", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsOffsetColonAlpha:
// 2015-02-18 00:12:00 +00:00 UTC
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 -07:00 UTC", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsOffset:
// 2017-07-19 03:21:51+00:00
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05-07:00", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsWsAlpha:
2014-12-03 06:57:00 +08:00
// 2014-12-16 06:20:00 UTC
2017-07-27 07:42:12 +08:00
t, err := parse("2006-01-02 15:04:05 UTC", datestr, loc)
if err == nil {
return t, nil
}
2017-07-27 07:42:12 +08:00
t, err = parse("2006-01-02 15:04:05 GMT", datestr, loc)
if err == nil {
return t, nil
}
if len(datestr) > len("2006-01-02 03:04:05") {
2017-07-27 07:42:12 +08:00
t, err = parse("2006-01-02 03:04:05", datestr[:len("2006-01-02 03:04:05")], loc)
if err == nil {
return t, nil
2015-04-17 02:37:50 +08:00
}
2017-04-12 06:30:42 +08:00
}
2017-08-13 00:48:28 +08:00
case stateDigitDashWsPeriod:
2017-04-12 06:30:42 +08:00
// 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
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsPeriodAlpha:
2017-04-12 06:30:42 +08:00
// 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
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 UTC", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsPeriodOffset:
2017-04-12 06:30:42 +08:00
// 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
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 -0700", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateDigitDashWsPeriodOffsetAlpha:
2017-04-12 06:30:42 +08:00
// 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
2017-07-27 07:42:12 +08:00
return parse("2006-01-02 15:04:05 -0700 UTC", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateAlphaWSAlphaColon:
// Mon Jan _2 15:04:05 2006
2017-07-27 07:42:12 +08:00
return parse(time.ANSIC, datestr, loc)
2017-08-13 00:48:28 +08:00
case stateAlphaWSAlphaColonOffset:
// Mon Jan 02 15:04:05 -0700 2006
2017-07-27 07:42:12 +08:00
return parse(time.RubyDate, datestr, loc)
2017-08-13 00:48:28 +08:00
case stateAlphaWSAlphaColonAlpha:
// Mon Jan _2 15:04:05 MST 2006
2017-07-27 07:42:12 +08:00
return parse(time.UnixDate, datestr, loc)
2017-08-13 00:48:28 +08:00
case stateAlphaWSAlphaColonAlphaOffset:
// Mon Aug 10 15:44:11 UTC+0100 2015
2017-07-27 07:42:12 +08:00
return parse("Mon Jan 02 15:04:05 MST-0700 2006", datestr, loc)
2017-08-13 00:48:28 +08:00
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]
2017-07-27 07:42:12 +08:00
return parse("Mon Jan 02 2006 15:04:05 MST-0700", dateTmp, loc)
}
2017-08-13 00:48:28 +08:00
case stateDigitSlash: // starts digit then slash 02/ (but nothing else)
2014-05-07 12:15:43 +08:00
// 3/1/2014
// 10/13/2014
// 01/02/2006
2014-07-11 06:25:23 +08:00
// 2014/10/13
if firstSlash == 4 {
if len(datestr) == len("2006/01/02") {
2017-07-27 07:42:12 +08:00
return parse("2006/01/02", datestr, loc)
2014-05-07 12:15:43 +08:00
}
2017-08-13 00:48:28 +08:00
return parse("2006/1/2", datestr, loc)
2017-08-13 00:50:14 +08:00
}
for _, parseFormat := range shortDates {
if t, err := parse(parseFormat, datestr, loc); err == nil {
return t, nil
2014-05-07 12:15:43 +08:00
}
}
2017-08-13 00:48:28 +08:00
case stateDigitSlashWSColon: // starts digit then slash 02/ more digits/slashes then whitespace
2014-05-07 12:15:43 +08:00
// 4/8/2014 22:05
2014-07-11 06:25:23 +08:00
// 04/08/2014 22:05
// 2014/4/8 22:05
// 2014/04/08 22:05
2017-02-14 08:49:48 +08:00
2014-07-11 06:25:23 +08:00
if firstSlash == 4 {
2017-07-14 10:57:15 +08:00
for _, layout := range []string{"2006/01/02 15:04", "2006/1/2 15:04", "2006/01/2 15:04", "2006/1/02 15:04"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2014-05-12 04:33:13 +08:00
}
}
2014-05-07 12:15:43 +08:00
} else {
2017-11-19 02:21:24 +08:00
for _, layout := range []string{"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"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2014-07-11 06:25:23 +08:00
}
2014-05-07 12:15:43 +08:00
}
}
2017-02-14 10:39:03 +08:00
2017-08-13 00:48:28 +08:00
case stateDigitSlashWSColonAMPM: // starts digit then slash 02/ more digits/slashes then whitespace
2017-02-14 10:39:03 +08:00
// 4/8/2014 22:05 PM
// 04/08/2014 22:05 PM
2017-07-14 10:57:15 +08:00
// 04/08/2014 1:05 PM
2017-02-14 10:39:03 +08:00
// 2014/4/8 22:05 PM
// 2014/04/08 22:05 PM
if firstSlash == 4 {
2017-07-14 10:57:15 +08:00
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"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2017-02-14 10:39:03 +08:00
}
}
} else {
2017-07-14 10:57:15 +08:00
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 3:04 PM", "01/2/2006 3:04 PM", "1/02/2006 3:04 PM", "1/2/2006 3:04 PM"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2017-02-14 10:39:03 +08:00
}
2017-07-14 10:57:15 +08:00
2017-02-14 10:39:03 +08:00
}
}
2017-02-14 08:49:48 +08:00
2017-08-13 00:48:28 +08:00
case stateDigitSlashWSColonColon: // starts digit then slash 02/ more digits/slashes then whitespace double colons
2014-07-11 06:25:23 +08:00
// 2014/07/10 06:55:38.156283
2014-05-07 12:15:43 +08:00
// 03/19/2012 10:11:59
// 3/1/2012 10:11:59
2014-05-12 04:33:13 +08:00
// 03/1/2012 10:11:59
// 3/01/2012 10:11:59
2017-11-19 02:21:24 +08:00
// 4/8/14 22:05
2014-07-11 06:25:23 +08:00
if firstSlash == 4 {
2017-07-14 10:57:15 +08:00
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"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2014-05-12 04:33:13 +08:00
}
}
2014-05-07 12:15:43 +08:00
} else {
2017-07-14 10:57:15 +08:00
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"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2014-07-11 06:25:23 +08:00
}
2014-05-07 12:15:43 +08:00
}
}
2017-02-14 10:39:03 +08:00
2017-08-13 00:48:28 +08:00
case stateDigitSlashWSColonColonAMPM: // starts digit then slash 02/ more digits/slashes then whitespace double colons
2017-02-14 10:39:03 +08:00
// 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 firstSlash == 4 {
2017-07-14 10:57:15 +08:00
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 3:04:05 PM", "2006/1/02 3:04:05 PM", "2006/01/2 3:04:05 PM", "2006/1/2 3:04:05 PM"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2017-02-14 10:39:03 +08:00
}
}
} else {
2017-07-14 10:57:15 +08:00
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"} {
2017-07-27 07:42:12 +08:00
if t, err := parse(layout, datestr, loc); err == nil {
2017-07-14 10:57:15 +08:00
return t, nil
2017-02-14 10:39:03 +08:00
}
}
}
2017-02-14 08:49:48 +08:00
2017-08-13 00:48:28 +08:00
case stateWeekdayCommaOffset:
2017-07-14 00:11:41 +08:00
// Monday, 02 Jan 2006 15:04:05 -0700
// Monday, 02 Jan 2006 15:04:05 +0100
2017-07-27 07:42:12 +08:00
return parse("Monday, 02 Jan 2006 15:04:05 -0700", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateWeekdayAbbrevComma: // Starts alpha then comma
2017-07-14 00:11:41 +08:00
// Mon, 02-Jan-06 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 MST
2017-07-27 07:42:12 +08:00
return parse("Mon, 02 Jan 2006 15:04:05 MST", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateWeekdayAbbrevCommaOffset:
2017-07-14 00:11:41 +08:00
// 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
2017-07-27 07:42:12 +08:00
return parse("Mon, 02 Jan 2006 15:04:05 -0700", datestr, loc)
2017-08-13 00:48:28 +08:00
case stateWeekdayAbbrevCommaOffsetZone:
2017-07-14 22:02:22 +08:00
// Tue, 11 Jul 2017 16:28:13 +0200 (CEST)
2017-07-27 07:42:12 +08:00
return parse("Mon, 02 Jan 2006 15:04:05 -0700 (CEST)", datestr, loc)
2014-04-21 10:56:17 +08:00
}
2014-06-16 02:18:20 +08:00
return time.Time{}, fmt.Errorf("Could not find date format for %s", datestr)
2014-04-21 10:56:17 +08:00
}