Replace the exception-driven datetime format trial loop with tryparse - #105
Merged
Merged
Conversation
str2zoneddatetime/str2datetime/str2date tried each of 18 hardcoded DateFormats via try/catch until one worked. For inputs matching a format partway through the list (any RFC3339 string with fractional seconds, e.g.), every earlier attempt threw and caught a real exception before the winning one ran -- 200-600x slower than a single successful parse. Swap tryparse (nothing on failure) for try/catch, and give str2zoneddatetime its own filtered+reordered format list: half the shared formats have no z specifier and can never build a ZonedDateTime, so they're dropped from its loop instead of being tried and discarded every call. str2datetime/str2date keep the original format order untouched, so no case that used to hit its match early gets slower. Acceptance is unchanged: same formats accepted, same values produced, same error on unparseable input.
Contributor
Author
|
We are hitting massive performance issues on this. I read the proposed change for 1.0 release but this is a valid fix that can live in the 0.2 world |
jd-lara
added a commit
to Sienna-Platform/PowerOpenAPIModels
that referenced
this pull request
Aug 21, 2026
0.2.8 carries the tryparse-based datetime parsing (JuliaComputing/OpenAPI.jl#105); older releases pay an exception-driven format trial per timestamp field.
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.
Problem
str2zoneddatetime/str2datetime/str2datetry each of 18 hardcodedDateFormats in a fixed order via try/catch, moving to the next format on any exception. Any input that only matches a format partway through the list (e.g. RFC3339 with a fractional-second component) throws and catches a real Julia exception on every earlier attempt before the winning one runs.Measured on RFC3339 timestamps (Julia 1.12, TimeZones 1.22):
str2zoneddatetimetook ~430 µs (no fraction) to ~750 µs (ms fraction), and up to ~1.8 ms in the worst case (18 failed formats, then a Date fallback) — vs ~1 µs for a single successfultryparse. This function runs once per timestamp field on every OpenAPI deserialization; in a real time-series-heavy workload it was ~92% of a warm document export/import cycle.Fix
Replace try/catch with
tryparse(T, str, fmt)— Dates/TimeZones already support this forT<:TimeType, returningnothingon failure instead of throwing. Same trial order, same acceptance, zero exceptions on failing attempts.str2zoneddatetimeadditionally gets its own format list (ZONED_DATETIME_FORMATS): 9 of the 18 shared formats have nozspecifier and can never build aZonedDateTime(verified:ZonedDateTime(str, fmt)always throws for those regardless of input), so they're dropped from its trial loop.str2datetime/str2datekeep the original, unreordered 18-format list — reordering it caused a real regression on the date-only case (198 ns → 480 ns, since that shape used to hit format #1 immediately), so that list is untouched and the reorder+filter win is confined to the new zoned-only list.Numbers
End-to-end (RTS-GMLC power-system export via a downstream OpenAPI-model pipeline, warm
to_file): 848 ms → 142 ms overall (5.97x); the time-series row deserialization segment specifically: 783 ms → 71 ms (11x).Correctness
@test_throwscoverage for the not-parseable-input path (previously uncovered).test_date()combinatorial test (2 dates × 2 separators × 5 time precisions × 4 timezones, through bothstr2zoneddatetimeandstr2datetime) already covers every format family and passes unchanged.reduce_to_ms_precision) string, they produce an identical parsed value — so changing trial order only changes how many candidates are tried before success, never which value comes out.Compat
No dependency/compat changes.
tryparse(::Type{T}, str, fmt) where T<:TimeTypeis Dates stdlib machinery thatZonedDateTimealready satisfies via the sameDates.tryparsenexthooks backing theZonedDateTime(str, fmt)constructor this file already uses — present across the wholeTimeZones = "1"range and unaffected byjulia = "1.6".