4

Today, I observed some strange behavior in the DateTime.Parse(String) method when running on different servers. This can be observed in different online C# compilers.

My input in the yyyy-MM-ddTHH:mm:ssZ format. Example: lets use 2020-02-12T16:57:36Z which converted to ticks is: 637171234560000000 (converted using https://tickstodatetime.azurewebsites.net/)

This is the code I use for testing this behavior:

DateTime parsedDateTime = DateTime.Parse("2020-02-12T16:57:36Z");
Console.WriteLine(parsedDateTime + " " + parsedDateTime.Kind.ToString() + " " + parsedDateTime.Ticks);

On https://dotnetfiddle.net/akuyiI, it returns 02/12/2020 16:57:36 Local 637171234560000000.

On https://rextester.com/XWH12209, it returns 12.02.2020 17:57:36 Local 637171270560000000

I understand that the DateTime is parsed into local timezone and displayed in local time, but why the number of ticks is also different between systems?

Dongminator
  • 795
  • 10
  • 15
  • Those ticks represent times that are exactly ONE HOUR apart, which suggests that this is a time zone issue (not daylight savings, unless you happen to be in the southern hemisphere...) – Matthew Watson Feb 13 '20 at 10:27

5 Answers5

4

A string in the yyyy-MM-ddTHH:mm:ssZ format represents a date in UTC.
It is correctly parsed as such, but unfortunately, the resulting DateTime value is DatetimeKind.Local, and its value is adjusted accordingly to the time zone of the computer.

As stated in the comment in the beginning of the DateTime source code file,

Starting from V2.0, DateTime also stored some context about its time
zone in the form of a 3-state value representing Unspecified, Utc or
Local. This is stored in the two top bits of the 64-bit numeric value
with the remainder of the bits storing the tick count. This information
is only used during time zone conversions and is not part of the
identity of the DateTime. Thus, operations like Compare and Equals
ignore this state. This is to stay compatible with earlier behavior
and performance characteristics and to avoid forcing  people into dealing
with the effects of daylight savings. Note, that this has little effect
on how the DateTime works except in a context where its specific time
zone is needed, such as during conversions and some parsing and formatting
cases.

Thus, the Ticks property of a DatetimeKind.Local date is relative to the local 12:00:00 midnight, January 1, 0001, not to the UTC 12:00:00 midnight, January 1, 0001.
This is documented in the remarks for the Ticks property.

This also means that the two date instances obtained via this kind of DateTime.Parse on different servers in different timezones, would compare as "unequal" even though they originate from the same string that describes the same UTC date. This is for backward compatibility.

In order to compare the ticks directly, you need to convert both dates to Kind.UTC first.

GSerg
  • 76,472
  • 17
  • 159
  • 346
  • "the Ticks property.. is relative to the local [time]" - that's the key! ;) Adding `Console.WriteLine(TimeZoneInfo.Local);` to the code makes it obvious where the difference lies... – Ian Feb 13 '20 at 10:54
1

It's about CultureInfo of the server you run on. DateTime.Parse has different overloads and parsing a datetime and also currency too, is depending on system's CultureInfo(language and region and etc.)

Ozan Topal
  • 127
  • 1
  • 1
  • 11
  • 4
    Actually, that is not true. A string [conforming to ISO8601](https://learn.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netframework-4.8#the-string-to-parse) should be parsed as UTC time, even though it is then adjusted to the local time). – GSerg Feb 13 '20 at 10:24
1

A possible solution for different timezones in which date is parsed could be this:

DateTime parsedDateTime = DateTime.Parse(
    "2020-02-12T16:57:36Z", 
    CultureInfo.InvariantCulture, 
    DateTimeStyles.AdjustToUniversal);
Marco
  • 56,740
  • 14
  • 129
  • 152
1

The answer is already in the question. The key point is in the output: 12.02.2020 17:57:36 Local 637171270560000000

The dateTime.kind shows what type of date it is? As the two website is most likely in two different places it shows two different times because .net has converted the given UTC time to their local time, which is reflected through DateTime.Kind.

If you instead run this

DateTime parsedDateTime = DateTime.Parse("2020-02-12T16:57:36Z").ToUniversalTime();
Console.WriteLine(parsedDateTime + " " + parsedDateTime.Kind.ToString() + " " + parsedDateTime.Ticks);

https://rextester.com/XWH12209

https://dotnetfiddle.net/o4XRFS

You will get the same date/time combination, because now it's not converted to local datetime but UTC instead.

For more clarification when I run your code on my local machine my output is:

12-Feb-20 10:57:36 PM Local 637171450560000000

Which basically means at the given UTC time it was 12-Feb-20 10:57:36 PM in my country.

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
SZT
  • 1,771
  • 4
  • 26
  • 53
-1
DateTime.ParseExact(DateTime, Format, DateTimeFormatInfo.InvariantInfo,
DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite);

for example:

DateTime.ParseExact("06APR22/1605", "ddMMMyy/HHmm", DateTimeFormatInfo.InvariantInfo,
DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite);
Nick Vu
  • 14,512
  • 4
  • 21
  • 31