123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- package time
- import (
- "context"
- "fmt"
- "math/big"
- "strings"
- "time"
- )
- const (
- // dateTimeFormat is a IMF-fixdate formatted RFC3339 section 5.6
- dateTimeFormatInput = "2006-01-02T15:04:05.999999999Z"
- dateTimeFormatInputNoZ = "2006-01-02T15:04:05.999999999"
- dateTimeFormatOutput = "2006-01-02T15:04:05.999Z"
- // httpDateFormat is a date time defined by RFC 7231#section-7.1.1.1
- // IMF-fixdate with no UTC offset.
- httpDateFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
- // Additional formats needed for compatibility.
- httpDateFormatSingleDigitDay = "Mon, _2 Jan 2006 15:04:05 GMT"
- httpDateFormatSingleDigitDayTwoDigitYear = "Mon, _2 Jan 06 15:04:05 GMT"
- )
- var millisecondFloat = big.NewFloat(1e3)
- // FormatDateTime formats value as a date-time, (RFC3339 section 5.6)
- //
- // Example: 1985-04-12T23:20:50.52Z
- func FormatDateTime(value time.Time) string {
- return value.UTC().Format(dateTimeFormatOutput)
- }
- // ParseDateTime parses a string as a date-time, (RFC3339 section 5.6)
- //
- // Example: 1985-04-12T23:20:50.52Z
- func ParseDateTime(value string) (time.Time, error) {
- return tryParse(value,
- dateTimeFormatInput,
- dateTimeFormatInputNoZ,
- time.RFC3339Nano,
- time.RFC3339,
- )
- }
- // FormatHTTPDate formats value as a http-date, (RFC 7231#section-7.1.1.1 IMF-fixdate)
- //
- // Example: Tue, 29 Apr 2014 18:30:38 GMT
- func FormatHTTPDate(value time.Time) string {
- return value.UTC().Format(httpDateFormat)
- }
- // ParseHTTPDate parses a string as a http-date, (RFC 7231#section-7.1.1.1 IMF-fixdate)
- //
- // Example: Tue, 29 Apr 2014 18:30:38 GMT
- func ParseHTTPDate(value string) (time.Time, error) {
- return tryParse(value,
- httpDateFormat,
- httpDateFormatSingleDigitDay,
- httpDateFormatSingleDigitDayTwoDigitYear,
- time.RFC850,
- time.ANSIC,
- )
- }
- // FormatEpochSeconds returns value as a Unix time in seconds with with decimal precision
- //
- // Example: 1515531081.123
- func FormatEpochSeconds(value time.Time) float64 {
- ms := value.UnixNano() / int64(time.Millisecond)
- return float64(ms) / 1e3
- }
- // ParseEpochSeconds returns value as a Unix time in seconds with with decimal precision
- //
- // Example: 1515531081.123
- func ParseEpochSeconds(value float64) time.Time {
- f := big.NewFloat(value)
- f = f.Mul(f, millisecondFloat)
- i, _ := f.Int64()
- // Offset to `UTC` because time.Unix returns the time value based on system
- // local setting.
- return time.Unix(0, i*1e6).UTC()
- }
- func tryParse(v string, formats ...string) (time.Time, error) {
- var errs parseErrors
- for _, f := range formats {
- t, err := time.Parse(f, v)
- if err != nil {
- errs = append(errs, parseError{
- Format: f,
- Err: err,
- })
- continue
- }
- return t, nil
- }
- return time.Time{}, fmt.Errorf("unable to parse time string, %w", errs)
- }
- type parseErrors []parseError
- func (es parseErrors) Error() string {
- var s strings.Builder
- for _, e := range es {
- fmt.Fprintf(&s, "\n * %q: %v", e.Format, e.Err)
- }
- return "parse errors:" + s.String()
- }
- type parseError struct {
- Format string
- Err error
- }
- // SleepWithContext will wait for the timer duration to expire, or until the context
- // is canceled. Whichever happens first. If the context is canceled the
- // Context's error will be returned.
- func SleepWithContext(ctx context.Context, dur time.Duration) error {
- t := time.NewTimer(dur)
- defer t.Stop()
- select {
- case <-t.C:
- break
- case <-ctx.Done():
- return ctx.Err()
- }
- return nil
- }
|