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