Skip to content

[release/11.0] Fix DateTime.ToUniversalTime for invalid local times in the DST gap - #135071

Merged
tarekgh merged 1 commit into
release/11.0from
backport/pr-134871-to-release/11.0
Oct 2, 2026
Merged

tarekgh merged 1 commit into
release/11.0from
backport/pr-134871-to-release/11.0

Conversation

@github-actions

@github-actions github-actions Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Backport of #134871 to release/11.0

/cc @tarekgh

Customer Impact

  • 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

  • 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.

…134871)

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. Europe`
`02: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.

Fixes #134846

---------

Co-authored-by: Tarek Mahmoud Sayed <tarekms@ntdev.microsoft.com>
@azure-pipelines

Copy link
Copy Markdown
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.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-datetime
See info in area-owners.md if you want to be subscribed.

@tarekgh tarekgh added the Servicing-consider Issue for next servicing release review label Oct 1, 2026
@tarekgh tarekgh self-assigned this Oct 1, 2026
@tarekgh tarekgh added this to the 11.0.0 milestone Oct 2, 2026
@tarekgh tarekgh added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Oct 2, 2026
@tarekgh

tarekgh commented Oct 2, 2026

Copy link
Copy Markdown
Member

Approved offline by email.

@tarekgh

tarekgh commented Oct 2, 2026

Copy link
Copy Markdown
Member

/ba-g failures are unrelated

@tarekgh
tarekgh merged commit 4d40922 into release/11.0 Oct 2, 2026
147 of 153 checks passed
@tarekgh
tarekgh deleted the backport/pr-134871-to-release/11.0 branch October 2, 2026 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.DateTime Servicing-approved Approved for servicing release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants