blob: efff656e1091838137a09c17c9e2e6e80c6999ae [file] [log] [blame]
Zack Williamse940c7a2019-08-21 14:25:39 -07001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package v1
18
19import (
20 "encoding/json"
21 "time"
22
23 "github.com/google/gofuzz"
24)
25
26// Time is a wrapper around time.Time which supports correct
27// marshaling to YAML and JSON. Wrappers are provided for many
28// of the factory methods that the time package offers.
29//
30// +protobuf.options.marshal=false
31// +protobuf.as=Timestamp
32// +protobuf.options.(gogoproto.goproto_stringer)=false
33type Time struct {
34 time.Time `protobuf:"-"`
35}
36
37// DeepCopyInto creates a deep-copy of the Time value. The underlying time.Time
38// type is effectively immutable in the time API, so it is safe to
39// copy-by-assign, despite the presence of (unexported) Pointer fields.
40func (t *Time) DeepCopyInto(out *Time) {
41 *out = *t
42}
43
44// String returns the representation of the time.
45func (t Time) String() string {
46 return t.Time.String()
47}
48
49// NewTime returns a wrapped instance of the provided time
50func NewTime(time time.Time) Time {
51 return Time{time}
52}
53
54// Date returns the Time corresponding to the supplied parameters
55// by wrapping time.Date.
56func Date(year int, month time.Month, day, hour, min, sec, nsec int, loc *time.Location) Time {
57 return Time{time.Date(year, month, day, hour, min, sec, nsec, loc)}
58}
59
60// Now returns the current local time.
61func Now() Time {
62 return Time{time.Now()}
63}
64
65// IsZero returns true if the value is nil or time is zero.
66func (t *Time) IsZero() bool {
67 if t == nil {
68 return true
69 }
70 return t.Time.IsZero()
71}
72
73// Before reports whether the time instant t is before u.
74func (t *Time) Before(u *Time) bool {
75 return t.Time.Before(u.Time)
76}
77
78// Equal reports whether the time instant t is equal to u.
79func (t *Time) Equal(u *Time) bool {
80 if t == nil && u == nil {
81 return true
82 }
83 if t != nil && u != nil {
84 return t.Time.Equal(u.Time)
85 }
86 return false
87}
88
89// Unix returns the local time corresponding to the given Unix time
90// by wrapping time.Unix.
91func Unix(sec int64, nsec int64) Time {
92 return Time{time.Unix(sec, nsec)}
93}
94
95// Rfc3339Copy returns a copy of the Time at second-level precision.
96func (t Time) Rfc3339Copy() Time {
97 copied, _ := time.Parse(time.RFC3339, t.Format(time.RFC3339))
98 return Time{copied}
99}
100
101// UnmarshalJSON implements the json.Unmarshaller interface.
102func (t *Time) UnmarshalJSON(b []byte) error {
103 if len(b) == 4 && string(b) == "null" {
104 t.Time = time.Time{}
105 return nil
106 }
107
108 var str string
109 err := json.Unmarshal(b, &str)
110 if err != nil {
111 return err
112 }
113
114 pt, err := time.Parse(time.RFC3339, str)
115 if err != nil {
116 return err
117 }
118
119 t.Time = pt.Local()
120 return nil
121}
122
123// UnmarshalQueryParameter converts from a URL query parameter value to an object
124func (t *Time) UnmarshalQueryParameter(str string) error {
125 if len(str) == 0 {
126 t.Time = time.Time{}
127 return nil
128 }
129 // Tolerate requests from older clients that used JSON serialization to build query params
130 if len(str) == 4 && str == "null" {
131 t.Time = time.Time{}
132 return nil
133 }
134
135 pt, err := time.Parse(time.RFC3339, str)
136 if err != nil {
137 return err
138 }
139
140 t.Time = pt.Local()
141 return nil
142}
143
144// MarshalJSON implements the json.Marshaler interface.
145func (t Time) MarshalJSON() ([]byte, error) {
146 if t.IsZero() {
147 // Encode unset/nil objects as JSON's "null".
148 return []byte("null"), nil
149 }
150
151 return json.Marshal(t.UTC().Format(time.RFC3339))
152}
153
154// OpenAPISchemaType is used by the kube-openapi generator when constructing
155// the OpenAPI spec of this type.
156//
157// See: https://github.com/kubernetes/kube-openapi/tree/master/pkg/generators
158func (_ Time) OpenAPISchemaType() []string { return []string{"string"} }
159
160// OpenAPISchemaFormat is used by the kube-openapi generator when constructing
161// the OpenAPI spec of this type.
162func (_ Time) OpenAPISchemaFormat() string { return "date-time" }
163
164// MarshalQueryParameter converts to a URL query parameter value
165func (t Time) MarshalQueryParameter() (string, error) {
166 if t.IsZero() {
167 // Encode unset/nil objects as an empty string
168 return "", nil
169 }
170
171 return t.UTC().Format(time.RFC3339), nil
172}
173
174// Fuzz satisfies fuzz.Interface.
175func (t *Time) Fuzz(c fuzz.Continue) {
176 if t == nil {
177 return
178 }
179 // Allow for about 1000 years of randomness. Leave off nanoseconds
180 // because JSON doesn't represent them so they can't round-trip
181 // properly.
182 t.Time = time.Unix(c.Rand.Int63n(1000*365*24*60*60), 0)
183}
184
185var _ fuzz.Interface = &Time{}