func (ti *TimeInterval) End() time.Time {
	return ti.end
}
End returns the starting time in UTC.
package utils
import (
	"fmt"
	"math/rand"
	"time"
)
const (
	ErrEndBeforeStart = "end time before start time"
	errWindowTooLargeFmt = "random window equal to or larger than TimeInterval: window %v, interval %v"
)
type TimeInterval struct {
	start time.Time
	end   time.Time
}
func NewTimeInterval(start, end time.Time) (*TimeInterval, error) {
	if end.Before(start) {
		return nil, fmt.Errorf(ErrEndBeforeStart)
	}
	return &TimeInterval{start.UTC(), end.UTC()}, nil
}
func (ti *TimeInterval) Duration() time.Duration {
	return ti.end.Sub(ti.start)
}
func (ti *TimeInterval) Overlap(other *TimeInterval) bool {
	s1 := ti.Start()
	e1 := ti.End()
	s2 := other.Start()
	e2 := other.End()
	if e1 == s2 || e2 == s1 {
		return false
	}
	if s1.Before(s2) && e1.Before(s2) {
		return false
	}
	if s2.Before(s1) && e2.Before(s1) {
		return false
	}
	return true
}
func (ti *TimeInterval) RandWindow(window time.Duration) (*TimeInterval, error) {
	lower := ti.start.UnixNano()
	upper := ti.end.Add(-window).UnixNano()
	if upper <= lower {
		return nil, fmt.Errorf(errWindowTooLargeFmt, window, ti.end.Sub(ti.start))
	}
	start := lower + rand.Int63n(upper-lower)
	end := start + window.Nanoseconds()
	x, err := NewTimeInterval(time.Unix(0, start), time.Unix(0, end))
	if err != nil {
		return nil, err
	} else if x.Duration() != window {
		panic("generated TimeInterval's duration does not equal window")
	}
	return x, nil
}
func (ti *TimeInterval) MustRandWindow(window time.Duration) *TimeInterval {
	res, err := ti.RandWindow(window)
	if err != nil {
		panic(err.Error())
	}
	return res
}
func (ti *TimeInterval) Start() time.Time {
	return ti.start
}
func (ti *TimeInterval) StartUnixNano() int64 {
	return ti.start.UnixNano()
}
func (ti *TimeInterval) StartUnixMillis() int64 {
	return ti.start.UTC().UnixNano() / int64(time.Millisecond)
}
func (ti *TimeInterval) StartString() string {
	return ti.start.Format(time.RFC3339)
}