1package date 2 3// Copyright 2017 Microsoft Corporation 4// 5// Licensed under the Apache License, Version 2.0 (the "License"); 6// you may not use this file except in compliance with the License. 7// You may obtain a copy of the License at 8// 9// http://www.apache.org/licenses/LICENSE-2.0 10// 11// Unless required by applicable law or agreed to in writing, software 12// distributed under the License is distributed on an "AS IS" BASIS, 13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14// See the License for the specific language governing permissions and 15// limitations under the License. 16 17import ( 18 "bytes" 19 "encoding/binary" 20 "encoding/json" 21 "time" 22) 23 24// unixEpoch is the moment in time that should be treated as timestamp 0. 25var unixEpoch = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC) 26 27// UnixTime marshals and unmarshals a time that is represented as the number 28// of seconds (ignoring skip-seconds) since the Unix Epoch. 29type UnixTime time.Time 30 31// Duration returns the time as a Duration since the UnixEpoch. 32func (t UnixTime) Duration() time.Duration { 33 return time.Time(t).Sub(unixEpoch) 34} 35 36// NewUnixTimeFromSeconds creates a UnixTime as a number of seconds from the UnixEpoch. 37func NewUnixTimeFromSeconds(seconds float64) UnixTime { 38 return NewUnixTimeFromDuration(time.Duration(seconds * float64(time.Second))) 39} 40 41// NewUnixTimeFromNanoseconds creates a UnixTime as a number of nanoseconds from the UnixEpoch. 42func NewUnixTimeFromNanoseconds(nanoseconds int64) UnixTime { 43 return NewUnixTimeFromDuration(time.Duration(nanoseconds)) 44} 45 46// NewUnixTimeFromDuration creates a UnixTime as a duration of time since the UnixEpoch. 47func NewUnixTimeFromDuration(dur time.Duration) UnixTime { 48 return UnixTime(unixEpoch.Add(dur)) 49} 50 51// UnixEpoch retreives the moment considered the Unix Epoch. I.e. The time represented by '0' 52func UnixEpoch() time.Time { 53 return unixEpoch 54} 55 56// MarshalJSON preserves the UnixTime as a JSON number conforming to Unix Timestamp requirements. 57// (i.e. the number of seconds since midnight January 1st, 1970 not considering leap seconds.) 58func (t UnixTime) MarshalJSON() ([]byte, error) { 59 buffer := &bytes.Buffer{} 60 enc := json.NewEncoder(buffer) 61 err := enc.Encode(float64(time.Time(t).UnixNano()) / 1e9) 62 if err != nil { 63 return nil, err 64 } 65 return buffer.Bytes(), nil 66} 67 68// UnmarshalJSON reconstitures a UnixTime saved as a JSON number of the number of seconds since 69// midnight January 1st, 1970. 70func (t *UnixTime) UnmarshalJSON(text []byte) error { 71 dec := json.NewDecoder(bytes.NewReader(text)) 72 73 var secondsSinceEpoch float64 74 if err := dec.Decode(&secondsSinceEpoch); err != nil { 75 return err 76 } 77 78 *t = NewUnixTimeFromSeconds(secondsSinceEpoch) 79 80 return nil 81} 82 83// MarshalText stores the number of seconds since the Unix Epoch as a textual floating point number. 84func (t UnixTime) MarshalText() ([]byte, error) { 85 cast := time.Time(t) 86 return cast.MarshalText() 87} 88 89// UnmarshalText populates a UnixTime with a value stored textually as a floating point number of seconds since the Unix Epoch. 90func (t *UnixTime) UnmarshalText(raw []byte) error { 91 var unmarshaled time.Time 92 93 if err := unmarshaled.UnmarshalText(raw); err != nil { 94 return err 95 } 96 97 *t = UnixTime(unmarshaled) 98 return nil 99} 100 101// MarshalBinary converts a UnixTime into a binary.LittleEndian float64 of nanoseconds since the epoch. 102func (t UnixTime) MarshalBinary() ([]byte, error) { 103 buf := &bytes.Buffer{} 104 105 payload := int64(t.Duration()) 106 107 if err := binary.Write(buf, binary.LittleEndian, &payload); err != nil { 108 return nil, err 109 } 110 111 return buf.Bytes(), nil 112} 113 114// UnmarshalBinary converts a from a binary.LittleEndian float64 of nanoseconds since the epoch into a UnixTime. 115func (t *UnixTime) UnmarshalBinary(raw []byte) error { 116 var nanosecondsSinceEpoch int64 117 118 if err := binary.Read(bytes.NewReader(raw), binary.LittleEndian, &nanosecondsSinceEpoch); err != nil { 119 return err 120 } 121 *t = NewUnixTimeFromNanoseconds(nanosecondsSinceEpoch) 122 return nil 123} 124