...
1 package time
2
3 import (
4 "context"
5 "fmt"
6 "math/big"
7 "strings"
8 "time"
9 )
10
11 const (
12
13 dateTimeFormatInput = "2006-01-02T15:04:05.999999999Z"
14 dateTimeFormatInputNoZ = "2006-01-02T15:04:05.999999999"
15 dateTimeFormatOutput = "2006-01-02T15:04:05.999Z"
16
17
18
19 httpDateFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
20
21 httpDateFormatSingleDigitDay = "Mon, _2 Jan 2006 15:04:05 GMT"
22 httpDateFormatSingleDigitDayTwoDigitYear = "Mon, _2 Jan 06 15:04:05 GMT"
23 )
24
25 var millisecondFloat = big.NewFloat(1e3)
26
27
28
29
30 func FormatDateTime(value time.Time) string {
31 return value.UTC().Format(dateTimeFormatOutput)
32 }
33
34
35
36
37 func ParseDateTime(value string) (time.Time, error) {
38 return tryParse(value,
39 dateTimeFormatInput,
40 dateTimeFormatInputNoZ,
41 time.RFC3339Nano,
42 time.RFC3339,
43 )
44 }
45
46
47
48
49 func FormatHTTPDate(value time.Time) string {
50 return value.UTC().Format(httpDateFormat)
51 }
52
53
54
55
56 func ParseHTTPDate(value string) (time.Time, error) {
57 return tryParse(value,
58 httpDateFormat,
59 httpDateFormatSingleDigitDay,
60 httpDateFormatSingleDigitDayTwoDigitYear,
61 time.RFC850,
62 time.ANSIC,
63 )
64 }
65
66
67
68
69 func FormatEpochSeconds(value time.Time) float64 {
70 ms := value.UnixNano() / int64(time.Millisecond)
71 return float64(ms) / 1e3
72 }
73
74
75
76
77 func ParseEpochSeconds(value float64) time.Time {
78 f := big.NewFloat(value)
79 f = f.Mul(f, millisecondFloat)
80 i, _ := f.Int64()
81
82
83 return time.Unix(0, i*1e6).UTC()
84 }
85
86 func tryParse(v string, formats ...string) (time.Time, error) {
87 var errs parseErrors
88 for _, f := range formats {
89 t, err := time.Parse(f, v)
90 if err != nil {
91 errs = append(errs, parseError{
92 Format: f,
93 Err: err,
94 })
95 continue
96 }
97 return t, nil
98 }
99
100 return time.Time{}, fmt.Errorf("unable to parse time string, %w", errs)
101 }
102
103 type parseErrors []parseError
104
105 func (es parseErrors) Error() string {
106 var s strings.Builder
107 for _, e := range es {
108 fmt.Fprintf(&s, "\n * %q: %v", e.Format, e.Err)
109 }
110
111 return "parse errors:" + s.String()
112 }
113
114 type parseError struct {
115 Format string
116 Err error
117 }
118
119
120
121
122 func SleepWithContext(ctx context.Context, dur time.Duration) error {
123 t := time.NewTimer(dur)
124 defer t.Stop()
125
126 select {
127 case <-t.C:
128 break
129 case <-ctx.Done():
130 return ctx.Err()
131 }
132
133 return nil
134 }
135
View as plain text