1
2
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18
19 package fs
20
21 import (
22 "errors"
23 "fmt"
24 "math"
25 "strconv"
26 "time"
27 )
28
29 var timeFormats = []string{
30 time.RFC3339Nano,
31 time.RFC3339,
32 time.RFC1123Z,
33 time.RFC1123,
34 time.UnixDate,
35 time.ANSIC,
36 time.RubyDate,
37 "2006-01-02T15:04",
38 "2006-01-02T15",
39 "2006-01-02",
40 "2006-01",
41 "2006",
42 }
43
44 var errUnparseableTimestamp = errors.New("unparsable timestamp")
45
46 var powTable = []int{
47 10e8,
48 10e7,
49 10e6,
50 10e5,
51 10e4,
52 10e3,
53 10e2,
54 10e1,
55 10,
56 1,
57 }
58
59
60 func parseCanonicalTime(in string) (time.Time, error) {
61 if len(in) < 20 || in[len(in)-1] != 'Z' {
62 return time.Time{}, errUnparseableTimestamp
63 }
64
65 if !(in[4] == '-' && in[7] == '-' && in[10] == 'T' &&
66 in[13] == ':' && in[16] == ':' && (in[19] == '.' || in[19] == 'Z')) {
67 return time.Time{}, fmt.Errorf("positionally incorrect: %v", in)
68 }
69
70
71
72
73
74
75 year, err := strconv.Atoi(in[0:4])
76 if err != nil {
77 return time.Time{}, fmt.Errorf("error parsing year: %v", err)
78 }
79
80 month, err := strconv.Atoi(in[5:7])
81 if err != nil {
82 return time.Time{}, fmt.Errorf("error parsing month: %v", err)
83 }
84
85 day, err := strconv.Atoi(in[8:10])
86 if err != nil {
87 return time.Time{}, fmt.Errorf("error parsing day: %v", err)
88 }
89
90 hour, err := strconv.Atoi(in[11:13])
91 if err != nil {
92 return time.Time{}, fmt.Errorf("error parsing hour: %v", err)
93 }
94
95 minute, err := strconv.Atoi(in[14:16])
96 if err != nil {
97 return time.Time{}, fmt.Errorf("error parsing minute: %v", err)
98 }
99
100 second, err := strconv.Atoi(in[17:19])
101 if err != nil {
102 return time.Time{}, fmt.Errorf("error parsing second: %v", err)
103 }
104
105 var nsecstr string
106 if in[19] != 'Z' {
107 nsecstr = in[20 : len(in)-1]
108 }
109 var nsec int
110
111 if nsecstr != "" {
112 nsec, err = strconv.Atoi(nsecstr)
113 if err != nil {
114 return time.Time{}, fmt.Errorf("error parsing nanoseconds: %v", err)
115 }
116 }
117
118 nsec *= powTable[len(nsecstr)]
119
120 return time.Date(year, time.Month(month), day,
121 hour, minute, second, nsec, time.UTC), nil
122 }
123
124 func parseTime(in string) (time.Time, error) {
125
126 n, err := strconv.ParseInt(in, 10, 64)
127 if err == nil {
128 switch {
129 case n > int64(math.MaxInt32)*1000:
130
131 return time.Unix(n/1e9, n%1e9), nil
132 case n > int64(math.MaxInt32):
133
134 return time.Unix(n/1000, (n%1000)*1e6), nil
135 case n > 10000:
136
137 return time.Unix(n, 0), nil
138 }
139 }
140 rv, err := parseCanonicalTime(in)
141 if err == nil {
142 return rv, nil
143 }
144 for _, f := range timeFormats {
145 parsed, err := time.Parse(f, in)
146 if err == nil {
147 return parsed, nil
148 }
149 }
150 return time.Time{}, errUnparseableTimestamp
151 }