github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/influxdb/models/time.go (about)

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