Files

233 lines
6.0 KiB
Go

// The MIT License
//
// Copyright (c) 2020 Temporal Technologies Inc. All rights reserved.
//
// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package timestamp
import (
"time"
"github.com/gogo/protobuf/types"
)
var (
// This is the maximal time value we support
maxValidTimeGo = time.Unix(0, MaxValidTimeNanoseconds).UTC()
maxValidTimestamp = TimestampFromTimePtr(&maxValidTimeGo)
)
const MaxValidTimeNanoseconds = (2 ^ (64 - 1)) - 1
// Timestamp provides easy conversions and utility comparison functions
// making go to proto time comparison straightforward
type Timestamp struct {
// one of
protoTime *types.Timestamp
goTime *time.Time
}
// TimestampFromProto returns a Timestamp from proto time
//noinspection GoNameStartsWithPackageName
func TimestampFromProto(ts *types.Timestamp) *Timestamp {
// todo: should we validate against proto min/max time here?
return &Timestamp{
protoTime: &types.Timestamp{
Seconds: ts.Seconds,
Nanos: ts.Nanos,
},
}
}
// TimestampFromTimePtr returns a Timestamp from a time.time
//noinspection GoNameStartsWithPackageName
func TimestampFromTime(t time.Time) *Timestamp {
// todo: should we validate against proto min/max time here?
c := time.Unix(0, t.UnixNano()).UTC()
return &Timestamp{
goTime: &c,
}
}
// TimestampFromTimePtr returns a Timestamp from a time.time
//noinspection GoNameStartsWithPackageName
func TimestampFromTimePtr(t *time.Time) *Timestamp {
// todo: should we validate against proto min/max time here?
c := time.Unix(0, t.UnixNano()).UTC()
return &Timestamp{
goTime: &c,
}
}
// TimestampNow returns a timestamp that represents Now()
//noinspection GoNameStartsWithPackageName
func TimestampNow() *Timestamp {
return &Timestamp{
protoTime: types.TimestampNow(),
}
}
// TimestampNowAddSeconds returns a timestamp that represents Now() + some number of seconds
//noinspection GoNameStartsWithPackageName
func TimestampNowAddSeconds(seconds int64) *Timestamp {
t := TimestampNow()
t.protoTime.Seconds += seconds
return t
}
// TimestampEpoch returns the unix epoch -TimestampFromTime(time.Unix(0, 0)).UTC()
//noinspection GoNameStartsWithPackageName
func TimestampEpoch() *Timestamp {
epoch := time.Unix(0, 0).UTC()
return TimestampFromTimePtr(&epoch)
}
// ToProto returns the proto representation
//noinspection GoReceiverNames
func (t *Timestamp) ToProto() *types.Timestamp {
if t.protoTime != nil {
return t.protoTime
}
proto, _ := types.TimestampProto(*t.goTime)
return proto
}
// ToTime returns the time.time representation
//noinspection GoReceiverNames
func (t *Timestamp) ToTime() *time.Time {
if t.goTime != nil {
return t.goTime
}
goTime, _ := types.TimestampFromProto(t.protoTime)
return &goTime
}
// Before returns true when t1 is after t2, false otherwise
//noinspection GoReceiverNames
func (t1 *Timestamp) After(t2 *Timestamp) bool {
if t1.goTime != nil && t2.goTime != nil {
// both go time
return t1.goTime.After(*t2.goTime)
}
return t1.UnixNano() > t2.UnixNano()
}
// Before returns true when t1 is before t2, false otherwise
//noinspection GoReceiverNames
func (t1 *Timestamp) Before(t2 *Timestamp) bool {
if t1.goTime != nil && t2.goTime != nil {
// both go time
return t1.goTime.Before(*t2.goTime)
}
return t1.UnixNano() < t2.UnixNano()
}
// SamesAs returns true when t1 is the same time as t2, false otherwise
//noinspection GoReceiverNames
func (t1 *Timestamp) SameAs(t2 *Timestamp) bool {
if t1.goTime != nil && t2.goTime != nil {
// both go time
return t1.goTime.Equal(*t2.goTime)
}
return t1.UnixNano() == t2.UnixNano()
}
// UnixNano returns the int64 representation of nanoseconds since 1970 (see time.UnixNano)
//noinspection GoReceiverNames
func (t *Timestamp) UnixNano() int64 {
if t.goTime != nil {
return t.goTime.UnixNano()
}
return t.protoTime.Seconds*time.Second.Nanoseconds() + int64(t.protoTime.Nanos)
}
func TimePtr(t time.Time) *time.Time {
return &t
}
func TimeValue(t *time.Time) time.Time {
if t == nil {
return time.Time{}
}
return *t
}
func DurationValue(d *time.Duration) time.Duration {
if d == nil {
return 0
}
return *d
}
func MinDurationPtr(d1 *time.Duration, d2 *time.Duration) *time.Duration {
res := MinDuration(DurationValue(d1), DurationValue(d2))
return &res
}
func MinDuration(d1 time.Duration, d2 time.Duration) time.Duration {
if d1 > d2 {
return d2
}
return d1
}
func RoundUp(d time.Duration) time.Duration {
res := d.Truncate(time.Second)
if res == d {
return d
}
return res + time.Second
}
func UnixOrZeroTime(nanos int64) time.Time {
if nanos <= 0 {
nanos = 0
}
return time.Unix(0, nanos).UTC()
}
func UnixOrZeroTimePtr(nanos int64) *time.Time {
return TimePtr(UnixOrZeroTime(nanos))
}
func TimeNowPtrUtcAddDuration(t time.Duration) *time.Time {
return TimePtr(time.Now().UTC().Add(t))
}
func TimeNowPtrUtcAddSeconds(seconds int) *time.Time {
return TimePtr(time.Now().UTC().Add(time.Second * time.Duration(seconds)))
}
func TimeNowPtrUtc() *time.Time {
return TimePtr(time.Now().UTC())
}