k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/strfmt/duration.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 "strconv" 22 "strings" 23 "time" 24 ) 25 26 func init() { 27 d := Duration(0) 28 // register this format in the default registry 29 Default.Add("duration", &d, IsDuration) 30 } 31 32 var ( 33 timeUnits = [][]string{ 34 {"ns", "nano"}, 35 {"us", "µs", "micro"}, 36 {"ms", "milli"}, 37 {"s", "sec"}, 38 {"m", "min"}, 39 {"h", "hr", "hour"}, 40 {"d", "day"}, 41 {"w", "wk", "week"}, 42 } 43 44 timeMultiplier = map[string]time.Duration{ 45 "ns": time.Nanosecond, 46 "us": time.Microsecond, 47 "ms": time.Millisecond, 48 "s": time.Second, 49 "m": time.Minute, 50 "h": time.Hour, 51 "d": 24 * time.Hour, 52 "w": 7 * 24 * time.Hour, 53 } 54 55 durationMatcher = regexp.MustCompile(`((\d+)\s*([A-Za-zµ]+))`) 56 ) 57 58 // IsDuration returns true if the provided string is a valid duration 59 func IsDuration(str string) bool { 60 _, err := ParseDuration(str) 61 return err == nil 62 } 63 64 // Duration represents a duration 65 // 66 // Duration stores a period of time as a nanosecond count, with the largest 67 // repesentable duration being approximately 290 years. 68 // 69 // swagger:strfmt duration 70 type Duration time.Duration 71 72 // MarshalText turns this instance into text 73 func (d Duration) MarshalText() ([]byte, error) { 74 return []byte(time.Duration(d).String()), nil 75 } 76 77 // UnmarshalText hydrates this instance from text 78 func (d *Duration) UnmarshalText(data []byte) error { // validation is performed later on 79 dd, err := ParseDuration(string(data)) 80 if err != nil { 81 return err 82 } 83 *d = Duration(dd) 84 return nil 85 } 86 87 // ParseDuration parses a duration from a string, compatible with scala duration syntax 88 func ParseDuration(cand string) (time.Duration, error) { 89 if dur, err := time.ParseDuration(cand); err == nil { 90 return dur, nil 91 } 92 93 var dur time.Duration 94 ok := false 95 for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) { 96 97 factor, err := strconv.Atoi(match[2]) // converts string to int 98 if err != nil { 99 return 0, err 100 } 101 unit := strings.ToLower(strings.TrimSpace(match[3])) 102 103 for _, variants := range timeUnits { 104 last := len(variants) - 1 105 multiplier := timeMultiplier[variants[0]] 106 107 for i, variant := range variants { 108 if (last == i && strings.HasPrefix(unit, variant)) || strings.EqualFold(variant, unit) { 109 ok = true 110 dur += time.Duration(factor) * multiplier 111 } 112 } 113 } 114 } 115 116 if ok { 117 return dur, nil 118 } 119 return 0, fmt.Errorf("unable to parse %s as duration", cand) 120 } 121 122 // Scan reads a Duration value from database driver type. 123 func (d *Duration) Scan(raw interface{}) error { 124 switch v := raw.(type) { 125 // TODO: case []byte: // ? 126 case int64: 127 *d = Duration(v) 128 case float64: 129 *d = Duration(int64(v)) 130 case nil: 131 *d = Duration(0) 132 default: 133 return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v) 134 } 135 136 return nil 137 } 138 139 // String converts this duration to a string 140 func (d Duration) String() string { 141 return time.Duration(d).String() 142 } 143 144 // MarshalJSON returns the Duration as JSON 145 func (d Duration) MarshalJSON() ([]byte, error) { 146 return json.Marshal(time.Duration(d).String()) 147 } 148 149 // UnmarshalJSON sets the Duration from JSON 150 func (d *Duration) UnmarshalJSON(data []byte) error { 151 if string(data) == jsonNull { 152 return nil 153 } 154 155 var dstr string 156 if err := json.Unmarshal(data, &dstr); err != nil { 157 return err 158 } 159 tt, err := ParseDuration(dstr) 160 if err != nil { 161 return err 162 } 163 *d = Duration(tt) 164 return nil 165 } 166 167 // DeepCopyInto copies the receiver and writes its value into out. 168 func (d *Duration) DeepCopyInto(out *Duration) { 169 *out = *d 170 } 171 172 // DeepCopy copies the receiver into a new Duration. 173 func (d *Duration) DeepCopy() *Duration { 174 if d == nil { 175 return nil 176 } 177 out := new(Duration) 178 d.DeepCopyInto(out) 179 return out 180 }