package mstime import ( "github.com/pkg/errors" "time" ) const ( nanosecondsInMillisecond = int64(time.Millisecond / time.Nanosecond) millisecondsInSecond = int64(time.Second / time.Millisecond) ) // Time is a wrapper for time.Time that guarantees all of its methods will return a millisecond precisioned times. type Time struct { time time.Time } // UnixMilliseconds returns t as a Unix time, the number of milliseconds elapsed // since January 1, 1970 UTC. func (t Time) UnixMilliseconds() int64 { return t.time.UnixNano() / nanosecondsInMillisecond } // UnixSeconds returns t as a Unix time, the number of seconds elapsed // since January 1, 1970 UTC. func (t Time) UnixSeconds() int64 { return t.time.Unix() } // String returns the time formatted using the format string // "2006-01-02 15:04:05.999999999 -0700 MST" func (t Time) String() string { return t.time.String() } // Clock returns the hour, minute, and second within the day specified by t. func (t Time) Clock() (hour, min, sec int) { return t.time.Clock() } // Millisecond returns the millisecond offset within the second specified by t, // in the range [0, 999]. func (t Time) Millisecond() int { return t.time.Nanosecond() / int(nanosecondsInMillisecond) } // Date returns the year, month, and day in which t occurs. func (t Time) Date() (year int, month time.Month, day int) { return t.time.Date() } // After reports whether the time instant t is after u. func (t Time) After(u Time) bool { return t.time.After(u.time) } // Before reports whether the time instant t is before u. func (t Time) Before(u Time) bool { return t.time.Before(u.time) } // Add returns the time t+d. // It panics if d has a precision greater than one millisecond (the duration has a non zero microseconds part). func (t Time) Add(d time.Duration) Time { validateDurationPrecision(d) return newMSTime(t.time.Add(d)) } // Sub returns the duration t-u. If the result exceeds the maximum (or minimum) // value that can be stored in a Duration, the maximum (or minimum) duration // will be returned. // To compute t-d for a duration d, use t.Add(-d). func (t Time) Sub(u Time) time.Duration { return t.time.Sub(u.time) } // IsZero reports whether t represents the zero time instant, // January 1, year 1, 00:00:00 UTC. func (t Time) IsZero() bool { return t.time.IsZero() } // ToNativeTime converts t to time.Time func (t Time) ToNativeTime() time.Time { return t.time } // Now returns the current local time, with precision of one millisecond. func Now() Time { return ToMSTime(time.Now()) } // UnixMilliseconds returns the local Time corresponding to the given Unix time, // ms milliseconds since January 1, 1970 UTC. func UnixMilliseconds(ms int64) Time { seconds := ms / millisecondsInSecond nanoseconds := (ms - seconds*millisecondsInSecond) * nanosecondsInMillisecond return newMSTime(time.Unix(ms/millisecondsInSecond, nanoseconds)) } // Since returns the time elapsed since t. // It is shorthand for Now().Sub(t). func Since(t Time) time.Duration { return Now().Sub(t) } // ToMSTime converts t to Time. // See Time for details. func ToMSTime(t time.Time) Time { return newMSTime(t.Round(time.Millisecond)) } func newMSTime(t time.Time) Time { return Time{time: t} } func validateDurationPrecision(d time.Duration) { if d.Nanoseconds()%nanosecondsInMillisecond != 0 { panic(errors.Errorf("duration %s has lower precision than millisecond", d)) } }