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