Skip to content

Commit 279dd19

Browse files
authored
Set json encoding precision (#162)
1 parent 863d23d commit 279dd19

File tree

2 files changed

+54
-6
lines changed

2 files changed

+54
-6
lines changed

types.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,13 @@ func newNumericDateFromSeconds(f float64) *NumericDate {
4949
// MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch
5050
// represented in NumericDate to a byte array, using the precision specified in TimePrecision.
5151
func (date NumericDate) MarshalJSON() (b []byte, err error) {
52+
var prec int
53+
if TimePrecision < time.Second {
54+
prec = int(math.Log10(float64(time.Second) / float64(TimePrecision)))
55+
}
5256
f := float64(date.Truncate(TimePrecision).UnixNano()) / float64(time.Second)
5357

54-
return []byte(strconv.FormatFloat(f, 'f', -1, 64)), nil
58+
return []byte(strconv.FormatFloat(f, 'f', prec, 64)), nil
5559
}
5660

5761
// UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a

types_test.go

+49-5
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ func TestNumericDate(t *testing.T) {
1818

1919
jwt.TimePrecision = time.Microsecond
2020

21-
raw := `{"iat":1516239022,"exp":1516239022.12345}`
21+
raw := `{"iat":1516239022.000000,"exp":1516239022.123450}`
2222

23-
err := json.Unmarshal([]byte(raw), &s)
24-
25-
if err != nil {
26-
t.Errorf("Unexpected error: %s", err)
23+
if err := json.Unmarshal([]byte(raw), &s); err != nil {
24+
t.Fatalf("Unexpected error: %s", err)
2725
}
2826

2927
b, _ := json.Marshal(s)
@@ -65,3 +63,49 @@ func TestSingleArrayMarshal(t *testing.T) {
6563
t.Errorf("Serialized format of string array mismatch. Expecting: %s Got: %s", string(expected), string(b))
6664
}
6765
}
66+
67+
func TestNumericDate_MarshalJSON(t *testing.T) {
68+
// Do not run this test in parallel because it's changing
69+
// global state.
70+
oldPrecision := jwt.TimePrecision
71+
t.Cleanup(func() {
72+
jwt.TimePrecision = oldPrecision
73+
})
74+
75+
tt := []struct {
76+
in time.Time
77+
want string
78+
precision time.Duration
79+
}{
80+
{time.Unix(5243700879, 0), "5243700879", time.Second},
81+
{time.Unix(5243700879, 0), "5243700879.000", time.Millisecond},
82+
{time.Unix(5243700879, 0), "5243700879.000001", time.Microsecond},
83+
{time.Unix(5243700879, 0), "5243700879.000000954", time.Nanosecond},
84+
//
85+
{time.Unix(4239425898, 0), "4239425898", time.Second},
86+
{time.Unix(4239425898, 0), "4239425898.000", time.Millisecond},
87+
{time.Unix(4239425898, 0), "4239425898.000000", time.Microsecond},
88+
{time.Unix(4239425898, 0), "4239425898.000000000", time.Nanosecond},
89+
//
90+
{time.Unix(0, 1644285000210402000), "1644285000", time.Second},
91+
{time.Unix(0, 1644285000210402000), "1644285000.210", time.Millisecond},
92+
{time.Unix(0, 1644285000210402000), "1644285000.210402", time.Microsecond},
93+
{time.Unix(0, 1644285000210402000), "1644285000.210402012", time.Nanosecond},
94+
//
95+
{time.Unix(0, 1644285315063096000), "1644285315", time.Second},
96+
{time.Unix(0, 1644285315063096000), "1644285315.063", time.Millisecond},
97+
{time.Unix(0, 1644285315063096000), "1644285315.063096", time.Microsecond},
98+
{time.Unix(0, 1644285315063096000), "1644285315.063096046", time.Nanosecond},
99+
}
100+
101+
for i, tc := range tt {
102+
jwt.TimePrecision = tc.precision
103+
by, err := jwt.NewNumericDate(tc.in).MarshalJSON()
104+
if err != nil {
105+
t.Fatal(err)
106+
}
107+
if got := string(by); got != tc.want {
108+
t.Errorf("[%d]: failed encoding: got %q want %q", i, got, tc.want)
109+
}
110+
}
111+
}

0 commit comments

Comments
 (0)