Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DateTime.Parse uses Local instead of UTC timestamp for time-only strings with DateTimeStyle.AssumeUniversal #111689

Closed
shapea opened this issue Jan 22, 2025 · 1 comment · Fixed by #111729
Assignees
Labels
area-System.DateTime in-pr There is an active PR which will close this issue when it is merged
Milestone

Comments

@shapea
Copy link

shapea commented Jan 22, 2025

Description

There appears to be an 11-year-old bug in the .NET DateTime.Parse() methods for handling time-only strings when passing in DateTimeStyle.AssumeUnivesal. Per the documentation, the Parse() method should be honoring the passed in style, but when stepping through .NET code it clearly ignores this.

Reproduction Steps

Use a debugger to step through DateTime.Parse("13:30", null, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal) in a debugger.

When stepping through, due to using a time-only string, it lands within the following method inside DateTimeParse.cs:

        private static DateTime GetDateTimeNow(scoped ref DateTimeResult result, scoped ref DateTimeStyles styles)
        {
            if ((result.flags & ParseFlags.CaptureOffset) != 0)
            {
                if ((result.flags & ParseFlags.TimeZoneUsed) != 0)
                {
                    // use the supplied offset to calculate 'Now'
                    return new DateTime(DateTime.UtcNow.Ticks + result.timeZoneOffset.Ticks, DateTimeKind.Unspecified);
                }
                else if ((styles & DateTimeStyles.AssumeUniversal) != 0)
                {
                    // assume the offset is Utc
                    return DateTime.UtcNow;
                }
            }

            // assume the offset is Local
            return DateTime.Now;
        }

The input resulting parameters from the DateTime.Parse() call above contain result.flags = ParseFlags.HaveTime and styles = DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal. Note that with this combination, the entire branch is skipped because a time-only string doesn't contain a capture offset. The requested styles are completely ignored and local time is used, which breaks documented convention.

Expected behavior

The expectation here is to use UTC when DateTimeStyles.AssumeUniversal is used instead of Local, per documentation:

https://learn.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=net-9.0#system-datetime-parse(system-string-system-iformatprovider-system-globalization-datetimestyles)
https://learn.microsoft.com/en-us/dotnet/api/system.globalization.datetimestyles?view=net-9.0#system-globalization-datetimestyles-assumeuniversal

Actual behavior

The observed behavior is that Local time is used even when DateTimeStyles.AssumeUniversal is specified.

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Jan 22, 2025
Copy link
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 this to the Future milestone Jan 23, 2025
@dotnet-policy-service dotnet-policy-service bot added the in-pr There is an active PR which will close this issue when it is merged label Jan 23, 2025
@tarekgh tarekgh removed the untriaged New issue has not been triaged by the area owner label Jan 23, 2025
@tarekgh tarekgh modified the milestones: Future, 10.0.0 Jan 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.DateTime in-pr There is an active PR which will close this issue when it is merged
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants