robocar-tools/vendor/github.com/aws/smithy-go/time/time.go

135 lines
3.3 KiB
Go

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
}