2014-04-21 10:56:17 +08:00
package dateparse
import (
"fmt"
2014-04-26 07:59:10 +08:00
"strconv"
2015-10-01 03:09:08 +08:00
"strings"
2014-04-21 10:56:17 +08:00
"time"
"unicode"
2014-05-07 12:15:43 +08:00
"unicode/utf8"
2015-10-01 03:09:08 +08:00
u "github.com/araddon/gou"
2014-04-21 10:56:17 +08:00
)
2014-05-21 13:08:25 +08:00
type DateState int
2014-04-21 10:56:17 +08:00
const (
2014-05-21 13:08:25 +08:00
ST_START DateState = iota
ST_DIGIT
ST_DIGITDASH
ST_DIGITDASHWS
2014-12-03 06:57:00 +08:00
ST_DIGITDASHWSALPHA
2014-05-21 13:08:25 +08:00
ST_DIGITDASHT
ST_DIGITCOMMA
ST_DIGITCOLON
ST_DIGITSLASH
ST_DIGITSLASHWS
ST_DIGITSLASHWSCOLON
2017-02-14 08:49:48 +08:00
ST_DIGITSLASHWSCOLONAM
ST_DIGITSLASHWSCOLONPM
2014-05-21 13:08:25 +08:00
ST_DIGITSLASHWSCOLONCOLON
2017-02-14 08:49:48 +08:00
ST_DIGITSLASHWSCOLONCOLONAM
ST_DIGITSLASHWSCOLONCOLONPM
2017-02-06 02:04:03 +08:00
ST_DIGITALPHA
2014-05-21 13:08:25 +08:00
ST_ALPHA
ST_ALPHAWS
ST_ALPHAWSCOMMA
2014-05-21 13:53:52 +08:00
ST_ALPHAWSALPHA
2014-05-21 13:08:25 +08:00
ST_ALPHACOMMA
2014-06-16 02:18:20 +08:00
ST_ALPHACOMMADASH
ST_ALPHACOMMADASHDASH
2016-05-04 04:55:11 +08:00
ST_MONTHCOMMA
ST_WEEKDAYCOMMA
ST_WEEKDAYABBREVCOMMA
2014-04-21 10:56:17 +08:00
)
2014-05-07 12:15:43 +08:00
var _ = u . EMPTY
2014-04-21 10:56:17 +08:00
2014-12-16 03:20:40 +08:00
var (
2016-05-04 04:55:11 +08:00
shortDates = [ ] string { "01/02/2006" , "1/2/2006" , "06/01/02" , "01/02/06" , "1/2/06" }
weekdays = map [ string ] bool { "Monday" : true , "Tuesday" : true , "Wednesday" : true , "Thursday" : true , "Friday" : true , "Saturday" : true , "Sunday" : true }
weekdayAbbrev = map [ string ] bool { "Mon" : true , "Tue" : true , "Wed" : true , "Thu" : true , "Fri" : true , "Sat" : true , "Sun" : true }
2014-12-16 03:20:40 +08:00
)
2016-09-19 02:46:39 +08:00
// Parse a date, and panic if it can't be parsed
func MustParse ( datestr string ) time . Time {
t , err := ParseAny ( datestr )
if err != nil {
panic ( err . Error ( ) )
}
return t
}
2014-05-07 12:15:43 +08:00
// Given an unknown date format, detect the type, parse, return time
func ParseAny ( datestr string ) ( time . Time , error ) {
2014-04-21 10:56:17 +08:00
2014-05-21 13:08:25 +08:00
state := ST_START
2014-04-21 10:56:17 +08:00
2014-07-11 06:25:23 +08:00
firstSlash := 0
2014-06-16 03:11:29 +08:00
// 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 ++ {
2014-06-16 03:11:29 +08:00
r , bytesConsumed := utf8 . DecodeRuneInString ( datestr [ i : ] )
if bytesConsumed > 1 {
i += ( bytesConsumed - 1 )
}
2014-05-07 12:15:43 +08:00
2014-07-11 06:25:23 +08:00
//u.Infof("char=%s i=%d datestr=%s", r, i, datestr)
2014-04-21 10:56:17 +08:00
switch state {
2014-05-07 12:15:43 +08:00
case ST_START :
if unicode . IsDigit ( r ) {
2014-05-21 13:08:25 +08:00
state = ST_DIGIT
2014-05-07 12:15:43 +08:00
} else if unicode . IsLetter ( r ) {
2014-05-21 13:08:25 +08:00
state = ST_ALPHA
2014-04-21 10:56:17 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGIT : // 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 ) {
state = ST_DIGITALPHA
continue
2014-04-21 10:56:17 +08:00
}
2014-05-07 12:15:43 +08:00
switch r {
case ',' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITCOMMA
2014-05-07 12:15:43 +08:00
case '-' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITDASH
2014-05-07 12:15:43 +08:00
case ':' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITCOLON
2014-05-07 12:15:43 +08:00
case '/' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITSLASH
2014-07-11 06:25:23 +08:00
firstSlash = i
2014-04-25 08:51:56 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITDASH : // starts digit then dash 02-
2014-05-07 12:15:43 +08:00
// 2006-01-02T15:04:05Z07:00
// 2006-01-02T15:04:05.999999999Z07:00
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
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
switch {
case r == ' ' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITDASHWS
2014-05-07 12:15:43 +08:00
case r == 'T' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITDASHT
2014-04-25 08:51:56 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITDASHWS : // starts digit then dash 02- then whitespace
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-12 09:08:56 +08:00
// 2012-08-03 18:31:59.257000000
2014-05-07 12:15:43 +08:00
// 2016-03-14 00:00:00.000
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
2014-05-07 12:15:43 +08:00
// 2014-04-26 05:24:37 PM
2014-12-03 06:57:00 +08:00
// 2014-12-16 06:20:00 UTC
2015-04-17 02:37:50 +08:00
// 2015-02-18 00:12:00 +0000 UTC
2015-06-26 08:24:55 +08:00
// 2015-06-25 01:25:37.115208593 +0000 UTC
2014-05-07 12:15:43 +08:00
switch r {
case 'A' , 'P' :
if len ( datestr ) == len ( "2014-04-26 03:24:37 PM" ) {
if t , err := time . Parse ( "2006-01-02 03:04:05 PM" , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 12:15:43 +08:00
}
2014-05-07 03:32:49 +08:00
}
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?
if t , err := time . Parse ( "2006-01-02 03:04:05" , datestr [ : i ] ) ; err == nil {
ms , err := strconv . Atoi ( datestr [ i + 1 : ] )
if err == nil {
return time . Unix ( 0 , t . UnixNano ( ) + int64 ( ms ) * 1e6 ) , nil
}
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-11 23:28:23 +08:00
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-11 23:28:23 +08:00
}
}
2014-12-03 06:57:00 +08:00
default :
if unicode . IsLetter ( r ) {
// 2014-12-16 06:20:00 UTC
state = ST_DIGITDASHWSALPHA
break iterRunes
}
2014-05-07 12:15:43 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITDASHT : // starts digit then dash 02- then T
2014-05-07 12:15:43 +08:00
// 2006-01-02T15:04:05Z07:00
2015-06-26 05:09:39 +08:00
// 2006-01-02T15:04:05
2014-05-07 12:15:43 +08:00
// 2006-01-02T15:04:05.999999999Z07:00
2014-10-03 05:39:24 +08:00
// 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
2014-05-07 12:15:43 +08:00
if len ( datestr ) == len ( "2006-01-02T15:04:05Z07:00" ) {
if t , err := time . Parse ( "2006-01-02T15:04:05Z07:00" , datestr ) ; err == nil {
2014-05-07 09:14:58 +08:00
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 09:14:58 +08:00
}
2014-05-07 12:15:43 +08:00
} else if len ( datestr ) == len ( "2006-01-02T15:04:05.999999999Z07:00" ) {
if t , err := time . Parse ( "2006-01-02T15:04:05.999999999Z07:00" , datestr ) ; err == nil {
2014-05-07 03:32:49 +08:00
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 03:32:49 +08:00
}
2015-06-26 05:09:39 +08:00
} else if len ( datestr ) == len ( "2006-01-02T15:04:05" ) {
if t , err := time . Parse ( "2006-01-02T15:04:05" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-10-03 05:39:24 +08:00
} else {
// updated to include timestamps of different precisions
if t , err := time . Parse ( "2006-01-02T15:04:05.999999999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.99999999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.9999999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.999999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.99999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.9999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.999Z" , datestr ) ; err == nil {
return t , nil
} else if t , err := time . Parse ( "2006-01-02T15:04:05.99Z" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-05-07 03:32:49 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITSLASH : // 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 ' ' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITSLASHWS
2014-05-07 12:15:43 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITSLASHWS : // 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
switch r {
case ':' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITSLASHWSCOLON
2014-05-07 12:15:43 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITSLASHWSCOLON : // 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
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 ':' :
2014-05-21 13:08:25 +08:00
state = ST_DIGITSLASHWSCOLONCOLON
2017-02-14 08:49:48 +08:00
case 'A' :
state = ST_DIGITSLASHWSCOLONAM
case 'P' :
state = ST_DIGITSLASHWSCOLONPM
2014-05-07 12:15:43 +08:00
}
2015-10-01 03:09:08 +08:00
case ST_DIGITSLASHWSCOLONCOLON : // starts digit then slash 02/ more digits/slashes then whitespace
// 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
// 3/1/2012 10:11:59 AM
switch r {
2017-02-14 08:49:48 +08:00
case 'A' :
state = ST_DIGITSLASHWSCOLONCOLONAM
case 'P' :
state = ST_DIGITSLASHWSCOLONCOLONPM
2015-10-01 03:09:08 +08:00
}
2017-02-06 02:04:03 +08:00
case ST_DIGITALPHA :
// 12 Feb 2006, 19:17
// 12 Feb 2006, 19:17:22
switch {
case len ( datestr ) == len ( "02 Jan 2006, 15:04" ) :
if t , err := time . Parse ( "02 Jan 2006, 15:04" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
case len ( datestr ) == len ( "02 Jan 2006, 15:04:05" ) :
if t , err := time . Parse ( "02 Jan 2006, 15:04:05" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
default :
//u.LogThrottle(u.WARN, 5, "ST_ALPHAWSALPHA case not found: %v", datestr)
}
2014-05-21 13:08:25 +08:00
case ST_ALPHA : // starts alpha
// May 8, 2009 5:57:51 PM
// Mon Jan _2 15:04:05 2006
// Mon Jan _2 15:04:05 MST 2006
// Mon Jan 02 15:04:05 -0700 2006
// Monday, 02-Jan-06 15:04:05 MST
2016-05-04 04:55:11 +08:00
// Monday, 02 Jan 2006 15:04:05 -0700
2014-05-21 13:08:25 +08:00
// Mon, 02 Jan 2006 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 -0700
2015-08-11 01:54:01 +08:00
// Mon Aug 10 15:44:11 UTC+0100 2015
2015-07-04 01:27:48 +08:00
// Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)
2014-05-07 12:15:43 +08:00
if unicode . IsLetter ( r ) {
continue
}
switch {
case r == ' ' :
2014-05-21 13:08:25 +08:00
state = ST_ALPHAWS
2014-05-21 13:53:52 +08:00
case r == ',' :
2016-05-04 04:55:11 +08:00
switch {
case weekdays [ datestr [ : i ] ] == true :
state = ST_WEEKDAYCOMMA
case weekdayAbbrev [ datestr [ : i ] ] == true :
state = ST_WEEKDAYABBREVCOMMA
default :
state = ST_MONTHCOMMA
}
}
case ST_WEEKDAYCOMMA : // Starts alpha then comma
// Monday, 02-Jan-06 15:04:05 MST
// Monday, 02 Jan 2006 15:04:05 -0700
switch {
case r == '-' :
if i < 15 {
t , err := time . Parse ( "Monday, 02-Jan-06 15:04:05 MST" , datestr )
if err == nil {
return t , nil
}
return time . Time { } , err
} else {
t , err := time . Parse ( "Monday, 02 Jan 2006 15:04:05 -0700" , datestr )
if err == nil {
return t , nil
}
return time . Time { } , err
}
}
case ST_WEEKDAYABBREVCOMMA : // Starts alpha then comma
// Mon, 02-Jan-06 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 -0700
switch {
case r == '-' :
if i < 15 {
t , err := time . Parse ( "Mon, 02-Jan-06 15:04:05 MST" , datestr )
if err == nil {
return t , nil
}
return time . Time { } , err
} else {
t , err := time . Parse ( "Mon, 02 Jan 2006 15:04:05 -0700" , datestr )
if err == nil {
return t , nil
}
return time . Time { } , err
}
2014-05-07 12:15:43 +08:00
}
2016-05-04 04:55:11 +08:00
2014-05-21 13:08:25 +08:00
case ST_ALPHAWS : // Starts alpha then whitespace
2015-07-04 01:27:48 +08:00
// May 8, 2009 5:57:51 PM
// 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 {
2014-05-21 13:08:25 +08:00
// case r == ' ':
// state = ST_ALPHAWSWS
2014-05-07 12:15:43 +08:00
case r == ',' :
2014-05-21 13:08:25 +08:00
state = ST_ALPHAWSCOMMA
2014-05-07 12:15:43 +08:00
case unicode . IsLetter ( r ) :
2014-05-21 13:53:52 +08:00
state = ST_ALPHAWSALPHA
}
case ST_ALPHACOMMA : // Starts alpha then comma
// Mon, 02 Jan 2006 15:04:05 MST
// Mon, 02 Jan 2006 15:04:05 -0700
switch {
case r == '-' :
2014-06-16 02:18:20 +08:00
state = ST_ALPHACOMMADASH
}
case ST_ALPHACOMMADASH : // Starts alpha then comma and one dash
// Mon, 02 Jan 2006 15:04:05 -0700
switch {
case r == '-' :
state = ST_ALPHACOMMADASHDASH
2014-05-07 12:15:43 +08:00
}
2016-05-04 04:02:30 +08:00
2014-05-21 13:08:25 +08:00
case ST_ALPHAWSCOMMA : // Starts Alpha, whitespace, digit, comma
2014-05-07 12:15:43 +08:00
// May 8, 2009 5:57:51 PM
2016-05-04 04:55:11 +08:00
t , err := time . Parse ( "Jan 2, 2006 3:04:05 PM" , datestr )
if err == nil {
2014-04-21 10:56:17 +08:00
return t , nil
}
2016-05-04 04:55:11 +08:00
return time . Time { } , err
2014-05-21 13:53:52 +08:00
case ST_ALPHAWSALPHA : // Starts Alpha, whitespace, alpha
2015-07-04 01:27:48 +08:00
// Fri Jul 03 2015 18:04:07 GMT+0100 (GMT Daylight Time)
// Mon Jan _2 15:04:05 2006
// Mon Jan _2 15:04:05 MST 2006
// Mon Jan 02 15:04:05 -0700 2006
2015-08-11 01:54:01 +08:00
// Mon Aug 10 15:44:11 UTC+0100 2015
2015-07-04 01:27:48 +08:00
switch {
case len ( datestr ) == len ( "Mon Jan _2 15:04:05 2006" ) :
2014-05-21 13:53:52 +08:00
if t , err := time . Parse ( time . ANSIC , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-21 13:53:52 +08:00
}
2015-07-04 01:27:48 +08:00
case len ( datestr ) == len ( "Mon Jan _2 15:04:05 MST 2006" ) :
2014-05-21 13:53:52 +08:00
if t , err := time . Parse ( time . UnixDate , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-21 13:53:52 +08:00
}
2015-07-04 01:27:48 +08:00
case len ( datestr ) == len ( "Mon Jan 02 15:04:05 -0700 2006" ) :
2014-05-21 13:53:52 +08:00
if t , err := time . Parse ( time . RubyDate , datestr ) ; err == nil {
return t , nil
} else {
2015-08-11 01:54:01 +08:00
return time . Time { } , err
}
case len ( datestr ) == len ( "Mon Aug 10 15:44:11 UTC+0100 2015" ) :
if t , err := time . Parse ( "Mon Jan 02 15:04:05 MST-0700 2006" , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-21 13:53:52 +08:00
}
2015-07-04 01:27:48 +08:00
case 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 ]
if t , err := time . Parse ( "Mon Jan 02 2006 15:04:05 MST-0700" , dateTmp ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2015-08-11 01:54:01 +08:00
default :
2016-03-14 08:58:21 +08:00
//u.LogThrottle(u.WARN, 5, "ST_ALPHAWSALPHA case not found: %v", datestr)
2014-05-21 13:53:52 +08:00
}
2014-05-07 12:15:43 +08:00
default :
//u.Infof("no case for: %d", state)
break iterRunes
2014-04-21 10:56:17 +08:00
}
2014-05-07 12:15:43 +08:00
}
switch state {
2014-05-21 13:08:25 +08:00
case ST_DIGIT :
2014-05-07 12:15:43 +08:00
// unixy timestamps ish
2015-08-19 06:50:04 +08:00
// 13980450781991351 nanoseconds
// 13980450781991 microseconds
// 1384216367189
// 1332151919 seconds
// 20140601 yyyymmdd
2016-03-02 05:25:00 +08:00
// 2014 yyyy
2014-04-26 07:59:10 +08:00
if len ( datestr ) >= len ( "13980450781991351" ) {
if nanoSecs , err := strconv . ParseInt ( datestr , 10 , 64 ) ; err == nil {
return time . Unix ( 0 , nanoSecs ) , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-04-26 07:59:10 +08:00
}
2014-05-07 12:15:43 +08:00
} else if len ( datestr ) >= len ( "13980450781991" ) {
if microSecs , err := strconv . ParseInt ( datestr , 10 , 64 ) ; err == nil {
return time . Unix ( 0 , microSecs * 1000 ) , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 12:15:43 +08:00
}
2014-10-08 09:30:17 +08:00
} else if len ( datestr ) >= len ( "1384216367189" ) {
if miliSecs , err := strconv . ParseInt ( datestr , 10 , 64 ) ; err == nil {
return time . Unix ( 0 , miliSecs * 1000 * 1000 ) , nil
} else {
return time . Time { } , err
}
2015-08-19 06:50:04 +08:00
} else if len ( datestr ) == len ( "20140601" ) {
if t , err := time . Parse ( "20060102" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2016-03-02 05:25:00 +08:00
} else if len ( datestr ) == len ( "2014" ) {
if t , err := time . Parse ( "2006" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-04-26 07:59:10 +08:00
} else {
if secs , err := strconv . ParseInt ( datestr , 10 , 64 ) ; err == nil {
return time . Unix ( secs , 0 ) , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-04-26 07:59:10 +08:00
}
}
2014-05-21 13:08:25 +08:00
case ST_DIGITDASH : // 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" ) {
if t , err := time . Parse ( "2006-01-02" , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 12:15:43 +08:00
}
2016-03-02 05:25:00 +08:00
} else if len ( datestr ) == len ( "2014-04" ) {
if t , err := time . Parse ( "2006-01" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-05-07 12:15:43 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITDASHWS : // starts digit then dash 02- then whitespace 1 << 2 << 5 + 3
2014-05-12 09:08:56 +08:00
// 2012-08-03 18:31:59.257000000
2017-01-31 09:18:48 +08:00
// 2014-04-26 17:24:37.3186369
// 2017-01-27 00:07:31.945167
2014-05-07 12:15:43 +08:00
// 2016-03-14 00:00:00.000
2014-05-12 09:22:16 +08:00
// 2013-04-01 22:43:22
2014-05-12 09:08:56 +08:00
if len ( datestr ) == len ( "2012-08-03 18:31:59.257000000" ) {
if t , err := time . Parse ( "2006-01-02 15:04:05.000000000" , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-12 09:08:56 +08:00
}
} else if len ( datestr ) == len ( "2014-04-26 05:24:37.3186369" ) {
2014-05-07 12:15:43 +08:00
if t , err := time . Parse ( "2006-01-02 15:04:05.0000000" , datestr ) ; err == nil {
return t , nil
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 12:15:43 +08:00
}
2017-01-31 09:18:48 +08:00
} else if len ( datestr ) == len ( "2014-04-26 05:24:37.945167" ) {
if t , err := time . Parse ( "2006-01-02 15:04:05.000000" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-05-07 12:15:43 +08:00
} else if len ( datestr ) == len ( "2014-04-26 05:24:37.000" ) {
if t , err := time . Parse ( "2006-01-02 15:04:05.000" , datestr ) ; err == nil {
return t , nil
2014-05-12 09:22:16 +08:00
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-12 09:22:16 +08:00
}
} else if len ( datestr ) == len ( "2013-04-01 22:43:22" ) {
if t , err := time . Parse ( "2006-01-02 15:04:05" , datestr ) ; err == nil {
return t , nil
2014-05-07 12:15:43 +08:00
} else {
2014-06-16 03:16:39 +08:00
return time . Time { } , err
2014-05-07 12:15:43 +08:00
}
}
2014-12-03 06:57:00 +08:00
case ST_DIGITDASHWSALPHA : // starts digit then dash 02- then whitespace 1 << 2 << 5 + 3
// 2014-12-16 06:20:00 UTC
2015-06-26 08:24:55 +08:00
// 2015-02-18 00:12:00 +0000 UTC
// 2015-06-25 01:25:37.115208593 +0000 UTC
switch len ( datestr ) {
case len ( "2006-01-02 15:04:05 UTC" ) :
2014-12-03 06:57:00 +08:00
if t , err := time . Parse ( "2006-01-02 15:04:05 UTC" , datestr ) ; err == nil {
return t , nil
} else {
2016-09-13 22:40:04 +08:00
if t , err := time . Parse ( "2006-01-02 15:04:05 GMT" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-12-03 06:57:00 +08:00
}
2015-06-26 08:24:55 +08:00
case len ( "2015-02-18 00:12:00 +0000 UTC" ) :
2015-04-17 02:37:50 +08:00
if t , err := time . Parse ( "2006-01-02 15:04:05 +0000 UTC" , datestr ) ; err == nil {
return t , nil
} else {
2016-09-13 22:40:04 +08:00
if t , err = time . Parse ( "2006-01-02 15:04:05 +0000 GMT" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2015-04-17 02:37:50 +08:00
}
2015-10-01 03:09:08 +08:00
case len ( "2015-09-30 18:48:56.35272715 +0000 UTC" ) :
if t , err := time . Parse ( "2006-01-02 15:04:05.00000000 +0000 UTC" , datestr ) ; err == nil {
return t , nil
} else {
2016-09-13 22:40:04 +08:00
if t , err := time . Parse ( "2006-01-02 15:04:05.00000000 +0000 GMT" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2015-10-01 03:09:08 +08:00
}
2015-06-26 08:24:55 +08:00
case len ( "2015-06-25 01:25:37.115208593 +0000 UTC" ) :
if t , err := time . Parse ( "2006-01-02 15:04:05.000000000 +0000 UTC" , datestr ) ; err == nil {
return t , nil
} else {
2016-09-13 22:40:04 +08:00
if t , err := time . Parse ( "2006-01-02 15:04:05.000000000 +0000 GMT" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2015-06-26 08:24:55 +08:00
}
2014-12-03 06:57:00 +08:00
}
2014-05-21 13:08:25 +08:00
case ST_DIGITSLASH : // 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" ) {
if t , err := time . Parse ( "2006/01/02" , datestr ) ; err == nil {
return t , nil
} else {
u . Errorf ( "hm: %v %s" , err , datestr )
return time . Time { } , err
}
2014-05-07 12:15:43 +08:00
} else {
2014-07-11 06:25:23 +08:00
if t , err := time . Parse ( "2006/1/2" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-05-07 12:15:43 +08:00
}
} else {
2014-12-16 03:20:40 +08:00
for _ , parseFormat := range shortDates {
if t , err := time . Parse ( parseFormat , datestr ) ; err == nil {
2014-07-11 06:25:23 +08:00
return t , nil
}
2014-05-07 12:15:43 +08:00
}
2014-12-16 03:20:40 +08:00
return time . Time { } , fmt . Errorf ( "Unrecognized dateformat: %v" , datestr )
2014-05-07 12:15:43 +08:00
}
2017-02-14 08:49:48 +08:00
case ST_DIGITSLASHWSCOLON , ST_DIGITSLASHWSCOLONAM , ST_DIGITSLASHWSCOLONPM : // 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/04/08 08:05 PM
var t time . Time
var err error
var add time . Duration
if state == ST_DIGITSLASHWSCOLONAM {
datestr = strings . Replace ( datestr , " AM" , "" , - 1 )
} else if state == ST_DIGITSLASHWSCOLONPM {
datestr = strings . Replace ( datestr , " PM" , "" , - 1 )
add = time . Duration ( 12 * time . Hour )
}
2014-07-11 06:25:23 +08:00
if firstSlash == 4 {
2017-02-14 08:49:48 +08:00
switch len ( datestr ) {
case len ( "2006/01/02 15:04" ) :
t , err = time . Parse ( "2006/01/02 15:04" , datestr )
case len ( "2006/01/2 15:04" ) :
if t , err = time . Parse ( "2006/01/2 15:04" , datestr ) ; err != nil {
t , err = time . Parse ( "2006/1/02 15:04" , datestr )
2014-05-12 04:33:13 +08:00
}
2017-02-14 08:49:48 +08:00
default :
t , err = time . Parse ( "2006/1/2 15:04" , datestr )
2014-05-12 04:33:13 +08:00
}
2014-05-07 12:15:43 +08:00
} else {
2017-02-14 08:49:48 +08:00
switch len ( datestr ) {
case len ( "01/02/2006 15:04" ) :
t , err = time . Parse ( "01/02/2006 15:04" , datestr )
case len ( "01/2/2006 15:04" ) :
if t , err = time . Parse ( "01/2/2006 15:04" , datestr ) ; err != nil {
t , err = time . Parse ( "1/02/2006 15:04" , datestr )
2014-07-11 06:25:23 +08:00
}
2017-02-14 08:49:48 +08:00
default :
t , err = time . Parse ( "1/2/2006 15:04" , datestr )
2014-05-07 12:15:43 +08:00
}
}
2017-02-14 08:49:48 +08:00
if err == nil {
return t . Add ( add ) , nil
}
return time . Time { } , err
case ST_DIGITSLASHWSCOLONCOLON , ST_DIGITSLASHWSCOLONCOLONAM , ST_DIGITSLASHWSCOLONCOLONPM : // 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-02-14 08:49:48 +08:00
// 3/01/2012 10:11:59 PM
var t time . Time
var err error
var add time . Duration
if state == ST_DIGITSLASHWSCOLONCOLONAM {
2015-10-01 03:09:08 +08:00
datestr = strings . Replace ( datestr , " AM" , "" , - 1 )
2017-02-14 08:49:48 +08:00
} else if state == ST_DIGITSLASHWSCOLONCOLONPM {
2015-10-01 03:09:08 +08:00
datestr = strings . Replace ( datestr , " PM" , "" , - 1 )
2017-02-14 08:49:48 +08:00
add = time . Duration ( 12 * time . Hour )
2015-10-01 03:09:08 +08:00
}
2017-02-14 08:49:48 +08:00
2014-07-11 06:25:23 +08:00
if firstSlash == 4 {
2017-02-14 08:49:48 +08:00
switch len ( datestr ) {
case len ( "2014/07/10 06:55:38.156283" ) :
t , err = time . Parse ( "2006/01/02 15:04:05.000000" , datestr )
case len ( "2006/01/02 15:04:05" ) :
t , err = time . Parse ( "2006/01/02 15:04:05" , datestr )
case len ( "2006/01/2 15:04:05" ) :
if t , err = time . Parse ( "2006/01/2 15:04:05" , datestr ) ; err != nil {
t , err = time . Parse ( "2006/1/02 15:04:05" , datestr )
2014-05-12 04:33:13 +08:00
}
2017-02-14 08:49:48 +08:00
default :
t , err = time . Parse ( "2006/1/2 15:04:05" , datestr )
2014-05-12 04:33:13 +08:00
}
2014-05-07 12:15:43 +08:00
} else {
2017-02-14 08:49:48 +08:00
switch len ( datestr ) {
case len ( "07/10/2014 06:55:38.156283" ) :
t , err = time . Parse ( "01/02/2006 15:04:05.000000" , datestr )
case len ( "01/02/2006 15:04:05" ) :
t , err = time . Parse ( "01/02/2006 15:04:05" , datestr )
case len ( "01/2/2006 15:04:05" ) :
if t , err = time . Parse ( "01/2/2006 15:04:05" , datestr ) ; err != nil {
t , err = time . Parse ( "1/02/2006 15:04:05" , datestr )
2014-07-11 06:25:23 +08:00
}
2017-02-14 08:49:48 +08:00
default :
t , err = time . Parse ( "1/2/2006 15:04:05" , datestr )
2014-05-07 12:15:43 +08:00
}
}
2017-02-14 08:49:48 +08:00
if err == nil {
return t . Add ( add ) , nil
}
return time . Time { } , err
2016-05-04 04:55:11 +08:00
case ST_WEEKDAYABBREVCOMMA : // Starts alpha then comma
// Mon, 02 Jan 2006 15:04:05 MST
t , err := time . Parse ( "Mon, 02 Jan 2006 15:04:05 MST" , datestr )
if err == nil {
return t , nil
}
return time . Time { } , err
2015-10-01 03:09:08 +08:00
2014-06-16 02:18:20 +08:00
case ST_ALPHACOMMA : // Starts alpha then comma but no DASH
// Mon, 02 Jan 2006 15:04:05 MST
2016-05-04 04:55:11 +08:00
// Jan 2, 2006 3:04:05 PM
2014-06-16 02:18:20 +08:00
if t , err := time . Parse ( "Jan 2, 2006 3:04:05 PM" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
case ST_ALPHACOMMADASH : // Starts alpha then comma and one dash
// Mon, 02 Jan 2006 15:04:05 -0700
2014-05-21 13:53:52 +08:00
2014-06-16 02:18:20 +08:00
//RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
// TODO: this doesn't work???
if t , err := time . Parse ( time . RFC1123Z , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
case ST_ALPHACOMMADASHDASH : // Starts alpha then comma and two dash'es
// Monday, 02-Jan-06 15:04:05 MST
if t , err := time . Parse ( "Monday, 02-Jan-06 15:04:05 MST" , datestr ) ; err == nil {
return t , nil
} else {
return time . Time { } , err
}
2014-04-21 10:56:17 +08:00
default :
2014-06-16 02:18:20 +08:00
//u.Infof("no case for: %d : %s", state, datestr)
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
}