feat(duration): add ISO 8601 / RFC 3339 duration format (duration-iso8601)#284
Merged
Merged
Conversation
…8601) * closes go-openapi#278 Adds first-class support for the JSON Schema draft 2020-12 "duration" format (RFC 3339 Appendix A: P1Y2M3DT4H5M6S, P2W, ...) alongside the existing human-readable Duration, without breaking it. Type & parser - New generic type ISODuration[P ISODurationPolicy] with phantom, zero-size policies DurationStrict / DurationLenient, and the strict alias DurationISO8601 = ISODuration[DurationStrict]. - Single-pass, zero-allocation parser enforcing strict RFC 3339 App. A by default (component ordering & anchoring, W-exclusivity, ASCII digits, no fraction/sign/whitespace). Per-rule leniency is opt-in on the explicit ParseISO8601Duration(s, ...opts) path only -- never the registry/struct-field decode path, which must stay unambiguous. - Overflow handled with the stdlib/duration.go discipline: bound the integer part to 1<<63 before multiplying, then check after the fractional add, so the fraction path cannot silently wrap (MaxInt64/MinInt64 are exact). Serialization - JSON, Text (policy-aware emit: a strict value errors rather than emit output a strict parser would reject; String stays lossless for display), SQL (Scan/Value as int64 nanoseconds), and BSON. - BSON is treated as a storage boundary (lossless via String + a lenient parse-back), so values a strict policy refuses to emit on the text/JSON path (a sign, sub-second precision) still round-trip through storage. Registration - Registered under the distinct handle "duration-iso8601"; "duration" keeps mapping to the human-readable Duration (non-breaking). - Registered under the distinct handle "duration-human": the "human readable" (existing duration) - Modified the existing Default Registry so that "duration-human" remains the default mapping for "duration" - Added a new pre-built Registry (JSONSchema2020Registry) for which "duration-iso8601" becomes the default mapping for "duration" Prerequisites: - Prerequisite refactor: MapStructureHookFunc now decodes via encoding.TextUnmarshaler (reflect.New + UnmarshalText), removing the hand-maintained decodeFormatFromString switch so new formats need no edits there and the json / mapstructure paths stop diverging. Other additions: - conv.DurationISO8601 / conv.DurationISO8601Value helpers. Tests & tooling - Strict parser passes all 36 cases of the vendored JSON Schema Test Suite (testdata/jsonschema-suite/duration.json); plus lenient/options/value- semantics/overflow, registry/SQL/BSON, and a fuzz corpus (temporal bucket, including overflow boundaries). - Postgres / MariaDB / Mongo (both the bsonlite and real-driver codecs) integration tests. - Benchmarks confirm zero-alloc parsing in the same order of magnitude as time.ParseDuration. Also fixes benchmarkIs to rotate its input set (b.Loop() keeps b.N constant during the loop, so the prior index pinned one element). - Add testable examples for the ISO 8601 duration format. This documents the new API surface introduced with the duration-iso8601 format as godoc-rendered runnable examples (external strfmt_test package): Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #284 +/- ##
==========================================
+ Coverage 87.81% 88.22% +0.41%
==========================================
Files 18 22 +4
Lines 2471 2778 +307
==========================================
+ Hits 2170 2451 +281
- Misses 208 221 +13
- Partials 93 106 +13 ☔ View full report in Codecov by Harness. |
This was referenced Jul 14, 2026
Closed
Contributor
|
Thank you |
ccoVeille
reviewed
Jul 14, 2026
| ## Durations | ||
|
|
||
| We have 2 very different definitions of the "duration" format: the "human-readable" duration that used to be just "duration", | ||
| and the new "duration-iso8601". There is no "dual" parser that accepts both formats: types are specialzed. |
Contributor
There was a problem hiding this comment.
Typo
Suggested change
| and the new "duration-iso8601". There is no "dual" parser that accepts both formats: types are specialzed. | |
| and the new "duration-iso8601". There is no "dual" parser that accepts both formats: types are specialized. |
Comment on lines
+340
to
+343
| if neg { | ||
| return -time.Duration(total), nil | ||
| } | ||
| return time.Duration(total), nil |
Member
Author
There was a problem hiding this comment.
sorry Christophe I lost track of your comment there. What is wrong with this expression ?
Contributor
There was a problem hiding this comment.
It's OK, you replied here
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds first-class support for the JSON Schema draft 2020-12 "duration" format (RFC 3339 Appendix A: P1Y2M3DT4H5M6S, P2W, ...) alongside the existing human-readable Duration, without breaking it.
Type & parser
Serialization
Registration
Prerequisites:
Other additions:
Tests & tooling
Change type
Please select: 🆕 New feature or enhancement|🔧 Bug fix'|📃 Documentation update
Short description
Fixes
Full description
Checklist