Skip to content

Commit 2a23014

Browse files
committed
Add methods to model.Duration for JSON marshalling and unmarshalling
Add methods to model.Duration structs to allow them to be serialized and unserialized to/from JSON. This helps downstream consumers of the structs that attempt to use them in objects that are expected to be able to be represented as JSON (such as Cortex). Signed-off-by: Nick Pillitteri <[email protected]>
1 parent 47ee79a commit 2a23014

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

model/time.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package model
1515

1616
import (
17+
"encoding/json"
1718
"fmt"
1819
"math"
1920
"regexp"
@@ -254,6 +255,22 @@ func (d Duration) String() string {
254255
return r
255256
}
256257

258+
// MarshalJSON implements the json.Marshaler interface.
259+
func (d Duration) MarshalJSON() ([]byte, error) {
260+
return json.Marshal(d.String())
261+
}
262+
263+
// UnmarshalJSON implements the json.Unmarshaler interface.
264+
func (d *Duration) UnmarshalJSON(bytes []byte) error {
265+
var err error
266+
var s string
267+
if err := json.Unmarshal(bytes, &s); err != nil {
268+
return err
269+
}
270+
*d, err = ParseDuration(s)
271+
return err
272+
}
273+
257274
// MarshalText implements the encoding.TextMarshaler interface.
258275
func (d *Duration) MarshalText() ([]byte, error) {
259276
return []byte(d.String()), nil

model/time_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package model
1515

1616
import (
17+
"encoding/json"
1718
"strconv"
1819
"testing"
1920
"time"
@@ -230,6 +231,82 @@ func TestDuration_UnmarshalText(t *testing.T) {
230231
}
231232
}
232233

234+
func TestDuration_UnmarshalJSON(t *testing.T) {
235+
var cases = []struct {
236+
in string
237+
out time.Duration
238+
239+
expectedString string
240+
}{
241+
{
242+
in: `"0"`,
243+
out: 0,
244+
expectedString: `"0s"`,
245+
}, {
246+
in: `"0w"`,
247+
out: 0,
248+
expectedString: `"0s"`,
249+
}, {
250+
in: `"0s"`,
251+
out: 0,
252+
}, {
253+
in: `"324ms"`,
254+
out: 324 * time.Millisecond,
255+
}, {
256+
in: `"3s"`,
257+
out: 3 * time.Second,
258+
}, {
259+
in: `"5m"`,
260+
out: 5 * time.Minute,
261+
}, {
262+
in: `"1h"`,
263+
out: time.Hour,
264+
}, {
265+
in: `"4d"`,
266+
out: 4 * 24 * time.Hour,
267+
}, {
268+
in: `"4d1h"`,
269+
out: 4*24*time.Hour + time.Hour,
270+
}, {
271+
in: `"14d"`,
272+
out: 14 * 24 * time.Hour,
273+
expectedString: `"2w"`,
274+
}, {
275+
in: `"3w"`,
276+
out: 3 * 7 * 24 * time.Hour,
277+
}, {
278+
in: `"3w2d1h"`,
279+
out: 3*7*24*time.Hour + 2*24*time.Hour + time.Hour,
280+
expectedString: `"23d1h"`,
281+
}, {
282+
in: `"10y"`,
283+
out: 10 * 365 * 24 * time.Hour,
284+
},
285+
}
286+
287+
for _, c := range cases {
288+
var d Duration
289+
err := json.Unmarshal([]byte(c.in), &d)
290+
if err != nil {
291+
t.Errorf("Unexpected error on input %q", c.in)
292+
}
293+
if time.Duration(d) != c.out {
294+
t.Errorf("Expected %v but got %v", c.out, d)
295+
}
296+
expectedString := c.expectedString
297+
if c.expectedString == "" {
298+
expectedString = c.in
299+
}
300+
bytes, err := json.Marshal(d)
301+
if err != nil {
302+
t.Errorf("Unexpected error on marshal of %v: %s", d, err)
303+
}
304+
if string(bytes) != expectedString {
305+
t.Errorf("Expected duration string %q but got %q", c.in, d.String())
306+
}
307+
}
308+
}
309+
233310
func TestParseBadDuration(t *testing.T) {
234311
var cases = []string{
235312
"1",

0 commit comments

Comments
 (0)