Helpful DateTime extension methods for dealing with Time Zones

This post is inspired by Scott Mitchell’s 5 Helpful DateTime Extension Methods. I built a couple extension methods while adding time zone support to our application. Since time zone math is never fun, I figure someone else may benefit from these.

ToStartOfTimeZonesDayInUtc

The name is clunky because its really hard to describe succinctly. Given a time (in UTC) and a time zone, I want to know the time (in UTC) that the day started in that time zone. This is useful, for example, when you want to display a list of events, grouped by day, in the user’s time zone. If an event happened at 3:05am UTC on February 4th, it should be grouped in Feburary 4th when displayed to a user in Western European Time, but grouped in February 3rd for a user in Central Time (US).

/// <summary>
/// The time in UTC that the day started in the given time zone for a specific UTC time
/// </summary>
/// <param name="utcTime">A point in time, specified in UTC</param>
/// <param name="timezone">The time zone that determines when the day started</param>
/// <returns></returns>
public static DateTime ToStartOfTimeZonesDayInUtc(this DateTime utcTime, TimeZoneInfo timezone)
{
    var startOfDayInGivenTimeZone = utcTime.ToLocalTime(timezone).Date;
    return startOfDayInGivenTimeZone.ToUniversalTime(timezone);
}

StartOfTodayInUtc

A convenience method for determining the day, right now, in a given time zone.

/// <summary>
/// The time in UTC that the current day started in the given time zone
/// </summary>
/// <param name="timezone">The time zone that determines when the day started</param>
/// <returns></returns>
public static DateTime StartOfTodayInUtc(this TimeZoneInfo timezone)
{
    return DateTime.UtcNow.ToStartOfTimeZonesDayInUtc(timezone);
}

ToLocalTime and ToUniversalTime

These are pretty straightforward but I’ll include them because the methods above depend on them. DateTime already has ToLocalTime and ToUniversalTime methods, but they are flawed because they do not let you specify a time zone. I’m not sure why they were not added as overloads when the TimeZoneInfo type was introduced.

/// <summary>
/// Converts a UTC time to a time in the given time zone
/// </summary>
/// <param name="targetTimeZone">The time zone to convert to</param>
/// <param name="utcTime">The UTC time</param>
/// <returns></returns>
public static DateTime ToLocalTime(this DateTime utcTime, TimeZoneInfo targetTimeZone)
{
    return TimeZoneInfo.ConvertTimeFromUtc(utcTime, targetTimeZone);
}

/// <summary>
/// Converts a local time to a UTC time
/// </summary>
/// <param name="sourceTimeZone">The time zone of the local time</param>
/// <param name="localTime">The local time</param>
/// <returns></returns>
public static DateTime ToUniversalTime(this DateTime localTime, TimeZoneInfo sourceTimeZone)
{
    return TimeZoneInfo.ConvertTimeToUtc(localTime, sourceTimeZone);
}

Related Articles:

This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Nadav

    Reqarding the ToLocal/ToUniversal functions,
    I’ve found that the ConvertTime To/From UTC throws exceptions if the Kind of the DateTime is not as it expects.
    Now, for ConvertTimeFromUtc it throws if the Kind!=UTC which is not a big suprise,
    But ConvertTimeToUtc requires that the Kind will be Unspecified which I found a bit of a suprise.

  • http://www.lostechies.com/members/jflanagan/default.aspx Joshua Flanagan

    @Nadav – great point. The trick is in understanding what DateTimeKind.Local means. It does not mean “not UTC”. It specifically means “in the timezone of the current system”.

    We do not want our application to have any dependency on the timezone of the current system, so we _never_ have a DateTime with Kind=Local. The only way you would have a DateTimeKind=Local is if you used DateTime.Now. When building a server application that needs to support multiple time zones, always use DateTime.UtcNow. When you convert a UTC time to a “local” time with TimeZoneInfo.ConvertTimeFromUtc and an arbitrary TimeZoneInfo, the resulting time has Kind=Unspecified, which will happily convert back to UTC with ConvertTimeToUtc.

  • Martin Sykora

    I liked your post, and I hope my comment is not too naive but I wonder what about Daylight savings time? So for example right now the UTC and GMT time in Britain differ by +1 hour since the United Kingdom is in BST (Summer savings time)…

    Does the TimeZoneInfo class account for that?? …or is more logic necessary here.. I guess I’ll try it when I have more time, but if you know, this would be usefull to point out here I think.

    thanks,
    Martin