1/* 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{} 186