Reputation: 4424
With the code below, I'm trying to convert this datetime
string to a Local DateTime
private DateTime ConvertToLocalTime(string datetimestring)
{
DateTime timeUtc = DateTime.Parse(datetimestring);
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
return cstTime;
}
This is the Exception I'm getting:
at System.TimeZoneInfo.ConvertTime(DateTime dateTime, TimeZoneInfo sourceTimeZone, TimeZoneInfo destinationTimeZone, TimeZoneInfoOptions flags, CachedData cachedData) at
System.TimeZoneInfo.ConvertTimeFromUtc(DateTime dateTime, TimeZoneInfo destinationTimeZone)
The conversion could not be completed because the supplied DateTime did not have the Kind property set correctly. For example, when the Kind property is
DateTimeKind.Local
, the source time zone must be TimeZoneInfo.Local.
The example for ConvertTimeFromUtc looks exactly like my code except I'm parsing this string into the timeUtc:
2017-01-23T05:00:00+00:00
If I call the Parse like this:
DateTime.Parse(datetimestring, null, System.Globalization.DateTimeStyles.RoundtripKind);
timeUtc.Kind.ToString()
returns "Local"
So, how do I remedy this? The times are going to be sent to me UTC.
Upvotes: 6
Views: 7497
Reputation: 3806
Just to digress more about converting Utc time to local time zone specified :
I checked the available time zones called 'Central' on my system and found these three :
The time zone called 'Central America Standard Time' has not support for daylight saving time, while 'Central Standard Time'. Probably you do want to use the one with the daylight saving time.
Here is an extension method I created similar to the other answers and accepts an arbitrary specified TimeZoneInfo id supported - it is checking if the time zone provided is recognized and requiring that the DateTime has Kind 'Utc'.
public static class DatetimeExtensions {
/// <summary>Returns the DateTime in a specified time zone</summary>
/// <remarks>
/// <paramref name="timeZoneId" /> must be a recognized time zone id, check with System.TimeZoneInfo.GetSystemTimeZones() available time zones on the target system
/// <paramref name="dateTime" /> must be a datetime of Kind Utc to be properly calculated into its proper value in the specified time zone id
/// </remarks>
public static DateTime ConvertToLocalTime(this DateTime dateTime, string timeZoneId){
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId) ?? System.TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(tz => string.Equals(tz.Id, timeZoneId, StringComparison.InvariantCultureIgnoreCase));
if (timeZone == null)
{
throw new ArgumentException($"The time zone with id {timeZoneId} is not recognized. (Available time zones can be retrieved using 'System.TimeZoneInfo.GetSystemTimeZones()' method)");
}
if (dateTime.Kind != DateTimeKind.Utc)
{
throw new ArgumentException($"The date time {dateTime} is not of the right Kind 'Utc'");
}
return TimeZoneInfo.ConvertTimeFromUtc(dateTime, timeZone);
}
}
A test using this method:
void Main()
{
var central = TimeZoneInfo.GetSystemTimeZones().Where(x => x.DisplayName.Contains("Central")).ToList();
central.Dump();
var someUtcDate = new DateTime(2024, 6, 4, 6, 30, 0, DateTimeKind.Utc);
var someUtcDateInCST = someUtcDate.ConvertToLocalTime("Central America Standard Time");
Console.WriteLine(someUtcDateInCST);
}
Running this method gives:
04.06.2024 00:30:00
If I switch instead to using "Central Standard Time", I get:
04.06.2024 01:30:00
This is only five hours behind UTC time, but it is daylight saving time adjusted, which agrees with the daylight saving.
Upvotes: 0
Reputation: 27019
If you just want to convert to local datetime and you do not need the offset, since your string has offset info, DateTime.Parse
will use the offset info and convert to local datetime. Then all you need to do is:
private static DateTime ConvertToLocalTime(string datetimestring)
{
// Parses to local datetime
// check the Kind property and you will see it has Local
return DateTime.Parse(datetimestring);
}
If you need the local datetime with the offset info, then have a look at DateTimeOffset because it is for this very purpose:
private static DateTimeOffset ConvertToLocalTime(string datetimestring)
{
DateTime timeUtc = DateTime.Parse(datetimestring, null, DateTimeStyles.AdjustToUniversal);
DateTimeOffset dateCst = new DateTimeOffset(timeUtc, TimeZoneInfo.Local.BaseUtcOffset);
return dateCst;
}
If you need the utc datetime converted to some other timezone, not local, then specify it like below:
private static DateTimeOffset ConvertToLocalTime(string datetimestring)
{
DateTime timeUtc = DateTime.Parse(datetimestring, null, DateTimeStyles.AdjustToUniversal);
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTimeOffset dateCst = new DateTimeOffset(timeUtc, cstZone.GetUtcOffset(timeUtc));
return dateCst;
}
This is the documentation:
//
// Summary:
// Initializes a new instance of the System.DateTimeOffset structure using the specified
// System.DateTime value and offset.
//
// Parameters:
// dateTime:
// A date and time.
//
// offset:
// The time's offset from Coordinated Universal Time (UTC).
//
// Exceptions:
// T:System.ArgumentException:
// dateTime.Kind equals System.DateTimeKind.Utc and offset does not equal zero.-or-dateTime.Kind
// equals System.DateTimeKind.Local and offset does not equal the offset of the
// system's local time zone.-or-offset is not specified in whole minutes.
//
// T:System.ArgumentOutOfRangeException:
// offset is less than -14 hours or greater than 14 hours.-or-System.DateTimeOffset.UtcDateTime
// is less than System.DateTimeOffset.MinValue or greater than System.DateTimeOffset.MaxValue.
Upvotes: 0
Reputation: 5867
DateTime.Parse
converts the result into local time regardless of the zone specified in the input string. You have to explicitly specify that you want a UTC result, as TimeZoneInfo.ConvertTimeFromUtc
requires the DateTime value to be of kind UTC.
private DateTime ConvertToLocalTime(string datetimestring)
{
DateTime timeUtc = DateTime.Parse(datetimestring, null, System.Globalization.DateTimeStyles.AdjustToUniversal);
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, cstZone);
return cstTime;
}
Upvotes: 3
Reputation: 1090
You have to add DateTime.SpecifyKind
private static DateTime ConvertToLocalTime(string datetimestring)
{
DateTime timeUtc = DateTime.Parse(datetimestring);
var dt = DateTime.SpecifyKind(timeUtc, DateTimeKind.Utc);
TimeZoneInfo cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
DateTime cstTime = TimeZoneInfo.ConvertTimeFromUtc(dt, cstZone);
return cstTime;
}
Upvotes: 5