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. '
No, it's behaving as documented. From the documentation of the zzz format specifier (emphasis mine):
With
DateTimevalues, 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'sDateTime.Kindproperty. For this reason, the "zzz" format specifier is not recommended for use withDateTimevalues.
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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With