I have question pertaining to the DateTimeKind
struct in C#.
If I have converted a DateTime
to a new DateTime (which is not in my local Timezone) using something like:
TimeZoneInfo.ConvertTimeBySystemTimeZoneId(now, "Tokyo Standard Time");
what should I use for the Kind
property of that new DateTime? Unspecified
feels a bit weird and does not help much with conversions.
I get the feeling that as soon as you use a Timezone
which is not your local and not UTC, then you absolutely have to start using the DateTimeOffset
struct.
CodePudding user response:
what should I use for the Kind property of that new DateTime?
Unspecified
feels a bit weird...
...but it's the correct value in this case. The documentation of the DateTimeKind enum is quite clear on this subject:
Local (2): The time represented is local time.
Unspecified (0): The time represented is not specified as either local time or Coordinated Universal Time (UTC).
Utc (1): The time represented is UTC.
Your time is neither local time nor UTC, so the only correct value is Unspecified
.
I get the feeling that as soon as you use a Timezone which is not your local and not UTC, then you absolutely have to start using the
DateTimeOffset
struct.
You don't have to, but it can definitely make your life easier. As you have noticed, DateTime
does not provide an option to store the time zone information along with the date. This is exactly what DateTimeOffset
is for.
CodePudding user response:
This is more a question about how to handle non-local TimeZones.
When you go beyond your local timezone, you really do need to use the DateTimeOffset
class.
When writing a time service, you may want to add a method for converting a DateTime in one non-local timezone to another non-local timezone. This is pretty straight forward when using the DateTimeOffset
class:
public DateTimeOffset ConvertToZonedOffset(DateTimeOffset toConvert, string timeZoneId)
{
var universalTime = toConvert.ToUniversalTime(); // first bring it back to the common baseline (or standard)
var dateTimeOffset = TimeZoneInfo.ConvertTime(universalTime, TimeZoneInfo.FindSystemTimeZoneById(timeZoneId));
return dateTimeOffset;
}
The incoming DateTimeOffset
has the source offset and the timeZoneId
being passed in gives enough information to realize the target timezone (and offset).
And the returned DateTimeOffset
has the target offset.
It gets a bit clunkier when you do it with the DateTime
struct, if you wanted to provide an equivalent method:
public DateTime ConvertToZonedOffset(DateTime toConvert, string sourceTimeZoneId, string targetTimeZoneId)
{
return TimeZoneInfo.ConvertTimeBySystemTimeZoneId(toConvert, sourceTimeZoneId, targetTimeZoneId);
}
And this is where the DateTimeKind
comes in. If you:
- pass the DateTime in with the Kind set to either UTC or Local; AND
- the sourceTimeZone is neither of those,
then ConvertTimeBySystemTimeZoneId
will throw an exception. So, when you are dealing with a "3rd timezone", Kind must be Unspecified
. This tells the method to ignore the system clock, to not assume that it is UTC and to go by whatever is passed in as the sourceTimeZone.
It's not as good as the DateTimeOffset
version in another way. The returned DateTime
has no information about the timezone and the Kind
is set to Unspecified
. This basically means that it is the responsibility of the calling code to know and track what timezone that date and time is valid in. Not ideal. So much so that I decided to "be opinionated" and get rid of that method. I'll force the calling code to convert the DateTime
they may be working with to a DateTimeOffset
and to consume one upon return.
Note 1: if Kind
is set to Local
and the sourceTimeZone matches your local timezone, it will work fine.
Note 2: if Kind
is set to Utc
and the sourceTimeZone is set to "Coordinated Universal Time", you may get the following TimeZoneNotFoundException
:
The time zone ID 'Coordinated Universal Time' was not found on the local computer
I assume that this is because UTC is a standard and not a timezone, despite being returned by TimeZoneInfo.GetSystemTimeZones
as a Timezone
.