Skip to content

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

@shapea

Description

@shapea

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

Metadata

Metadata

Assignees

Labels

area-System.DateTimein-prThere is an active PR which will close this issue when it is merged

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions