Skip to content

Format UTC offsets with the invariant culture - #1854

Merged
SimonCropp merged 2 commits into
mainfrom
fix-negative-offset-culture
Aug 17, 2026
Merged

Format UTC offsets with the invariant culture#1854
SimonCropp merged 2 commits into
mainfrom
fix-negative-offset-culture

Conversation

@SimonCropp

Copy link
Copy Markdown
Member

GetDateOffset in src/Verify/Serialization/DateFormatter_DateTimeOffset.cs built the offset with plain interpolation, so the numbers went through CurrentCulture, while every other part of the rendered date in that file passes Culture.InvariantCulture explicitly.

NumberFormatInfo.NegativeSign is not - everywhere:

Culture Negative sign -01:30 renders as
invariant / en-US U+002D -1-30
sv-SE U+2212 −1−30
ar-SA U+061C U+002D ؜-1؜-30
fa-IR U+200E U+2212 ‎−1‎−30

Only negative offsets are affected; the positive and zero branches write a literal +.

Impact

The string reaches two places.

  • Snapshot content, via DateFormatter.Convert. A DateTimeOffset serialized on a Swedish machine differs from the one committed from an en-US machine even though the values are equal.
  • Parameter file names, via DateFormatter.ToParameterString. The verified file for a parameter with offset -05:00 is looked up under a name that machine can never produce a match for, so the test reports the snapshot as new on every run.

Change

The four interpolations now go through FormattableString.Invariant, which keeps the format strings in place and is available on every target framework down to net462. Output under the invariant culture is byte identical, so no existing snapshot moves.

Test

DateFormatterTests.OffsetDoesNotTakeTheCurrentCultureNegativeSign pins all five branches (-1.5, -5, +1.5, +5, 0) against expected literals while CurrentCulture carries U+2212 as its negative sign. The sign is assigned onto a clone of the invariant culture rather than picking a real culture, so the assertion does not move with the ICU data the test runs against.

Confirmed the test fails on unpatched source (both negative cases, positives unaffected) and passes after. Full Verify.Tests suite green: 1304 passed, 0 failed. Verify.csproj builds clean across all nine target frameworks.

GetDateOffset built the offset with plain interpolation, so the numbers went
through CurrentCulture while every other part of the rendered date passed
Culture.InvariantCulture explicitly.

NumberFormatInfo.NegativeSign is not "-" everywhere. sv-SE renders U+2212
MINUS SIGN, ar-SA prefixes U+061C ARABIC LETTER MARK, and fa-IR uses
U+200E + U+2212. Only negative offsets are affected, since the positive and
zero branches write a literal "+".

The string reaches two places. As snapshot content, via Convert, a
DateTimeOffset serialized on a Swedish machine differs from the one committed
from an en-US machine even though the values are equal. As a parameter file
name, via ToParameterString, the verified file for offset -05:00 is looked up
under a name that machine can never produce a match for.
@SimonCropp SimonCropp added this to the 32.0.0 milestone Aug 17, 2026
@SimonCropp
SimonCropp merged commit 1e6d61e into main Aug 17, 2026
1 of 3 checks passed
@SimonCropp
SimonCropp deleted the fix-negative-offset-culture branch August 17, 2026 13:33
This was referenced Aug 26, 2026
This was referenced Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants