I'm trying to get ahold of this timezone issue we are having. We would like to store all DateTime
s in UTC, and then convert the DateTime
to the user's timezone.
We decided to use NodaTime for this, as it seems like the right approach. However, we are experiencing an issue with it.
This is how we convert the DateTime
to UTC (note - I hardcoded the usersTimeZone
for now):
public static DateTime ConvertLocaltoUTC(this DateTime dateTime)
{
LocalDateTime localDateTime = LocalDateTime.FromDateTime(dateTime);
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
var usersTimezoneId = "Europe/Copenhagen";
var usersTimezone = timeZoneProvider[usersTimezoneId];
var zonedDbDateTime = usersTimezone.AtLeniently(localDateTime);
var returnThis = zonedDbDateTime.ToDateTimeUtc();
return zonedDbDateTime.ToDateTimeUtc();
}
And here is how we convert it back:
public static DateTime ConvertUTCtoLocal(this DateTime dateTime)
{
Instant instant = Instant.FromDateTimeUtc(dateTime);
IDateTimeZoneProvider timeZoneProvider = DateTimeZoneProviders.Tzdb;
var usersTimezoneId = "Europe/Copenhagen"; //just an example
var usersTimezone = timeZoneProvider[usersTimezoneId];
var usersZonedDateTime = instant.InZone(usersTimezone);
return usersZonedDateTime.ToDateTimeUnspecified();
}
However, when we convert it back to local time, it throws an exception:
Argument Exception: Invalid DateTime.Kind for Instant.FromDateTimeUtc
at the first line of ConvertUTCtoLocal()
.
An example of the DateTime
could be: "9/18/2017 5:28:46 PM" - yes this has been through the ConvertLocalToUTC
method.
Am I providing an incorrect format? What am I doing wrong here?
The exception you show:
Argument Exception: Invalid DateTime.Kind for Instant.FromDateTimeUtc
Is thrown from this code:
Instant instant = Instant.FromDateTimeUtc(dateTime);
It means that dateTime.Kind
needs to be DateTimeKind.Utc
to be convertible to an Instant
, and for whatever reason it is not.
If you look at the result of your ConvertLocaltoUTC
method, you'll find that it does have .Kind == DateTimeKind.Utc
.
So, the problem lies elsewhere in your code, wherever you created the dateTime
you're passing in to ConvertUTCtoLocal
.
You may find the solution could be any of the following:
You might need to call DateTime.SpecifyKind
to set the kind to UTC, but be careful to only do this when your values are actually UTC and it's just not setting the kind. For example, use this when loading a UTC-based DateTime
from a database.
You might need to call .ToUniversalTime()
, but be careful to only do this if the machine's local time zone is relevant to your situation. For example, do this in desktop or mobile apps where a UI control is picking a date, but you meant it to mean UTC instead of local time.
You might need to change how you parse strings into DateTime
values, such as by passing DateTimeStyles.RoundTripKind
to a DateTime.Parse
call (or any of its variants. For example, do this if you are reading data from text, csv, etc.
If you want to avoid having to decide, don't write functions that take DateTime
as input or give DateTime
as output. Instead, use DateTimeOffset
, or use Noda-Time types like Instant
, LocalDateTime
, etc. as early as possible.
This is what worked for me:
Instant instant = Instant.FromDateTimeUtc(DateTime.SpecifyKind(datetime, DateTimeKind.Utc));
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