Source file src/encoding/json/internal/jsonopts/options_format.go
1 // Copyright 2026 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build goexperiment.jsonv2 6 7 package jsonopts 8 9 // NOTE: While [ExperimentalSupportFormatTag] is exported, 10 // it is in an internal package and thus inaccessible for public use. 11 // 12 // The [github.com/go-json-experiment/json] module is kept in sync 13 // with the Go standard standard library and will expose this option 14 // in a way that public code can now directly reference. 15 16 type supportFormatTag struct { 17 Options 18 v bool 19 } 20 21 var ( 22 enableFormatTag = supportFormatTag{v: true} 23 disableFormatTag = supportFormatTag{v: false} 24 ) 25 26 // ExperimentalSupportFormatTag is a marker method that is specially 27 // recognized by the "encoding/json/v2" runtime. 28 func (o *supportFormatTag) ExperimentalSupportFormatTag() bool { 29 return o.v 30 } 31 32 // ExperimentalSupportFormatTag enables support for the `format` tag. 33 // 34 // WARNING: This is an experimental feature and will be removed in the future 35 // as either a failed experiment or be formally included in "encoding/json/v2" 36 // in some semantically similar form, in which case, users of this option 37 // must migrate to the officially supported feature. 38 // 39 // The `format` tag was originally part of the "encoding/json/v2" experiment 40 // but support for it was removed (see https://go.dev/issue/79071) for the 41 // initial release of "encoding/json/v2" in light of the anticipation that 42 // the Go language might support typed struct tags (https://go.dev/issue/74472). 43 // 44 // Typed struct tags are a more expressive and type-safe way to express format 45 // attributes than the bespoke `format` tag option that implements a miniature 46 // domain-specific language (DSL) within the "json" package itself. 47 // 48 // While "encoding/json/v2" was in the experimental phase, 49 // some users were already depending on the `format` tag option. 50 // This experimental option exists to provide a temporary workaround 51 // until the (hopeful) inclusion of typed struct tags and support for 52 // formatting directives in "encoding/json/v2" using that language mechanism. 53 // 54 // This option enables support for the `format` tag option, which specifies 55 // a format flag used to specialize the formatting of the field value. 56 // The option is a key-value pair specified as "format:value" where 57 // the value must be either a literal consisting of letters and numbers 58 // (e.g., `format:RFC3339`) or a single-quoted string literal 59 // (e.g., `format:'2006-01-02'`). The interpretation of the format flag 60 // is determined by the struct field type. 61 // 62 // Go types with alternative representations are as follows: 63 // 64 // - A Go []byte or [N]byte is usually represented as a JSON string 65 // containing the binary value encoded using RFC 4648. 66 // If the format is "base64" or unspecified, then this uses RFC 4648, section 4. 67 // If the format is "base64url", then this uses RFC 4648, section 5. 68 // If the format is "base32", then this uses RFC 4648, section 6. 69 // If the format is "base32hex", then this uses RFC 4648, section 7. 70 // If the format is "base16" or "hex", then this uses RFC 4648, section 8. 71 // If the format is "array", then the bytes value is represented as a JSON array 72 // where each element recursively uses the JSON representation of each byte. 73 // 74 // - A Go float is usually represented as a JSON number. 75 // If the format is "nonfinite", then NaN, +Inf, and -Inf are represented as 76 // the JSON strings "NaN", "Infinity", and "-Infinity", respectively. 77 // Without the use of this format, such string values result in a [SemanticError]. 78 // 79 // - A nil Go map is usually encoded using an empty JSON object. 80 // If the format is "emitnull", then a nil map is encoded as a JSON null. 81 // If the format is "emitempty", then a nil map is encoded as an empty JSON object, 82 // regardless of whether [FormatNilMapAsNull] is specified. 83 // 84 // - A nil Go slice is usually encoded using an empty JSON array. 85 // If the format is "emitnull", then a nil slice is encoded as a JSON null. 86 // If the format is "emitempty", then a nil slice is encoded as an empty JSON array, 87 // regardless of whether [FormatNilSliceAsNull] is specified. 88 // 89 // - A Go pointer usually uses the JSON representation of the underlying value. 90 // The format is forwarded to the marshaling and unmarshaling of the underlying type. 91 // 92 // - A Go [time.Time] is usually represented as a JSON string containing 93 // the timestamp formatted in RFC 3339 with nanosecond precision. 94 // If the format matches one of the format constants declared 95 // in the time package (e.g., RFC1123), then that format is used. 96 // If the format is "unix", "unixmilli", "unixmicro", or "unixnano", 97 // then the timestamp is represented as a possibly fractional JSON number 98 // of the number of seconds (or milliseconds, microseconds, or nanoseconds) 99 // since the Unix epoch, which is January 1st, 1970 at 00:00:00 UTC. 100 // To avoid a fractional component when encoding, 101 // round the timestamp to the relevant unit. 102 // Otherwise if non-empty, the format is used as-is and 103 // encoded using [time.Time.Format] and 104 // decoded using [time.Time.Parse]. 105 // 106 // - A Go [time.Duration] usually has no default representation. 107 // If the format is "sec", "milli", "micro", or "nano", 108 // then the duration is represented as a possibly fractional JSON number 109 // of the number of seconds (or milliseconds, microseconds, or nanoseconds). 110 // To avoid a fractional component when encoding, 111 // round the duration to the relevant unit. 112 // If the format is "units", it is represented as a JSON string 113 // encoded using [time.Duration.String] and decoded using [time.ParseDuration] 114 // (e.g., "1h30m" for 1 hour 30 minutes). 115 // If the format is "iso8601", it is represented as a JSON string using the 116 // ISO 8601 standard for durations (e.g., "PT1H30M" for 1 hour 30 minutes) 117 // using only accurate units of hours, minutes, and seconds. 118 func ExperimentalSupportFormatTag(v bool) Options { 119 if v { 120 return &enableFormatTag 121 } else { 122 return &disableFormatTag 123 } 124 } 125