time.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. package time
  2. import (
  3. "context"
  4. "fmt"
  5. "math/big"
  6. "strings"
  7. "time"
  8. )
  9. const (
  10. // dateTimeFormat is a IMF-fixdate formatted RFC3339 section 5.6
  11. dateTimeFormatInput = "2006-01-02T15:04:05.999999999Z"
  12. dateTimeFormatInputNoZ = "2006-01-02T15:04:05.999999999"
  13. dateTimeFormatOutput = "2006-01-02T15:04:05.999Z"
  14. // httpDateFormat is a date time defined by RFC 7231#section-7.1.1.1
  15. // IMF-fixdate with no UTC offset.
  16. httpDateFormat = "Mon, 02 Jan 2006 15:04:05 GMT"
  17. // Additional formats needed for compatibility.
  18. httpDateFormatSingleDigitDay = "Mon, _2 Jan 2006 15:04:05 GMT"
  19. httpDateFormatSingleDigitDayTwoDigitYear = "Mon, _2 Jan 06 15:04:05 GMT"
  20. )
  21. var millisecondFloat = big.NewFloat(1e3)
  22. // FormatDateTime formats value as a date-time, (RFC3339 section 5.6)
  23. //
  24. // Example: 1985-04-12T23:20:50.52Z
  25. func FormatDateTime(value time.Time) string {
  26. return value.UTC().Format(dateTimeFormatOutput)
  27. }
  28. // ParseDateTime parses a string as a date-time, (RFC3339 section 5.6)
  29. //
  30. // Example: 1985-04-12T23:20:50.52Z
  31. func ParseDateTime(value string) (time.Time, error) {
  32. return tryParse(value,
  33. dateTimeFormatInput,
  34. dateTimeFormatInputNoZ,
  35. time.RFC3339Nano,
  36. time.RFC3339,
  37. )
  38. }
  39. // FormatHTTPDate formats value as a http-date, (RFC 7231#section-7.1.1.1 IMF-fixdate)
  40. //
  41. // Example: Tue, 29 Apr 2014 18:30:38 GMT
  42. func FormatHTTPDate(value time.Time) string {
  43. return value.UTC().Format(httpDateFormat)
  44. }
  45. // ParseHTTPDate parses a string as a http-date, (RFC 7231#section-7.1.1.1 IMF-fixdate)
  46. //
  47. // Example: Tue, 29 Apr 2014 18:30:38 GMT
  48. func ParseHTTPDate(value string) (time.Time, error) {
  49. return tryParse(value,
  50. httpDateFormat,
  51. httpDateFormatSingleDigitDay,
  52. httpDateFormatSingleDigitDayTwoDigitYear,
  53. time.RFC850,
  54. time.ANSIC,
  55. )
  56. }
  57. // FormatEpochSeconds returns value as a Unix time in seconds with with decimal precision
  58. //
  59. // Example: 1515531081.123
  60. func FormatEpochSeconds(value time.Time) float64 {
  61. ms := value.UnixNano() / int64(time.Millisecond)
  62. return float64(ms) / 1e3
  63. }
  64. // ParseEpochSeconds returns value as a Unix time in seconds with with decimal precision
  65. //
  66. // Example: 1515531081.123
  67. func ParseEpochSeconds(value float64) time.Time {
  68. f := big.NewFloat(value)
  69. f = f.Mul(f, millisecondFloat)
  70. i, _ := f.Int64()
  71. // Offset to `UTC` because time.Unix returns the time value based on system
  72. // local setting.
  73. return time.Unix(0, i*1e6).UTC()
  74. }
  75. func tryParse(v string, formats ...string) (time.Time, error) {
  76. var errs parseErrors
  77. for _, f := range formats {
  78. t, err := time.Parse(f, v)
  79. if err != nil {
  80. errs = append(errs, parseError{
  81. Format: f,
  82. Err: err,
  83. })
  84. continue
  85. }
  86. return t, nil
  87. }
  88. return time.Time{}, fmt.Errorf("unable to parse time string, %w", errs)
  89. }
  90. type parseErrors []parseError
  91. func (es parseErrors) Error() string {
  92. var s strings.Builder
  93. for _, e := range es {
  94. fmt.Fprintf(&s, "\n * %q: %v", e.Format, e.Err)
  95. }
  96. return "parse errors:" + s.String()
  97. }
  98. type parseError struct {
  99. Format string
  100. Err error
  101. }
  102. // SleepWithContext will wait for the timer duration to expire, or until the context
  103. // is canceled. Whichever happens first. If the context is canceled the
  104. // Context's error will be returned.
  105. func SleepWithContext(ctx context.Context, dur time.Duration) error {
  106. t := time.NewTimer(dur)
  107. defer t.Stop()
  108. select {
  109. case <-t.C:
  110. break
  111. case <-ctx.Done():
  112. return ctx.Err()
  113. }
  114. return nil
  115. }