time.go 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  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. var (
  10. // MaxNanoTime is the maximum time that can be represented via int64 nanoseconds since the epoch.
  11. MaxNanoTime = time.Unix(0, math.MaxInt64).UTC()
  12. // MinNanoTime is the minumum time that can be represented via int64 nanoseconds since the epoch.
  13. MinNanoTime = time.Unix(0, math.MinInt64).UTC()
  14. // ErrTimeOutOfRange gets returned when time is out of the representable range using int64 nanoseconds since the epoch.
  15. ErrTimeOutOfRange = fmt.Errorf("time outside range %s - %s", MinNanoTime, MaxNanoTime)
  16. )
  17. // SafeCalcTime safely calculates the time given. Will return error if the time is outside the
  18. // supported range.
  19. func SafeCalcTime(timestamp int64, precision string) (time.Time, error) {
  20. mult := GetPrecisionMultiplier(precision)
  21. if t, ok := safeSignedMult(timestamp, mult); ok {
  22. return time.Unix(0, t).UTC(), nil
  23. }
  24. return time.Time{}, ErrTimeOutOfRange
  25. }
  26. // CheckTime checks that a time is within the safe range.
  27. func CheckTime(t time.Time) error {
  28. if t.Before(MinNanoTime) || t.After(MaxNanoTime) {
  29. return ErrTimeOutOfRange
  30. }
  31. return nil
  32. }
  33. // Perform the multiplication and check to make sure it didn't overflow.
  34. func safeSignedMult(a, b int64) (int64, bool) {
  35. if a == 0 || b == 0 || a == 1 || b == 1 {
  36. return a * b, true
  37. }
  38. if a == math.MinInt64 || b == math.MaxInt64 {
  39. return 0, false
  40. }
  41. c := a * b
  42. return c, c/b == a
  43. }