blob: 28df8e48ba9fb7baa5f897d79ae81a462257bce7 [file] [log] [blame]
Serge Bazanskicc25bdf2018-10-25 14:02:58 +02001// 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
15package strfmt
16
17import (
18 "database/sql/driver"
19 "errors"
20 "fmt"
21 "regexp"
22 "strconv"
23 "strings"
24 "time"
25
26 "github.com/globalsign/mgo/bson"
27 "github.com/mailru/easyjson/jlexer"
28 "github.com/mailru/easyjson/jwriter"
29)
30
31func init() {
32 d := Duration(0)
33 // register this format in the default registry
34 Default.Add("duration", &d, IsDuration)
35}
36
37var (
38 timeUnits = [][]string{
39 {"ns", "nano"},
40 {"us", "µs", "micro"},
41 {"ms", "milli"},
42 {"s", "sec"},
43 {"m", "min"},
44 {"h", "hr", "hour"},
45 {"d", "day"},
46 {"w", "wk", "week"},
47 }
48
49 timeMultiplier = map[string]time.Duration{
50 "ns": time.Nanosecond,
51 "us": time.Microsecond,
52 "ms": time.Millisecond,
53 "s": time.Second,
54 "m": time.Minute,
55 "h": time.Hour,
56 "d": 24 * time.Hour,
57 "w": 7 * 24 * time.Hour,
58 }
59
60 durationMatcher = regexp.MustCompile(`((\d+)\s*([A-Za-zµ]+))`)
61)
62
63// IsDuration returns true if the provided string is a valid duration
64func IsDuration(str string) bool {
65 _, err := ParseDuration(str)
66 return err == nil
67}
68
69// Duration represents a duration
70//
71// Duration stores a period of time as a nanosecond count, with the largest
72// repesentable duration being approximately 290 years.
73//
74// swagger:strfmt duration
75type Duration time.Duration
76
77// MarshalText turns this instance into text
78func (d Duration) MarshalText() ([]byte, error) {
79 return []byte(time.Duration(d).String()), nil
80}
81
82// UnmarshalText hydrates this instance from text
83func (d *Duration) UnmarshalText(data []byte) error { // validation is performed later on
84 dd, err := ParseDuration(string(data))
85 if err != nil {
86 return err
87 }
88 *d = Duration(dd)
89 return nil
90}
91
92// ParseDuration parses a duration from a string, compatible with scala duration syntax
93func ParseDuration(cand string) (time.Duration, error) {
94 if dur, err := time.ParseDuration(cand); err == nil {
95 return dur, nil
96 }
97
98 var dur time.Duration
99 ok := false
100 for _, match := range durationMatcher.FindAllStringSubmatch(cand, -1) {
101
102 factor, err := strconv.Atoi(match[2]) // converts string to int
103 if err != nil {
104 return 0, err
105 }
106 unit := strings.ToLower(strings.TrimSpace(match[3]))
107
108 for _, variants := range timeUnits {
109 last := len(variants) - 1
110 multiplier := timeMultiplier[variants[0]]
111
112 for i, variant := range variants {
113 if (last == i && strings.HasPrefix(unit, variant)) || strings.EqualFold(variant, unit) {
114 ok = true
115 dur += (time.Duration(factor) * multiplier)
116 }
117 }
118 }
119 }
120
121 if ok {
122 return dur, nil
123 }
124 return 0, fmt.Errorf("Unable to parse %s as duration", cand)
125}
126
127// Scan reads a Duration value from database driver type.
128func (d *Duration) Scan(raw interface{}) error {
129 switch v := raw.(type) {
130 // TODO: case []byte: // ?
131 case int64:
132 *d = Duration(v)
133 case float64:
134 *d = Duration(int64(v))
135 case nil:
136 *d = Duration(0)
137 default:
138 return fmt.Errorf("cannot sql.Scan() strfmt.Duration from: %#v", v)
139 }
140
141 return nil
142}
143
144// Value converts Duration to a primitive value ready to be written to a database.
145func (d Duration) Value() (driver.Value, error) {
146 return driver.Value(int64(d)), nil
147}
148
149// String converts this duration to a string
150func (d Duration) String() string {
151 return time.Duration(d).String()
152}
153
154// MarshalJSON returns the Duration as JSON
155func (d Duration) MarshalJSON() ([]byte, error) {
156 var w jwriter.Writer
157 d.MarshalEasyJSON(&w)
158 return w.BuildBytes()
159}
160
161// MarshalEasyJSON writes the Duration to a easyjson.Writer
162func (d Duration) MarshalEasyJSON(w *jwriter.Writer) {
163 w.String(time.Duration(d).String())
164}
165
166// UnmarshalJSON sets the Duration from JSON
167func (d *Duration) UnmarshalJSON(data []byte) error {
168 l := jlexer.Lexer{Data: data}
169 d.UnmarshalEasyJSON(&l)
170 return l.Error()
171}
172
173// UnmarshalEasyJSON sets the Duration from a easyjson.Lexer
174func (d *Duration) UnmarshalEasyJSON(in *jlexer.Lexer) {
175 if data := in.String(); in.Ok() {
176 tt, err := ParseDuration(data)
177 if err != nil {
178 in.AddError(err)
179 return
180 }
181 *d = Duration(tt)
182 }
183}
184
185// GetBSON returns the Duration a bson.M{} map.
186func (d *Duration) GetBSON() (interface{}, error) {
187 return bson.M{"data": int64(*d)}, nil
188}
189
190// SetBSON sets the Duration from raw bson data
191func (d *Duration) SetBSON(raw bson.Raw) error {
192 var m bson.M
193 if err := raw.Unmarshal(&m); err != nil {
194 return err
195 }
196
197 if data, ok := m["data"].(int64); ok {
198 *d = Duration(data)
199 return nil
200 }
201
202 return errors.New("couldn't unmarshal bson raw value as Duration")
203}