time.go 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. package models
  2. // Helper time methods since parsing time can easily overflow and we only support a
  3. // specific time range.
  4. import (
  5. "fmt"
  6. "math"
  7. "time"
  8. )
  9. const (
  10. // MinNanoTime is the minumum time that can be represented.
  11. //
  12. // 1677-09-21 00:12:43.145224194 +0000 UTC
  13. //
  14. // The two lowest minimum integers are used as sentinel values. The
  15. // minimum value needs to be used as a value lower than any other value for
  16. // comparisons and another separate value is needed to act as a sentinel
  17. // default value that is unusable by the user, but usable internally.
  18. // Because these two values need to be used for a special purpose, we do
  19. // not allow users to write points at these two times.
  20. MinNanoTime = int64(math.MinInt64) + 2
  21. // MaxNanoTime is the maximum time that can be represented.
  22. //
  23. // 2262-04-11 23:47:16.854775806 +0000 UTC
  24. //
  25. // The highest time represented by a nanosecond needs to be used for an
  26. // exclusive range in the shard group, so the maximum time needs to be one
  27. // less than the possible maximum number of nanoseconds representable by an
  28. // int64 so that we don't lose a point at that one time.
  29. MaxNanoTime = int64(math.MaxInt64) - 1
  30. )
  31. var (
  32. minNanoTime = time.Unix(0, MinNanoTime).UTC()
  33. maxNanoTime = time.Unix(0, MaxNanoTime).UTC()
  34. // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch.
  35. ErrTimeOutOfRange = fmt.Errorf("time outside range %d - %d", MinNanoTime, MaxNanoTime)
  36. )
  37. // SafeCalcTime safely calculates the time given. Will return error if the time is outside the
  38. // supported range.
  39. func SafeCalcTime(timestamp int64, precision string) (time.Time, error) {
  40. mult := GetPrecisionMultiplier(precision)
  41. if t, ok := safeSignedMult(timestamp, mult); ok {
  42. tme := time.Unix(0, t).UTC()
  43. return tme, CheckTime(tme)
  44. }
  45. return time.Time{}, ErrTimeOutOfRange
  46. }
  47. // CheckTime checks that a time is within the safe range.
  48. func CheckTime(t time.Time) error {
  49. if t.Before(minNanoTime) || t.After(maxNanoTime) {
  50. return ErrTimeOutOfRange
  51. }
  52. return nil
  53. }
  54. // Perform the multiplication and check to make sure it didn't overflow.
  55. func safeSignedMult(a, b int64) (int64, bool) {
  56. if a == 0 || b == 0 || a == 1 || b == 1 {
  57. return a * b, true
  58. }
  59. if a == MinNanoTime || b == MaxNanoTime {
  60. return 0, false
  61. }
  62. c := a * b
  63. return c, c/b == a
  64. }