Ctrl K
ComunidadGuías…

types/jsonformat/duration.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// Copyright (c) Tailscale Inc & contributors
// SPDX-License-Identifier: BSD-3-Clause

package jsonformat

import (
	"time"

	"github.com/go-json-experiment/json"
	"github.com/go-json-experiment/json/jsontext"
)

// DurationNano is a [time.Duration] that represents a duration as
// a JSON number of nanoseconds. If [json.StringifyNumbers] is specified,
// then it represents the duration as a JSON number within a JSON string.
//
// This format is what v1 [encoding/json] historically used for durations.
// It is not recommended that newly defined types represent durations
// using this format, as a standalone JSON number lacks context
// as to the units of the duration.
type DurationNano struct{ time.Duration }

func (d DurationNano) MarshalJSON() ([]byte, error) {
	return json.Marshal(d)
}

func (d DurationNano) MarshalJSONTo(enc *jsontext.Encoder) error {
	// Marshaling as an int64 directly allows us to properly handle
	// the [json.StringifyNumbers] option.
	return json.MarshalEncode(enc, int64(d.Duration))
}

func (d *DurationNano) UnmarshalJSON(b []byte) error {
	return json.Unmarshal(b, d)
}

func (d *DurationNano) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
	// Unmarshaling into an int64 directly allows us to properly handle
	// the [json.StringifyNumbers] option.
	return json.UnmarshalDecode(dec, (*int64)(&d.Duration))
}

// DurationUnits is a [time.Duration] that represents a duration as
// a JSON string using the format of [time.Duration.String].
//
// While this format is human-readable (e.g., "43m17.152s"),
// it is also highly specific to the Go ecosystem
// (and not used elsewhere in the industry).
type DurationUnits struct{ time.Duration }

func (d DurationUnits) MarshalJSON() ([]byte, error) {
	return json.Marshal(d)
}

func (d DurationUnits) MarshalJSONTo(enc *jsontext.Encoder) error {
	b := enc.AvailableBuffer()
	b = append(b, '"')
	b = append(b, d.Duration.String()...)
	b = append(b, '"')
	return enc.WriteValue(b)
}

func (d *DurationUnits) UnmarshalJSON(b []byte) error {
	return json.Unmarshal(b, d)
}

func (d *DurationUnits) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
	isNull := dec.PeekKind() == 'n'
	var s string
	if err := json.UnmarshalDecode(dec, &s); err != nil {
		return err
	}
	if isNull {
		d.Duration = 0
		return nil
	}
	var err error
	d.Duration, err = time.ParseDuration(s)
	return err
}

// DurationISO8601 is a [time.Duration] that represents a duration as
// a JSON string using a subset of the ISO 8601 format.
// In particular, it uses the exact grammar of ISO 8601 that JavaScript
// uses for its Temporal.Duration type.
//
// While this format is relatively novel in the Go ecosystem,
// the fact that JSON finds its heritage in JavaScript and that
// JavaScript has adopted ISO 8601 as the JSON representation for durations
// suggests that JavaScript's particular flavor of ISO 8601 may well become
// the de facto standard for representing durations across the industry.
type DurationISO8601 struct{ time.Duration }

func (d DurationISO8601) MarshalJSON() ([]byte, error) {
	return json.Marshal(d)
}

func (d DurationISO8601) MarshalJSONTo(enc *jsontext.Encoder) error {
	b := enc.AvailableBuffer()
	b = append(b, '"')
	b = appendDurationISO8601(b, d.Duration)
	b = append(b, '"')
	return enc.WriteValue(b)
}

func (d *DurationISO8601) UnmarshalJSON(b []byte) error {
	return json.Unmarshal(b, d)
}

func (d *DurationISO8601) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
	isNull := dec.PeekKind() == 'n'
	var s string
	if err := json.UnmarshalDecode(dec, &s); err != nil {
		return err
	}
	if isNull {
		d.Duration = 0
		return nil
	}
	var err error
	d.Duration, err = parseDurationISO8601([]byte(s))
	return err
}