package date // Copyright 2017 Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import ( "bytes" "encoding/binary" "encoding/json" "time" ) // unixEpoch is the moment in time that should be treated as timestamp 0. var unixEpoch = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC) // UnixTime marshals and unmarshals a time that is represented as the number // of seconds (ignoring skip-seconds) since the Unix Epoch. type UnixTime time.Time // Duration returns the time as a Duration since the UnixEpoch. func (t UnixTime) Duration() time.Duration { return time.Time(t).Sub(unixEpoch) } // NewUnixTimeFromSeconds creates a UnixTime as a number of seconds from the UnixEpoch. func NewUnixTimeFromSeconds(seconds float64) UnixTime { return NewUnixTimeFromDuration(time.Duration(seconds * float64(time.Second))) } // NewUnixTimeFromNanoseconds creates a UnixTime as a number of nanoseconds from the UnixEpoch. func NewUnixTimeFromNanoseconds(nanoseconds int64) UnixTime { return NewUnixTimeFromDuration(time.Duration(nanoseconds)) } // NewUnixTimeFromDuration creates a UnixTime as a duration of time since the UnixEpoch. func NewUnixTimeFromDuration(dur time.Duration) UnixTime { return UnixTime(unixEpoch.Add(dur)) } // UnixEpoch retreives the moment considered the Unix Epoch. I.e. The time represented by '0' func UnixEpoch() time.Time { return unixEpoch } // MarshalJSON preserves the UnixTime as a JSON number conforming to Unix Timestamp requirements. // (i.e. the number of seconds since midnight January 1st, 1970 not considering leap seconds.) func (t UnixTime) MarshalJSON() ([]byte, error) { buffer := &bytes.Buffer{} enc := json.NewEncoder(buffer) err := enc.Encode(float64(time.Time(t).UnixNano()) / 1e9) if err != nil { return nil, err } return buffer.Bytes(), nil } // UnmarshalJSON reconstitures a UnixTime saved as a JSON number of the number of seconds since // midnight January 1st, 1970. func (t *UnixTime) UnmarshalJSON(text []byte) error { dec := json.NewDecoder(bytes.NewReader(text)) var secondsSinceEpoch float64 if err := dec.Decode(&secondsSinceEpoch); err != nil { return err } *t = NewUnixTimeFromSeconds(secondsSinceEpoch) return nil } // MarshalText stores the number of seconds since the Unix Epoch as a textual floating point number. func (t UnixTime) MarshalText() ([]byte, error) { cast := time.Time(t) return cast.MarshalText() } // UnmarshalText populates a UnixTime with a value stored textually as a floating point number of seconds since the Unix Epoch. func (t *UnixTime) UnmarshalText(raw []byte) error { var unmarshaled time.Time if err := unmarshaled.UnmarshalText(raw); err != nil { return err } *t = UnixTime(unmarshaled) return nil } // MarshalBinary converts a UnixTime into a binary.LittleEndian float64 of nanoseconds since the epoch. func (t UnixTime) MarshalBinary() ([]byte, error) { buf := &bytes.Buffer{} payload := int64(t.Duration()) if err := binary.Write(buf, binary.LittleEndian, &payload); err != nil { return nil, err } return buf.Bytes(), nil } // UnmarshalBinary converts a from a binary.LittleEndian float64 of nanoseconds since the epoch into a UnixTime. func (t *UnixTime) UnmarshalBinary(raw []byte) error { var nanosecondsSinceEpoch int64 if err := binary.Read(bytes.NewReader(raw), binary.LittleEndian, &nanosecondsSinceEpoch); err != nil { return err } *t = NewUnixTimeFromNanoseconds(nanosecondsSinceEpoch) return nil }