I wrote two extension methods to convert times from local time to UTC and back. This is what I have:
public static DateTime ConvertUserTimeToUTCTime(this DateTime TheUserTime, string TheTimezoneID)
{
TheUserTime = new DateTime(TheUserTime.Year, TheUserTime.Month,
TheUserTime.Day, TheUserTime.Hour, TheUserTime.Minute,
TheUserTime.Second, DateTimeKind.Local);
TimeZoneInfo TheTZ = TimeZoneInfo.FindSystemTimeZoneById(TheTimezoneID);
TimeSpan TheOffset = TheTZ.GetUtcOffset(TheUserTime);
DateTimeOffset TheUTCTimeOffset = new DateTimeOffset(
TheUserTime, TheOffset).ToUniversalTime();
DateTime TheUTCTime = new DateTime(TheUTCTimeOffset.Year,
TheUTCTimeOffset.Month, TheUTCTimeOffset.Day, TheUTCTimeOffset.Hour,
TheUTCTimeOffset.Minute, 0, DateTimeKind.Utc);
return TheUTCTime;
}
public static DateTime ConvertUTCTimeToUserTime(this DateTime TheUTCTime,
string TheTimezoneID)
{
TimeZoneInfo TheTZ = TimeZoneInfo.FindSystemTimeZoneById(TheTimezoneID);
DateTime UTCTime = new DateTime(TheUTCTime.Year, TheUTCTime.Month,
TheUTCTime.Day, TheUTCTime.Hour, TheUTCTime.Minute, 0, DateTimeKind.Utc);
DateTime TheUserTime = TimeZoneInfo.ConvertTime(UTCTime, TheTZ);
return TheUserTime;
}
I use these two quite frequently in my app and I was wondering if they’re thread safe. Also, would there be any benefit to putting these two method in an abstract class and then having all the classes that involve time operations inherit from this abstract class?
Thanks for your suggestions on this time conversion topic.
Yes, they’re thread-safe. They’re ugly in terms of variable naming (why “The” before everything, and why the Pascal-casing?), and you should consider using
DateTime.SpecifyKind, but they’re not doing anything with shared state… unlessTimeZoneInfohas thread safety problems, it should be fine. (TimeZoneInfoactually specifies that instance members aren’t guaranteed to be thread-safe, but it’s also noted to be immutable. I’d expect it to be thread-safe.)You definitely shouldn’t put these in an abstract class as a base class – that would be an abuse of inheritance. It doesn’t really represent some abstract notion you want to specialize, does it? Extension methods are reasonable here.
You should also think very carefully about how you want the code in the first method to behave in the case of ambiguous or invalid conversions: for example, if the clock goes forward at 1am to 2am, then 1:30am is invalid in that time zone on that day. Likewise if it goes back from 2am to 1am, then 1:30am occurs twice. Check the docs for
TimeZoneInfo.GetUtcOffsetto make sure that the value returned from it is what you want in those situations.Finally, consider using Noda Time instead, my alternative .NET date/time API which (I believe) keeps things rather cleaner – and makes your choices around things like date/time conversion very explicit.
(I wrote a blog post about this very topic just the other day, in terms of the choices I’ve been thinking about for the API. Feedback welcome.)