DateOnly Won't Save You From Timezone Handling
An adventure in spacetime.
There was a misunderstanding about time zones in a team I was working with once.
They were developing an API that could receive calls from all around the world. Since clock time and timezone handling is, let’s admit it, always a pain, the team had decided to avoid the timezones altogether.
.NET 6.0 had just been released with the inclusion of the new DateOnly struct.
The team started experimenting using this new struct, which essentially strips off all time and timezone information.
Then funny things started happening!
Here’s the thing: Using DateOnly doesn’t save you from Timezone handling (in most cases).
For time-independent or time-insensitive data, like birth dates, event dates, milestone dates, etc. DateOnly is sufficient.
But for everything else where time is relevant, you can’t escape timezone handling like that.
It’s not only that right now Auckland time is ahead of Athens time, it’s that it has always been like that. So past datetimes appearing in logs and everywhere must respect this timezone difference and timezone offset.
Historic dates are not “fixed”, since if you want to track specific actions at specific times in the past, you need to take the offset into account. Timezone offset problems also appear in past dates, and not only in the current time and day.
If you convert a full DateTime into DateOnly, you lose important information that will make your life harder when the time comes to troubleshoot an issue. Such an approach will also distort your reporting and cause a myriad of other problems.
A DateOnly created from a full DateTime, can result in a different date depending on where you are located on the surface of the Earth.
Consider the following example, which highlights the problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string loggedTimestamp = "2021-12-20T17:30:00+02:00";
var origParsedDateTime = DateTimeOffset.Parse(loggedTimestamp);
Console.WriteLine($"Log entry with timezone as spotted in a log file: \"{loggedTimestamp}\"\n");
// Convert to UTC (remove the original offset)
DateTimeOffset utcDateTime = origParsedDateTime.ToUniversalTime();
TimeZoneInfo aucklandTimeZone = TimeZoneInfo.FindSystemTimeZoneById("New Zealand Standard Time");
// Convert to Auckland time
DateTimeOffset aucklandDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime.DateTime, aucklandTimeZone);
DateOnly dateOnlyAth = DateOnly.FromDateTime(origParsedDateTime.DateTime);
DateOnly dateOnlyAuck = DateOnly.FromDateTime(aucklandDateTime.DateTime);
Console.WriteLine($"DateOnly Athens: {dateOnlyAth}");
Console.WriteLine($"DateOnly Auckland: {dateOnlyAuck}");
1
2
3
4
Log entry with timezone as spotted in a log file: "2021-12-20T17:30:00+02:00"
DateOnly Athens: 20/12/2021
DateOnly Auckland: 21/12/2021
A test scenario that showcases this can be found @ DateOnly and Timezone Test
