.NET’s DateTime struct is basically just a number with some properties and methods wrapped around it. It can represent a date and time, but no concept of where in the world that time is.
The DateTimeOffset struct adds on a UTC offset, which means it now represents a given point in time (ignoring leap seconds – that screws things up).
Suppose you have a DateTime of “2021-04-09 12:34:56.789”. This is precise to the millisecond, but is that UTC time? Arizona time? Does it account for daylight saving time? Who knows?
A DateTimeOffset includes the UTC offset, so “2021-04-09 12:34:56.789-0700” is much clearer – this is 7 hours before UTC time. You can decide what you want to do with it from there. Note that this is an offset, not a time zone – this doesn’t account for daylight saving time or other weird scenarios.
However, in my personal experience, unless you’re strictly 100% local with no possibility of change, I would treat all times everywhere as UTC. Use DateTime.UtcNow instead of DateTime.Now everywhere in the code. The only time you would convert is specifically when you’re presenting data to the client or reading from the client – then you can do time zone conversions based on the user’s preferences.View code on GitHub