1
2
3
4
5
6
7 package json
8
9 import (
10 "bytes"
11 "cmp"
12 "errors"
13 "fmt"
14 "math"
15 "math/bits"
16 "reflect"
17 "strconv"
18 "strings"
19 "time"
20
21 "encoding/json/internal"
22 "encoding/json/internal/jsonflags"
23 "encoding/json/internal/jsonopts"
24 "encoding/json/internal/jsonwire"
25 "encoding/json/jsontext"
26 )
27
28 var (
29 timeDurationType = reflect.TypeFor[time.Duration]()
30 timeTimeType = reflect.TypeFor[time.Time]()
31 )
32
33 func makeTimeArshaler(fncs *arshaler, t reflect.Type) *arshaler {
34
35
36
37
38
39
40
41
42 switch t {
43 case timeDurationType:
44 fncs.nonDefault = true
45 marshalNano := fncs.marshal
46 fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error {
47 xe := export.Encoder(enc)
48 var m durationArshaler
49 if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
50 if !m.initFormat(mo.Format) {
51 return newInvalidFormatError(enc, t, mo)
52 }
53 } else if mo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) {
54 return marshalNano(enc, va, mo)
55 }
56
57
58 m.td = *va.Addr().Interface().(*time.Duration)
59 k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers))
60 if err := xe.AppendRaw(k, true, m.appendMarshal); err != nil {
61 if !isSyntacticError(err) && !export.IsIOError(err) {
62 err = newMarshalErrorBefore(enc, t, err)
63 }
64 return err
65 }
66 return nil
67 }
68 unmarshalNano := fncs.unmarshal
69 fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error {
70 xd := export.Decoder(dec)
71 var u durationArshaler
72 if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
73 if !u.initFormat(uo.Format) {
74 return newInvalidFormatError(dec, t, uo)
75 }
76 } else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) {
77 return unmarshalNano(dec, va, uo)
78 }
79
80 stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers)
81 var flags jsonwire.ValueFlags
82 td := va.Addr().Interface().(*time.Duration)
83 val, err := xd.ReadValue(&flags)
84 if err != nil {
85 return err
86 }
87 switch k := val.Kind(); k {
88 case 'n':
89 if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
90 *td = time.Duration(0)
91 }
92 return nil
93 case '"':
94 if !stringify {
95 break
96 }
97 val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
98 if err := u.unmarshal(val); err != nil {
99 return newUnmarshalErrorAfter(dec, t, err)
100 }
101 *td = u.td
102 return nil
103 case '0':
104 if stringify {
105 break
106 }
107 if err := u.unmarshal(val); err != nil {
108 return newUnmarshalErrorAfter(dec, t, err)
109 }
110 *td = u.td
111 return nil
112 }
113 return newUnmarshalErrorAfter(dec, t, nil)
114 }
115 case timeTimeType:
116 fncs.nonDefault = true
117 fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) {
118 xe := export.Encoder(enc)
119 var m timeArshaler
120 if mo.Format != "" && mo.FormatDepth == xe.Tokens.Depth() {
121 if !m.initFormat(mo.Format) {
122 return newInvalidFormatError(enc, t, mo)
123 }
124 }
125
126
127 m.tt = *va.Addr().Interface().(*time.Time)
128 k := stringOrNumberKind(!m.isNumeric() || xe.Tokens.Last.NeedObjectName() || mo.Flags.Get(jsonflags.StringifyNumbers))
129 if err := xe.AppendRaw(k, !m.hasCustomFormat(), m.appendMarshal); err != nil {
130 if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
131 return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON")
132 }
133 if !isSyntacticError(err) && !export.IsIOError(err) {
134 err = newMarshalErrorBefore(enc, t, err)
135 }
136 return err
137 }
138 return nil
139 }
140 fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) (err error) {
141 xd := export.Decoder(dec)
142 var u timeArshaler
143 if uo.Format != "" && uo.FormatDepth == xd.Tokens.Depth() {
144 if !u.initFormat(uo.Format) {
145 return newInvalidFormatError(dec, t, uo)
146 }
147 } else if uo.Flags.Get(jsonflags.FormatTimeWithLegacySemantics) {
148 u.looseRFC3339 = true
149 }
150
151 stringify := !u.isNumeric() || xd.Tokens.Last.NeedObjectName() || uo.Flags.Get(jsonflags.StringifyNumbers)
152 var flags jsonwire.ValueFlags
153 tt := va.Addr().Interface().(*time.Time)
154 val, err := xd.ReadValue(&flags)
155 if err != nil {
156 return err
157 }
158 switch k := val.Kind(); k {
159 case 'n':
160 if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) {
161 *tt = time.Time{}
162 }
163 return nil
164 case '"':
165 if !stringify {
166 break
167 }
168 val = jsonwire.UnquoteMayCopy(val, flags.IsVerbatim())
169 if err := u.unmarshal(val); err != nil {
170 if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
171 return err
172 }
173 return newUnmarshalErrorAfter(dec, t, err)
174 }
175 *tt = u.tt
176 return nil
177 case '0':
178 if stringify {
179 break
180 }
181 if err := u.unmarshal(val); err != nil {
182 if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
183 return err
184 }
185 return newUnmarshalErrorAfter(dec, t, err)
186 }
187 *tt = u.tt
188 return nil
189 }
190 return newUnmarshalErrorAfter(dec, t, nil)
191 }
192 }
193 return fncs
194 }
195
196 type durationArshaler struct {
197 td time.Duration
198
199
200
201
202
203 base uint64
204 }
205
206 func (a *durationArshaler) initFormat(format string) (ok bool) {
207 switch format {
208 case "units":
209 a.base = 0
210 case "sec":
211 a.base = 1e9
212 case "milli":
213 a.base = 1e6
214 case "micro":
215 a.base = 1e3
216 case "nano":
217 a.base = 1e0
218 default:
219 return false
220 }
221 return true
222 }
223
224 func (a *durationArshaler) isNumeric() bool {
225 return a.base != 0 && a.base != 60
226 }
227
228 func (a *durationArshaler) appendMarshal(b []byte) ([]byte, error) {
229 switch a.base {
230 case 0:
231 return append(b, a.td.String()...), nil
232 default:
233 return appendDurationBase10(b, a.td, a.base), nil
234 }
235 }
236
237 func (a *durationArshaler) unmarshal(b []byte) (err error) {
238 switch a.base {
239 case 0:
240 a.td, err = time.ParseDuration(string(b))
241 default:
242 a.td, err = parseDurationBase10(b, a.base)
243 }
244 return err
245 }
246
247 type timeArshaler struct {
248 tt time.Time
249
250
251
252
253
254
255 base uint64
256 format string
257
258 looseRFC3339 bool
259 }
260
261 func (a *timeArshaler) initFormat(format string) bool {
262
263
264 if len(format) == 0 {
265 return false
266 }
267 a.base = math.MaxUint
268 if c := format[0]; !('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z') {
269 a.format = format
270 return true
271 }
272 switch format {
273 case "ANSIC":
274 a.format = time.ANSIC
275 case "UnixDate":
276 a.format = time.UnixDate
277 case "RubyDate":
278 a.format = time.RubyDate
279 case "RFC822":
280 a.format = time.RFC822
281 case "RFC822Z":
282 a.format = time.RFC822Z
283 case "RFC850":
284 a.format = time.RFC850
285 case "RFC1123":
286 a.format = time.RFC1123
287 case "RFC1123Z":
288 a.format = time.RFC1123Z
289 case "RFC3339":
290 a.base = 0
291 a.format = time.RFC3339
292 case "RFC3339Nano":
293 a.base = 0
294 a.format = time.RFC3339Nano
295 case "Kitchen":
296 a.format = time.Kitchen
297 case "Stamp":
298 a.format = time.Stamp
299 case "StampMilli":
300 a.format = time.StampMilli
301 case "StampMicro":
302 a.format = time.StampMicro
303 case "StampNano":
304 a.format = time.StampNano
305 case "DateTime":
306 a.format = time.DateTime
307 case "DateOnly":
308 a.format = time.DateOnly
309 case "TimeOnly":
310 a.format = time.TimeOnly
311 case "unix":
312 a.base = 1e0
313 case "unixmilli":
314 a.base = 1e3
315 case "unixmicro":
316 a.base = 1e6
317 case "unixnano":
318 a.base = 1e9
319 default:
320
321 if strings.TrimFunc(format, isLetterOrDigit) == "" {
322 return false
323 }
324 a.format = format
325 }
326 return true
327 }
328
329 func (a *timeArshaler) isNumeric() bool {
330 return int(a.base) > 0
331 }
332
333 func (a *timeArshaler) hasCustomFormat() bool {
334 return a.base == math.MaxUint
335 }
336
337 func (a *timeArshaler) appendMarshal(b []byte) ([]byte, error) {
338 switch a.base {
339 case 0:
340 format := cmp.Or(a.format, time.RFC3339Nano)
341 n0 := len(b)
342 b = a.tt.AppendFormat(b, format)
343
344
345
346 switch b := b[n0:]; {
347 case b[len("9999")] != '-':
348 return b, errors.New("year outside of range [0,9999]")
349 case b[len(b)-1] != 'Z':
350 c := b[len(b)-len("Z07:00")]
351 if ('0' <= c && c <= '9') || parseDec2(b[len(b)-len("07:00"):]) >= 24 {
352 return b, errors.New("timezone hour outside of range [0,23]")
353 }
354 }
355 return b, nil
356 case math.MaxUint:
357 return a.tt.AppendFormat(b, a.format), nil
358 default:
359 return appendTimeUnix(b, a.tt, a.base), nil
360 }
361 }
362
363 func (a *timeArshaler) unmarshal(b []byte) (err error) {
364 switch a.base {
365 case 0:
366
367 if err := a.tt.UnmarshalText(b); err != nil {
368 return err
369 }
370
371
372
373
374
375 newParseError := func(layout, value, layoutElem, valueElem, message string) error {
376 return &time.ParseError{Layout: layout, Value: value, LayoutElem: layoutElem, ValueElem: valueElem, Message: message}
377 }
378 switch {
379 case a.looseRFC3339:
380 return nil
381 case b[len("2006-01-02T")+1] == ':':
382 return newParseError(time.RFC3339, string(b), "15", string(b[len("2006-01-02T"):][:1]), "")
383 case b[len("2006-01-02T15:04:05")] == ',':
384 return newParseError(time.RFC3339, string(b), ".", ",", "")
385 case b[len(b)-1] != 'Z':
386 switch {
387 case parseDec2(b[len(b)-len("07:00"):]) >= 24:
388 return newParseError(time.RFC3339, string(b), "Z07:00", string(b[len(b)-len("Z07:00"):]), ": timezone hour out of range")
389 case parseDec2(b[len(b)-len("00"):]) >= 60:
390 return newParseError(time.RFC3339, string(b), "Z07:00", string(b[len(b)-len("Z07:00"):]), ": timezone minute out of range")
391 }
392 }
393 return nil
394 case math.MaxUint:
395 a.tt, err = time.Parse(a.format, string(b))
396 return err
397 default:
398 a.tt, err = parseTimeUnix(b, a.base)
399 return err
400 }
401 }
402
403
404
405 func appendDurationBase10(b []byte, d time.Duration, pow10 uint64) []byte {
406 b, n := mayAppendDurationSign(b, d)
407 whole, frac := bits.Div64(0, n, uint64(pow10))
408 b = strconv.AppendUint(b, whole, 10)
409 return appendFracBase10(b, frac, pow10)
410 }
411
412
413
414 func parseDurationBase10(b []byte, pow10 uint64) (time.Duration, error) {
415 suffix, neg := consumeSign(b)
416 wholeBytes, fracBytes := bytesCutByte(suffix, '.', true)
417 whole, okWhole := jsonwire.ParseUint(wholeBytes)
418 frac, okFrac := parseFracBase10(fracBytes, pow10)
419 hi, lo := bits.Mul64(whole, uint64(pow10))
420 sum, co := bits.Add64(lo, uint64(frac), 0)
421 switch d := mayApplyDurationSign(sum, neg); {
422 case (!okWhole && whole != math.MaxUint64) || !okFrac:
423 return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrSyntax)
424 case !okWhole || hi > 0 || co > 0 || neg != (d < 0):
425 return 0, fmt.Errorf("invalid duration %q: %w", b, strconv.ErrRange)
426 default:
427 return d, nil
428 }
429 }
430
431
432 func mayAppendDurationSign(b []byte, d time.Duration) ([]byte, uint64) {
433 if d < 0 {
434 b = append(b, '-')
435 d *= -1
436 }
437 return b, uint64(d)
438 }
439
440
441 func mayApplyDurationSign(n uint64, neg bool) time.Duration {
442 if neg {
443 return -1 * time.Duration(n)
444 } else {
445 return +1 * time.Duration(n)
446 }
447 }
448
449
450
451 func appendTimeUnix(b []byte, t time.Time, pow10 uint64) []byte {
452 sec, nsec := t.Unix(), int64(t.Nanosecond())
453 if sec < 0 {
454 b = append(b, '-')
455 sec, nsec = negateSecNano(sec, nsec)
456 }
457 switch {
458 case pow10 == 1e0:
459 b = strconv.AppendUint(b, uint64(sec), 10)
460 return appendFracBase10(b, uint64(nsec), 1e9)
461 case uint64(sec) < 1e9:
462 b = strconv.AppendUint(b, uint64(sec)*uint64(pow10)+uint64(uint64(nsec)/(1e9/pow10)), 10)
463 return appendFracBase10(b, (uint64(nsec)*pow10)%1e9, 1e9)
464 default:
465 b = strconv.AppendUint(b, uint64(sec), 10)
466 b = appendPaddedBase10(b, uint64(nsec)/(1e9/pow10), pow10)
467 return appendFracBase10(b, (uint64(nsec)*pow10)%1e9, 1e9)
468 }
469 }
470
471
472
473 func parseTimeUnix(b []byte, pow10 uint64) (time.Time, error) {
474 suffix, neg := consumeSign(b)
475 wholeBytes, fracBytes := bytesCutByte(suffix, '.', true)
476 whole, okWhole := jsonwire.ParseUint(wholeBytes)
477 frac, okFrac := parseFracBase10(fracBytes, 1e9/pow10)
478 var sec, nsec int64
479 switch {
480 case pow10 == 1e0:
481 sec = int64(whole)
482 nsec = int64(frac)
483 case okWhole:
484 sec = int64(whole / pow10)
485 nsec = int64((whole%pow10)*(1e9/pow10) + frac)
486 case !okWhole && whole == math.MaxUint64:
487 width := int(math.Log10(float64(pow10)))
488 whole, okWhole = jsonwire.ParseUint(wholeBytes[:len(wholeBytes)-width])
489 mid, _ := parsePaddedBase10(wholeBytes[len(wholeBytes)-width:], pow10)
490 sec = int64(whole)
491 nsec = int64(mid*(1e9/pow10) + frac)
492 }
493 if neg {
494 sec, nsec = negateSecNano(sec, nsec)
495 }
496 switch t := time.Unix(sec, nsec).UTC(); {
497 case (!okWhole && whole != math.MaxUint64) || !okFrac:
498 return time.Time{}, fmt.Errorf("invalid time %q: %w", b, strconv.ErrSyntax)
499 case !okWhole || neg != (t.Unix() < 0):
500 return time.Time{}, fmt.Errorf("invalid time %q: %w", b, strconv.ErrRange)
501 default:
502 return t, nil
503 }
504 }
505
506
507 func negateSecNano(sec, nsec int64) (int64, int64) {
508 sec = ^sec
509 nsec = -nsec + 1e9
510 sec += int64(nsec / 1e9)
511 nsec %= 1e9
512 return sec, nsec
513 }
514
515
516
517 func appendFracBase10(b []byte, n, max10 uint64) []byte {
518 if n == 0 {
519 return b
520 }
521 return bytes.TrimRight(appendPaddedBase10(append(b, '.'), n, max10), "0")
522 }
523
524
525
526 func parseFracBase10(b []byte, max10 uint64) (n uint64, ok bool) {
527 switch {
528 case len(b) == 0:
529 return 0, true
530 case len(b) < len(".0") || b[0] != '.':
531 return 0, false
532 }
533 return parsePaddedBase10(b[len("."):], max10)
534 }
535
536
537
538 func appendPaddedBase10(b []byte, n, max10 uint64) []byte {
539 if n < max10/10 {
540
541
542 i := len(b)
543 b = strconv.AppendUint(b, n+max10/10, 10)
544 b[i]--
545 return b
546 }
547 return strconv.AppendUint(b, n, 10)
548 }
549
550
551
552
553
554 func parsePaddedBase10(b []byte, max10 uint64) (n uint64, ok bool) {
555 pow10 := uint64(1)
556 for pow10 < max10 {
557 n *= 10
558 if len(b) > 0 {
559 if b[0] < '0' || '9' < b[0] {
560 return n, false
561 }
562 n += uint64(b[0] - '0')
563 b = b[1:]
564 }
565 pow10 *= 10
566 }
567 if len(b) > 0 && len(bytes.TrimRight(b, "0123456789")) > 0 {
568 return n, false
569 }
570 return n, true
571 }
572
573
574 func consumeSign(b []byte) ([]byte, bool) {
575 if len(b) > 0 && b[0] == '-' {
576 return b[len("-"):], true
577 }
578 return b, false
579 }
580
581
582
583 func bytesCutByte(b []byte, c byte, include bool) ([]byte, []byte) {
584 if i := bytes.IndexByte(b, c); i >= 0 {
585 if include {
586 return b[:i], b[i:]
587 }
588 return b[:i], b[i+1:]
589 }
590 return b, nil
591 }
592
593
594
595 func parseDec2(b []byte) byte {
596 if len(b) < 2 {
597 return 0
598 }
599 return 10*(b[0]-'0') + (b[1] - '0')
600 }
601
View as plain text