Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# DateTime.ToString with zzz breaks in dotnet framework but not in dotnet core

Tags:

c#

datetime

I have my local time in GMT +01:00 as the time of writing. I experience something, to me unexpected, when doing a ToString in the following way. Here we go:

Demonstrating the local system settings with +01:00 time zone (all these run green):

var myLocalDate = new DateTime(2020, 11, 25, 08, 00, 00, DateTimeKind.Local);
Assert.AreEqual("2020-11-25T08:00:00+01:00", myLocalDate.ToString(@"yyyy-MM-dd\THH:mm:sszzz"));
Assert.AreEqual(DateTimeKind.Local, myLocalDate.Kind);
Assert.AreEqual(myLocalDate, myLocalDate.ToLocalTime());

And now I create the same time, in utc, by manually subtracting an hour and specifying the "utc" as kind. But when I call ToString, the time zone is written as +01:00 which I would expect to be +00:00:

var myUtcDate = new DateTime(2020, 11, 25, 07, 00, 00, DateTimeKind.Utc);
// THIS Breaks:
Assert.AreEqual("2020-11-25T07:00:00+00:00", myUtcDate.ToString(@"yyyy-MM-dd\THH:mm:sszzz"));

Error message:

Message: Assert.AreEqual failed. Expected:<2020-11-25T07:00:00+00:00>. Actual:<2020-11-25T07:00:00+01:00>.

Do I miss something about datetimes and formats here, or is this maybe a known bug?

I run .Net Framework 4.8

This post is about the same issue, I see: How to solve DateTimeInvalidLocalFormat error: "A UTC DateTime is being converted to text in a format that is only correct for local times."?

UPDATE:

Running the following program yields different results in dotnet framework and dotnet core (as mentioned by evk):

Console.WriteLine(new DateTime(2025, 11, 25, 07, 00, 00, DateTimeKind.Utc).ToString(@"yyyy-MM-dd\THH:mm:sszzz"));

dotnet core prints:

2020-11-25T07:00:00+00:00

dotnet framework prints:

2020-11-25T07:00:00+01:00

Furthermore, when running dotnet framework in debug mode, the following debug assistant message shows up, but is ignored internally in the DateTime.ToString():

Managed Debugging Assistant 'DateTimeInvalidLocalFormat' : 'A UTC DateTime is being converted to text in a format that is only correct for local times. This can happen when calling DateTime.ToString using the 'z' format specifier, which will include a local time zone offset in the output. In that case, either use the 'Z' format specifier, which designates a UTC time, or use the 'o' format string, which is the recommended way to persist a DateTime in text. This can also occur when passing a DateTime to be serialized by XmlConvert or DataSet. If using XmlConvert.ToString, pass in XmlDateTimeSerializationMode.RoundtripKind to serialize correctly. If using DataSet, set the DateTimeMode on the DataColumn object to DataSetDateTime.Utc. '

like image 708
Stephan Møller Avatar asked Oct 29 '25 10:10

Stephan Møller


1 Answers

No, it's behaving as documented. From the documentation of the zzz format specifier (emphasis mine):

With DateTime values, the "zzz" custom format specifier represents the signed offset of the local operating system's time zone from UTC, measured in hours and minutes. It doesn't reflect the value of an instance's DateTime.Kind property. For this reason, the "zzz" format specifier is not recommended for use with DateTime values.

Arguably that's unfortunate, but it's not a bug.

Note that .NET Core (and .NET 5.0) apparently doesn't behave as documented. While you could argue it's "fixed" in .NET Core, I'd suggest that behaving in an undocumented way is a bug in itself, and one that could make code migration harder than expected.

I suggest you follow the recommendation in the docs, and avoid using zzz with DateTime values. I'd also suggest using my Noda Time library instead, where there isn't the ambiguity in terms of a value "maybe being local, or maybe being UTC", but that's a slightly different matter. (I wouldn't expect you to run into this problem using Noda Time, and your other date/time code would hopefully be clearer.)

like image 118
Jon Skeet Avatar answered Nov 01 '25 02:11

Jon Skeet