Tuesday, April 14, 2009

Weekly .Net Library Review 1: TimeZoneInfo and DateTimeOffset

Weekly .Net Library Review 1: TimeZoneInfo and DateTimeOffset

While on StackOverflow (www.stackoverflow.com), I ran across a link to this poster.




I know very few of the classes listed on the poster, but it occurred to me that I should strive to learn more of them, so in the style defined by Scott Hanseleman, I plan to investigate a different class or two available in the standard .Net library. In this first installment of many, I will go over two classes that were introduced in .NET 3.0, TimeZoneInfo and DateTimeOffset. Both of these classes can be found in the System Namespace.


TimeZoneInfo

TimeZoneInfo is similar to the TimeZone class. However unlike the TimeZone class, the TimeZoneInfo class provides many static methods, including GetSystemTimeZones(), which returns a collection containing a TimeZoneInfo object for each Time Zone that is configured on the local machine.

DateTimeOffset

The DateTimeOffset class is similar to the DateTime object that has been in present in .NET since 1.0. There are two distinctions. First, the DateTime has a Property called Kind, which returns an object of type DateTimeKind. DateTimeKind is an enum with three values, Utc, Local, and unspecified. This denotes what time zone the object is based on; UTC, Local, or an Unspecified time zone. DateTimeOffset is always based on UTC time, so this property is unnecessary. DateTimeOffset also contains an Offset property, which is an object of type TimeSpan. This object contains the Offset necessary to calculate the local time from the UTC time. For example, if the local time zone is Eastern Standard Time, then the offset will be -05:00:00.

Sample Code

Above is a screenshot of the application, with notes in red.

1 is a drop down box named cbTimeZones.

2 is a label named lblUTTime

3 is a label named lblTime

4 is a label named lblOffset


During initiailization, cbTimeZones is populated with the results of TimeZoneInfo.GetSystemTimeZones(). The selected Time Zone is set to the local time zone. A function called UpdateTime is called, which sets lblUTTime to the current UT Time, lblTime is set to the time in lblUTTime plus the offset, and lblOffset is set to the offset of the current selected Time Zone.

A DispatchTimer is created and set to trigger every second. When triggered, it calls a method which in turns calls UpdateTime().

The constructor looks like this:




public TimeZoneUtil()

{

InitializeComponent();

DateTimeOffset currentTime = DateTimeOffset.Now;

foreach(TimeZoneInfo tzi in TimeZoneInfo.GetSystemTimeZones())

{

cbTimeZones.Items.Add(tzi);

if (tzi.Equals(TimeZoneInfo.Local))

{

cbTimeZones.SelectedItem = tzi;

}

}

UpdateTime();

timer = new DispatcherTimer();

timer.Interval = TimeSpan.FromMilliseconds(1000);

timer.Tick += new EventHandler(Timer_Tick);

timer.Start();

}




The TimerTick method is trivial and the UpdateTime method is straight forward:





private void Timer_Tick(object sender, EventArgs e)

{

UpdateTime();

}

private void UpdateTime()

{

DateTimeOffset currentTime = DateTimeOffset.Now;

TimeZoneInfo selectedTimeZone = (TimeZoneInfo)cbTimeZones.SelectedItem;

TimeSpan selectedTimeZoneOffset = selectedTimeZone.GetUtcOffset(currentTime);

lblTime.Content = currentTime.UtcDateTime.Add(selectedTimeZoneOffset).ToString();

lblUTTime.Content = currentTime.UtcDateTime.ToString();

lblOffset.Content = selectedTimeZone.GetUtcOffset(currentTime);

}




The 4th line of UpdateTime is the trickiest. Here we get the UTC time (A DateTime object) stored in the DateTimeOffset object and we add to it the offset from the currently selected TimeZoneInfo (A TimeSpan object). This gives us the current time in the selected time zone.

To get the current time, the easier approach would be to call LocalDateTime property on the DateTimeOffset object. I do not do that in this example, as I wanted to allow the user to select a time zone instead of always using the local time zone.

No comments:

Post a Comment