Skip to content

Working with time zones

Rian Stockbower edited this page Apr 7, 2018 · 4 revisions

On calendars

When constructing a Calendar, you may wish to give it a time zone. Behind the scenes, time zone operations use NodaTime to do the heavy lifting for date/time conversions, and any time zone string that NodaTime supports will work.

var calendar = new Calendar();
calendar.AddTimeZone(new VTimeZone("America/New_York"));

When computing when future events will occur

In the general case in date and time programming, it's not really possible to express rules about future times using UTC as your starting point if your target time zone isn't also UTC. Time zones are socio-political, and the rules change.

To that end, the solution is to express your CalDateTimes with local time zones. Once you've done that, GetOccurrences() will compute the recurrence set correctly.

var start = DateTime.Parse("2017-02-01 11:00");
var end = start.AddHours(1);
var dailyUntilSummer = new RecurrencePattern(FrequencyType.Daily, 1)
{
    Until = DateTime.Parse("2017-07-01 12:00"),
};
var calendarEvent = new CalendarEvent
{
    Start = new CalDateTime(start, "America/New_York"),
    End = new CalDateTime(end, "America/New_York"),
    RecurrenceRules = new List<RecurrencePattern> { dailyUntilSummer },
};

var calendar = new Calendar();
calendar.Events.Add(calendarEvent);

var occurrences = calendar.GetOccurrences(start, start.AddMonths(6))
    .Select(o => new {Local = o.Period.StartTime, Utc = o.Period.StartTime.AsUtc})
    .OrderBy(o => o.Local)
    .ToList();

If you set a breakpoint after occurrences, and look at its contents, you'll see that on March 12, the UTC time goes from 16:00 to 15:00 while the local time remains stable. On March 12, America/New_York went from UTC-5 to UTC-4 when the clocks changed:

{ Local = {3/10/2017 11:00:00 AM America/New_York}, Utc = {3/10/2017 4:00:00 PM} }
{ Local = {3/11/2017 11:00:00 AM America/New_York}, Utc = {3/11/2017 4:00:00 PM} }
{ Local = {3/12/2017 11:00:00 AM America/New_York}, Utc = {3/12/2017 3:00:00 PM} }
{ Local = {3/13/2017 11:00:00 AM America/New_York}, Utc = {3/13/2017 3:00:00 PM} }

Converting a time to another time zone

Sometimes you may need to get a representation of a Start or End time to another time zone. You can do this with ToTimeZone(), which does NOT change the time zone of the original CalDateTime:

var calendarEvent = new CalendarEvent
{
    Start = new CalDateTime(DateTime.Now, "America/New_York"),  // IANA time zone
    // ...
}

// but you want to know what time that is in Canberra, Australia:
var inCanberra = calendarEvent.Start.ToTimeZone("Australia/Canberra");

// You can also convert to time zones in different time zone databases:
// Libya Standard Time is a Windows time zone
var inLibya = calendarEvent.Start.ToTimeZone("Libya Standard Time");