unixtime.go raw

   1  package 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  
  17  import (
  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.
  25  var 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.
  29  type UnixTime time.Time
  30  
  31  // Duration returns the time as a Duration since the UnixEpoch.
  32  func (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.
  37  func 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.
  42  func 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.
  47  func 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'
  52  func 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.)
  58  func (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.
  70  func (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.
  84  func (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.
  90  func (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.
 102  func (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.
 115  func (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