k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/strfmt/time.go (about) 1 // Copyright 2015 go-swagger maintainers 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package strfmt 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "regexp" 21 "strings" 22 "time" 23 ) 24 25 func init() { 26 dt := DateTime{} 27 Default.Add("datetime", &dt, IsDateTime) 28 } 29 30 // IsDateTime returns true when the string is a valid date-time 31 func IsDateTime(str string) bool { 32 if len(str) < 4 { 33 return false 34 } 35 s := strings.Split(strings.ToLower(str), "t") 36 if len(s) < 2 || !IsDate(s[0]) { 37 return false 38 } 39 40 matches := rxDateTime.FindAllStringSubmatch(s[1], -1) 41 if len(matches) == 0 || len(matches[0]) == 0 { 42 return false 43 } 44 m := matches[0] 45 res := m[1] <= "23" && m[2] <= "59" && m[3] <= "59" 46 return res 47 } 48 49 const ( 50 // RFC3339Millis represents a ISO8601 format to millis instead of to nanos 51 RFC3339Millis = "2006-01-02T15:04:05.000Z07:00" 52 // RFC3339Micro represents a ISO8601 format to micro instead of to nano 53 RFC3339Micro = "2006-01-02T15:04:05.000000Z07:00" 54 // ISO8601LocalTime represents a ISO8601 format to ISO8601 in local time (no timezone) 55 ISO8601LocalTime = "2006-01-02T15:04:05" 56 // DateTimePattern pattern to match for the date-time format from http://tools.ietf.org/html/rfc3339#section-5.6 57 DateTimePattern = `^([0-9]{2}):([0-9]{2}):([0-9]{2})(.[0-9]+)?(z|([+-][0-9]{2}:[0-9]{2}))$` 58 ) 59 60 var ( 61 dateTimeFormats = []string{RFC3339Micro, RFC3339Millis, time.RFC3339, time.RFC3339Nano, ISO8601LocalTime} 62 rxDateTime = regexp.MustCompile(DateTimePattern) 63 // MarshalFormat sets the time resolution format used for marshaling time (set to milliseconds) 64 MarshalFormat = RFC3339Millis 65 ) 66 67 // ParseDateTime parses a string that represents an ISO8601 time or a unix epoch 68 func ParseDateTime(data string) (DateTime, error) { 69 if data == "" { 70 return NewDateTime(), nil 71 } 72 var lastError error 73 for _, layout := range dateTimeFormats { 74 dd, err := time.Parse(layout, data) 75 if err != nil { 76 lastError = err 77 continue 78 } 79 return DateTime(dd), nil 80 } 81 return DateTime{}, lastError 82 } 83 84 // DateTime is a time but it serializes to ISO8601 format with millis 85 // It knows how to read 3 different variations of a RFC3339 date time. 86 // Most APIs we encounter want either millisecond or second precision times. 87 // This just tries to make it worry-free. 88 // 89 // swagger:strfmt date-time 90 type DateTime time.Time 91 92 // NewDateTime is a representation of zero value for DateTime type 93 func NewDateTime() DateTime { 94 return DateTime(time.Unix(0, 0).UTC()) 95 } 96 97 // String converts this time to a string 98 func (t DateTime) String() string { 99 return time.Time(t).Format(MarshalFormat) 100 } 101 102 // MarshalText implements the text marshaller interface 103 func (t DateTime) MarshalText() ([]byte, error) { 104 return []byte(t.String()), nil 105 } 106 107 // UnmarshalText implements the text unmarshaller interface 108 func (t *DateTime) UnmarshalText(text []byte) error { 109 tt, err := ParseDateTime(string(text)) 110 if err != nil { 111 return err 112 } 113 *t = tt 114 return nil 115 } 116 117 // Scan scans a DateTime value from database driver type. 118 func (t *DateTime) Scan(raw interface{}) error { 119 // TODO: case int64: and case float64: ? 120 switch v := raw.(type) { 121 case []byte: 122 return t.UnmarshalText(v) 123 case string: 124 return t.UnmarshalText([]byte(v)) 125 case time.Time: 126 *t = DateTime(v) 127 case nil: 128 *t = DateTime{} 129 default: 130 return fmt.Errorf("cannot sql.Scan() strfmt.DateTime from: %#v", v) 131 } 132 133 return nil 134 } 135 136 // MarshalJSON returns the DateTime as JSON 137 func (t DateTime) MarshalJSON() ([]byte, error) { 138 return json.Marshal(time.Time(t).Format(MarshalFormat)) 139 } 140 141 // UnmarshalJSON sets the DateTime from JSON 142 func (t *DateTime) UnmarshalJSON(data []byte) error { 143 if string(data) == jsonNull { 144 return nil 145 } 146 147 var tstr string 148 if err := json.Unmarshal(data, &tstr); err != nil { 149 return err 150 } 151 tt, err := ParseDateTime(tstr) 152 if err != nil { 153 return err 154 } 155 *t = tt 156 return nil 157 } 158 159 // DeepCopyInto copies the receiver and writes its value into out. 160 func (t *DateTime) DeepCopyInto(out *DateTime) { 161 *out = *t 162 } 163 164 // DeepCopy copies the receiver into a new DateTime. 165 func (t *DateTime) DeepCopy() *DateTime { 166 if t == nil { 167 return nil 168 } 169 out := new(DateTime) 170 t.DeepCopyInto(out) 171 return out 172 }