<ComboBox DisplayMemberPath="DisplayName" ItemsSource="{Binding Path=DataConnector.TimeZoneInfoProviderResolved.TimeZoneTokens, ElementName=myDataManager}” />
Proper support for time zones is essential in any robust scheduling system. Consider the following scenario. Let’s say you are in New York and you want to set up an appointment or meeting for 12:00 noon New York time. You have a colleague in Los Angeles and another in London that need to participate. The time for this appointment will be 9:00 a.m. in LA and 5:00 p.m. (17:00) in London. When you each view your calendars you need to see the appointment displayed relative to your local time zone, 9:00, 12:00 and 17:00 respectively.
The only reliable way of maintaining this is to store the start and end times of these activities in universal or ‘UTC’ time (in this case 17:00) and then convert the time into each ‘local’ time zone to display it. This becomes even more important when dealing with recurring appointments since their occurrences need to be calculated into the future taking into account daylight savings time adjustments for each time zone depending on the time of year for each occurrence.
There are certain activities which are time-zone neutral; e.g., an activity that represents a holiday will span from 12:00 a.m. to 12:00 a.m. (i.e., the entire day) in every time zone. In fact when the ‘All Day Event’ checkbox is checked in the appointment dialog, the start and end times are set accordingly and the activity is marked ‘time zone neutral’ so that no UTC to local adjustments are made and the start and end time are displayed to the user ’as is’. Note: it is possible to mark any activity as ‘time zone neutral’ even if it doesn’t span a day. It just means that the start and end time will be displayed ‘as is’ without any time-zone conversions.
In order for time-zone conversions to be made accurately, the scheduling controls must have access to information about every time zone, including each time zone’s base UTC offset as well as its set of rules that define when daylight savings time starts and ends in each year.
The WPF framework provides this information for all time zones through its TimeZoneInfo class. In Silveright the TimeZoneInfo class exists in the framework but it only exposes the information for the ‘local’ and ‘UTC’ time zones.
To solve this problem the Infragistics scheduling components define a base class called TimeZoneInfoProvider. There is an OSTimeZoneInfoProvider-derived class that is essentially implemented as a thin wrapper around the framework’s TimeZoneInfo class. As such it only exists in the WPF version of the controls. The other derived class, CustomTimeZoneInfoProvider, exists in both Silverlight and WPF. It can be used to register the time zones in code or load/save them in xml format.
TimeZoneInfoProvider exposes a thread static property named DefaultProvider which in WPF returns an instance of the OSTimeZoneInfoProvider class.
The DataConnector, exposed off xamScheduleDataManager, exposes the following properties relating to time zones:
TimeZoneInfoProvider – this is a get/set property that can be used to specify a custom time-zone provider. This is null by default.
TimeZoneInfoProviderResolved – this is a read-only property that will always return a provider, either the TimeZoneInfoProvider if specified or the TimeZoneInfoProvider.DefaultProvider described above. Note: if you wanted to show a ComboBox to let the user select a specific time zone, you could bind its ItemsSource to the TimeZoneTokens collection exposed off this object and set the ComboBox’s DisplayMember property to “DisplayName”. E.g.:
In XAML:
<ComboBox DisplayMemberPath="DisplayName" ItemsSource="{Binding Path=DataConnector.TimeZoneInfoProviderResolved.TimeZoneTokens, ElementName=myDataManager}” />
When using the OsTimeZoneInfoProvider in WPF the default ‘local’ time zone will be picked from the OS settings.
When using a CustomTimeZoneInfoProvider an attempt is made to default the local time zone based on the following approach:
If a time zone is registered with the same id as the current OS local time zone id then this time zone is used. Note: this step only applies to WPF because the information is not available in Silverlight.
If step 1 is not successful, all time zones registered to the provider that have the same base UTC offset as the system local time zone are checked. If one and only one time zone has date conversions to UTC time that exactly match the system local time zone conversions to UTC then it is used as the default. Otherwise no local time zone is set. This is a fairly efficient process because only times just before and after the daylight savings cusp times are checked.
The local time zone can be changed programmatically by setting the provider’s LocalTimeZoneId property.
The xamScheduleDataManager also exposes an enum property named PromptForLocalTimeZone with the following values:
OnlyIfRequired – this is the default setting and will result in a dialog being displayed to the user prompting for a time-zone selection only if a default local time zone was not found.
Always – the dialog will be displayed whether or not a default was found.
Never – the dialog will not be displayed even if a default local time zone was not found. Note: in this case the controls treat this as a blocking error since they can’t convert times accurately and will display the blocking error inside a control overlay.
The TimeZoneInfoProvider class exposes methods to get information about specific time zones and to convert times between time zones via a TimeZoneToken class. You access the token by calling the provider’s GetTimeZoneToken method passing in the id of the time zone. The returned token is then passed into the other methods to identify the time zone.
Note: The TimeZoneToken exposes an Id property, a DisplayName property and a Provider property which will return the TimeZoneInfoProvider it is associated with.
ActivityBase (the base class for Appointment, Journal and Task) exposes the following properties that have a direct or indirect effect on time zones:
Start/ End – these properties are of the type DateTime and store the start and end times of the activity in UTC time (or unspecified in the case of time-zone neutral activities).
StartTimeZoneId/ EndTimeZoneId – these string properties identify the time zone that the Start and End time are related to. When generating occurrences of a recurring activity these time zone ids ensure that the correct times are used even when transitioning into and out of daylight savings time.
IsTimeZoneNeutral – if set to True will prevent time-zone conversions. This will cause the StartTimeZoneId/EndTimeZoneId settings to be ignored.
ActivityBase also exposes two helper methods, SetStartLocal and SetEndLocal, which take a time zone token and a DateTime and will set the Start/End times correctly based on the IsTimeZoneNeutral setting. If True it will set the Start and End properties to the passed in DateTime without conversions. If False it will convert the DateTime to UTC time from that time zone.
Note: Make sure you set the IsTimeZoneNeutral property appropriately before you call these methods, because changing this property afterward will not convert the date time values.