time.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  	"regexp"
  19  	"time"
  20  )
  21  
  22  // Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases.
  23  const (
  24  	azureUtcFormatJSON = `"2006-01-02T15:04:05.999999999"`
  25  	azureUtcFormat     = "2006-01-02T15:04:05.999999999"
  26  	rfc3339JSON        = `"` + time.RFC3339Nano + `"`
  27  	rfc3339            = time.RFC3339Nano
  28  	tzOffsetRegex      = `(Z|z|\+|-)(\d+:\d+)*"*$`
  29  )
  30  
  31  // Time defines a type similar to time.Time but assumes a layout of RFC3339 date-time (i.e.,
  32  // 2006-01-02T15:04:05Z).
  33  type Time struct {
  34  	time.Time
  35  }
  36  
  37  // MarshalBinary preserves the Time as a byte array conforming to RFC3339 date-time (i.e.,
  38  // 2006-01-02T15:04:05Z).
  39  func (t Time) MarshalBinary() ([]byte, error) {
  40  	return t.Time.MarshalText()
  41  }
  42  
  43  // UnmarshalBinary reconstitutes a Time saved as a byte array conforming to RFC3339 date-time
  44  // (i.e., 2006-01-02T15:04:05Z).
  45  func (t *Time) UnmarshalBinary(data []byte) error {
  46  	return t.UnmarshalText(data)
  47  }
  48  
  49  // MarshalJSON preserves the Time as a JSON string conforming to RFC3339 date-time (i.e.,
  50  // 2006-01-02T15:04:05Z).
  51  func (t Time) MarshalJSON() (json []byte, err error) {
  52  	return t.Time.MarshalJSON()
  53  }
  54  
  55  // UnmarshalJSON reconstitutes the Time from a JSON string conforming to RFC3339 date-time
  56  // (i.e., 2006-01-02T15:04:05Z).
  57  func (t *Time) UnmarshalJSON(data []byte) (err error) {
  58  	timeFormat := azureUtcFormatJSON
  59  	match, err := regexp.Match(tzOffsetRegex, data)
  60  	if err != nil {
  61  		return err
  62  	} else if match {
  63  		timeFormat = rfc3339JSON
  64  	}
  65  	t.Time, err = ParseTime(timeFormat, string(data))
  66  	return err
  67  }
  68  
  69  // MarshalText preserves the Time as a byte array conforming to RFC3339 date-time (i.e.,
  70  // 2006-01-02T15:04:05Z).
  71  func (t Time) MarshalText() (text []byte, err error) {
  72  	return t.Time.MarshalText()
  73  }
  74  
  75  // UnmarshalText reconstitutes a Time saved as a byte array conforming to RFC3339 date-time
  76  // (i.e., 2006-01-02T15:04:05Z).
  77  func (t *Time) UnmarshalText(data []byte) (err error) {
  78  	timeFormat := azureUtcFormat
  79  	match, err := regexp.Match(tzOffsetRegex, data)
  80  	if err != nil {
  81  		return err
  82  	} else if match {
  83  		timeFormat = rfc3339
  84  	}
  85  	t.Time, err = ParseTime(timeFormat, string(data))
  86  	return err
  87  }
  88  
  89  // String returns the Time formatted as an RFC3339 date-time string (i.e.,
  90  // 2006-01-02T15:04:05Z).
  91  func (t Time) String() string {
  92  	// Note: time.Time.String does not return an RFC3339 compliant string, time.Time.MarshalText does.
  93  	b, err := t.MarshalText()
  94  	if err != nil {
  95  		return ""
  96  	}
  97  	return string(b)
  98  }
  99  
 100  // ToTime returns a Time as a time.Time
 101  func (t Time) ToTime() time.Time {
 102  	return t.Time
 103  }
 104