You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixes the DateTime.ToUniversalTime() regression for Local values that fall in the spring-forward DST gap (an invalid time).
The invalid-time fallback in TimeZoneInfo.ConvertTime added the base UTC offset instead of subtracting it, so an invalid local time was converted to a UTC value two offsets too high (for example W. Europe02:30 became 03:30Z instead of 01:30Z). The result now subtracts the offset and agrees with TimeZoneInfo.Local.GetUtcOffset and new DateTimeOffset(local).UtcDateTime.
Added a regression test that sets the local time zone and verifies the invalid-time conversion for several European zones.
The invalid-time fallback in TimeZoneInfo.ConvertTime added the base UTC
offset instead of subtracting it, so ToUniversalTime on a Local value in
the spring-forward gap returned a UTC value two offsets too high. Subtract
the offset so the result matches GetUtcOffset and DateTimeOffset.
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.
…conversion
Resolve the applicable adjustment rule when converting an invalid (DST gap) local time to UTC so zones that changed their standard offset over time (non-zero BaseUtcOffsetDelta) convert correctly. Strengthen the regression test with a negative-offset zone, independent literal expectations, and the Europe/Lisbon 1993 historical case.
Return the applicable standard offset (base plus BaseUtcOffsetDelta) for invalid local times in GetUtcOffset so GetUtcOffset and DateTimeOffset stay consistent with ConvertTime/ToUniversalTime for zones that changed their standard offset over time.
Constructing a DateTime here makes an out-of-range conversion throw before the existing clamping path runs. DateTime.ToUniversalTime() promises MinValue/MaxValue when the UTC result is outside the representable range, and the implementation before the transition-cache rewrite carried raw UTC ticks into its clamp. Keep the raw tick value so the SafeCreateDateTimeFromTicks calls below preserve that contract.
Resolve the adjustment rule for an invalid (DST gap) local time using the
rule adjacent to the exact timestamp rather than by calendar year. Zones that
change their standard offset between two rules within the same year (for
example southern-hemisphere zones that begin a year in daylight saving time)
could otherwise pick the wrong rule and compute the gap offset incorrectly.
The new FindRuleIndexForLocalTime binary search reuses the existing
CompareAdjustmentRuleToDateTime comparison; FindRuleForYear is left unchanged.
The Europe/Lisbon 1993 spring-forward gap conversion is wrong on IANA in
both .NET 10 and .NET 11 (a long-standing historical-offset bug), so it is
not part of the issue dotnet#134846 regression and does not belong with these
regression rows. The remaining rows cover the actual regression fix.
The invalid-time regression test body runs inside a RemoteExecutor child
process that exits immediately after the delegate, so restoring the TZ
environment variable and clearing the cache in a finally block is dead
work. Set TZ and clear the cache once at the top.
…n the DST gap (#135071)
Backport of #134871 to release/11.0
/cc @tarekgh
## Customer Impact
- [x] Customer reported
- [ ] Found internally
#134846
In .NET 11, converting a local `DateTime` in the daylight-saving
spring-forward gap to UTC returns the wrong value - `ToUniversalTime()`,
`DateTimeOffset`, and `GetUtcOffset()` add the offset instead of
subtracting it, landing off by roughly twice the UTC offset. It's a
silent regression from .NET 10 (no exception, just wrong data), which
can misorder events or corrupt timestamps in scheduling, logging,
billing, and calendar scenarios.
## Regression
- [x] Yes
- [ ] No
The regression came from the `TimeZoneInfo` rewrite in .NET 11 #119662 .
That change reworked how invalid (DST-gap) local times are converted,
and in the rewritten invalid-time fallback the standard UTC offset was
added instead of subtracted - a sign error. Before the rewrite the
offset was subtracted correctly; afterward, any local time in the
spring-forward gap converts to the wrong UTC instant (off by roughly
twice the offset). The .NET 10 code path did not have this error, which
is why it's a 10→11 regression.
## Testing
Verified the failing scenario, added a new test to cover the failing
scenario, passing all regression tests.
## Risk
Low
This change touches an extremely narrow scenario: only local times that
fall inside a daylight-saving spring-forward gap - times the wall clock
skips and that rarely occur in practice. Every valid time, ambiguous
time, and modern time zone is completely unaffected; the result changes
solely for cases that were already returning wrong answers. It reuses
existing, vetted rule-comparison logic rather than new math and leaves
all hot paths untouched. The worst case is no change, and the expected
case is a correct result replacing silent corruption - so accepting it
is low risk.
Co-authored-by: Tarek Mahmoud Sayed <10833894+tarekgh@users.noreply.github.com>
Co-authored-by: Tarek Mahmoud Sayed <tarekms@ntdev.microsoft.com>
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
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.
Fixes the
DateTime.ToUniversalTime()regression forLocalvalues that fall in the spring-forward DST gap (an invalid time).The invalid-time fallback in
TimeZoneInfo.ConvertTimeadded the base UTC offset instead of subtracting it, so an invalid local time was converted to a UTC value two offsets too high (for exampleW. Europe02:30became03:30Zinstead of01:30Z). The result now subtracts the offset and agrees withTimeZoneInfo.Local.GetUtcOffsetandnew DateTimeOffset(local).UtcDateTime.Added a regression test that sets the local time zone and verifies the invalid-time conversion for several European zones.
Fixes #134846