fmt/strtime: some tweaks to %y and %s handling#432
Merged
BurntSushi merged 3 commits intomasterfrom Oct 17, 2025
Merged
Conversation
Previously, it was possible for lenient formatting to still error when the formatting string contained invalid UTF-8. This commit alleviates that error condition by writing a replacement character instead. This required tweaking our UTF-8 decoding routines so that we could implement the "substitution by maximal subparts" strategy for lossy decoding. This now means that lenient formatting can only fail when writing to the underlying writer fails.
Previously, these would fail if the year wasn't in the range `1969-2068`. This was done because parsing fails for the same reason, and it seemed like good sense to have parsing and formatting be consistent with one another. ... however, this is the *only* formatting specifier that can yield an error based on the specific values provided. In contrast, all other errors are tied to either the validity of the formatting string or if all relevant data is provided (i.e., you get an error if you use `%y` and your `BrokenDownTime` doesn't have a way to get the year). I don't think this aberration is worth it. I think it's better to be able to say the two broad error categories and be able to stick to them. This should also hopefully avoid accidental panics, since now the only error conditions that result in, say, `Zoned::strftime` panicking are limited to the format string itself. Fixes #428
…re consistent Specifically, all of the other higher level constructors on `BrokenDownTime` already try their "hardest" to produce the requested value. Notably, both `BrokenDownTime::to_date` and `BrokenDownTime::to_time` go to some effort to achieve this. However, `BrokenDownTime::to_timestamp` wasn't doing everything it could. Namely, it was completely ignoring its internal `timestamp` field. This is weird and inconsistent from how the rest of the constructors worked. I think this is overall more flexible as well. Because it means that parsing `%s` is, at the level of the individual pieces of data inside a `BrokenDownTime`, completely separate from everything else. So you don't have any weird overwriting behavior at the lowest levels. I started thinking about this in #428. While I don't think the motivation in #428 is that compelling, it got me thinking more deeply about how a `BrokenDownTime` deals with timestamps. I think we got to this state because I bolted `%s` on to `fmt::strtime` and didn't think deeply about it. Fixes #428
96fc57f to
2e5a079
Compare
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.
This PR bundles together three related changes:
%yno longer errors when its year value is outside therange supported by parsing
%y. This brings it more into line withGNU's
strftimebehavior and also removes the singular reason forJiff's
strftimeformatting to fail based on the specific data values.when the formatting string is invalid UTF-8. Instead, it will silently
automatically lossily decode it. Lenient formatting will now only ever
return an error when writing to the provided writer fails.
BrokenDownTime's explicitly set timestamp field is now used ina way that is consistent with other data. It's a bit weird because it
isn't in conflict with any one other field, but rather, to an aggregate
of other fields (a civil datetime + offset/time zone). Previously, we
would let
%sand, say,%F %zoverride one another. Now they areseparate and the higher level constructors (
to_timestamp,to_zoned)now prefer an explicitly set timestamp when present.
Fixes #428