Dan Rigsby – Coding Up Style

Developer.Speaker.Blogger

Archive for the 'C#' Category

TimeZone vs. TimeZoneInfo in .Net

Posted by Dan Rigsby on 24th August 2008

Working with Dates and Times in .Net 3.5 Series:
Part 1: DateTime vs. DateTimeOffset in .Net
Part 2: TimeZone vs. TimeZoneInfo in .Net

This is Part 2 in a series on working with Dates and Times in .Net 3.5.  You might want to read Part 1: DateTime vs. DateTimeOffset in .Net in WCF before continuing on with this post.

MoonKnt_12The TimeZone data type was introduced in .Net 1.0 as a mechanism for retrieving information about the current time zone, and to convert times from local time to Coordinated Universal Time (UTC) or vice versa.  The down side is that you cannot use this to represent any other time zone other than the local zone.  It also can’t be used to convert one date time to another zone.  This is a pretty sever limitation and something that .Net has been lacking for some time.

In .Net 3.5, Microsoft finally introduced a replacement for TimeZone.  The TimeZoneInfo class fills in all of the gaps where TimeZone left off.  You can represent any time zone and perform various calculations.  Many people have yet to hear of this class, but it is crucial if you are working with applications that need to perform calculations on dates and times which may originate from differet time zones. The major functions of this class include the ability to:

  • Retrieving a time zone that is already defined by the operating system. This can be retrieved by ID or the current local time zone.
  • Converting times between different time zones.
  • Enumerating the time zones that are available on a system.
  • Find all time zones a DateTime or DateTimeOffset can represent.
  • Creating a new time zone that is not already defined by the operating system.
  • Serializing a time zone for later retrieval.

View the complete list of members here: http://msdn.microsoft.com/en-us/library/system.timezoneinfo_members.aspx

Use this class to work with any time zone that is predefined on a system, to create new time zones, and to easily convert dates and times from one time zone to another. The TimeZoneInfo class replaces the TimeZone class in every way.  For all new development, ignore the TimeZone class and move straight to TimeZoneInfo.  The TimeZone class should probably have been marked as “Obsolete”.

How TimeZone class works

TimeZone timeZone = System.TimeZone.CurrentTimeZone;
Console.WriteLine(timeZone.StandardName);
 
With the TimeZone class you could pull the current time zone with the static CurrentTimeZone static property.  The TimeZone class has no constructors and fairly limited use.  You can convert dates and times from the local zone to UTC, but you have no access to other time zones.

How to retrieve a time zone with TimeZoneInfo

TimeZoneInfo hwZone =
    TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time");
TimeZoneInfo info = TimeZoneInfo.Local;
 
The TimeZoneInfo class allows you to access the local time zone with the Local static property.  This is similar to the TimeZone class.  However, TimeZoneInfo also allows you to reference any time zone with the FindSystemTimeZoneById static method. This method takes in a string which represents the Id for the time zone. Once you have this time zone, you can work with methods on the object to perform a variety of conversions.
 
A TimeZoneNotFoundException is thrown if the time zone ID could not be found on the local system.

How to convert times between different time zones with TimeZoneInfo

The TimeZoneInfo provides a few conversion methods to allow conversions between different time zones.  The most useful of which is the ConvertTime method.  With this, you can pass in a date/time and the time zone in which you want to convert it into.  If you are using DateTimeOffset, then when you compare the two date/time values, they are equivalent since they both represent the same time, just in different time zones.

DateTimeOffset nowDateTime = DateTimeOffset.Now;
DateTimeOffset newDateTime = TimeZoneInfo.ConvertTime(
    nowDateTime,
    TimeZoneInfo.FindSystemTimeZoneById("Hawaiian Standard Time"));
Console.WriteLine("Now: {0}", nowDateTime);
Console.WriteLine("Now in Hawaii: {0}", newDateTime);
 
timezoneinfo1 

How to enumerate through all time zones on the computer with TimeZoneInfo

The GetSystemTimeZones method of the TimeZoneInfo class returns a ReadOnlyCollection of all of the time zones that the current system knows about.

ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();
Console.WriteLine("All time zones:");
foreach (TimeZoneInfo timeZoneInfo in timeZones)
{
    Console.WriteLine("   {0}", timeZoneInfo.DisplayName);
}

timezoneinfo2 

How to find all time zones a DateTime or DateTimeOffset can represent with TimeZoneInfome

Most date time offset can represent multiple time zones.  For instance, if a date and time have a –6 hour offset, this could be in the Central Time, Central American, Saskatchewan, or Guadalajara.  With the TimeZoneInfo class, you can easily find all of the time zones that the date and time could represent by simply interating over all of the time zones on the system and comparing their offset to the offset stored in the DateTimeOffset object:

DateTimeOffset current = DateTimeOffset.Now;
ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();
Console.WriteLine("You might be in the following time zones:");
foreach (TimeZoneInfo timeZoneInfo in timeZones)
{
    // Compare offset with offset for that date in that time zone
    if (timeZoneInfo.GetUtcOffset(current).Equals(current.Offset))
    {
        Console.WriteLine("   {0}", timeZoneInfo.DisplayName);
    }
}
 
This code outputs all of the following time zones.  DateTimeOffset.Now happens to represent “Eastern Time” in this example.
 
timezoneinfo3 

How to create a new time zone with TimeZoneInfo

The TimeZoneInfo class has no constructors, so it is impossible to new up a new instance.  However, it does provide a static method called CreateCustomTimeZone that allows you to create a new time zone to work with.  This method has a couple of overrides to provide you with everything needed to create a new time zone.  The following creates a new simple time zone called “My Custom Time Zone” which has a –4 hour offset from GMT and observes daylight savings time.

TimeZoneInfo info = TimeZoneInfo.CreateCustomTimeZone(
    "My Custom Time Zone",
    new TimeSpan(-4, 0, 0),
    "My Custom Time Zone",
    "My Custom Time Zone",
    "My Custom Time Zone",
    new TimeZoneInfo.AdjustmentRule[] { },
    false);

How to serialize a time zone with TimeZoneInfo

One of the unique features of the TimeZoneInfo class is that it has a native method to serialize the time zone to a string.  The ToSerializedString method is unlike other serialization methods in that it doesn’t serialize to xml by default, but instead to a semicolon delimited list.  This serialized string can be stored to disk or some other location for later retrieval.

TimeZoneInfo info = TimeZoneInfo.Local;
string serialized = info.ToSerializedString();
 
This code produces the following output:

Eastern Standard Time;-300;(GMT-05:00) Eastern Time (US & Canada);Eastern Standard Time;Eastern Daylight Time;[01:01:0001;12:31:2006;60;[0;02:00:00;4;1;0;];[0;02:00:00;10;5;0;];][01:01:2007;12:31:9999;60;[0;02:00:00;3;2;0;];[0;02:00:00;11;1;0;];];

To deserialize the string back into a TimeZoneInfo class, you can use the FromSerializedString static method to create a new TimeZoneInfo object.

TimeZoneInfo info2 = TimeZoneInfo.FromSerializedString(serialized);
DotNetKicks Image

Posted in .Net, C# | 10 Comments »

DateTime vs. DateTimeOffset in .Net

Posted by Dan Rigsby on 23rd August 2008

Working with Dates and Times in .Net 3.5 Series:
Part 1: DateTime vs. DateTimeOffset in .Net
Part 2: TimeZone vs. TimeZoneInfo in .Net

MoonKnt_12 The DateTime data type has been around since .Net 1.0 and suited us well for a long time.  It simply defines a date and a time together and offers methods for working with these constructs. It is a struct and hence can’t be set to null.  This caused some people some problems over the years.  Especially when modeling a DateTime from the database, since in most databases like SQL Server, the datetime field can be null.  So, usually a null DateTime would be set to DateTime.MinValue.  However, this wasn’t the most optimal solution.

In .Net 2.0 nullable types were introduced.  Now, we could have a null DateTime by simply defining the field as  System.Nullable<DateTime> (or DateTime?) instead of the standard DateTime.  This allowed us to set the field to null, and pull the value using the Value property of the field.

In .Net 3.5 an entirely new date/time field was added called DateTimeOffset.  This data extends the DateTime to add in the concept of a timezone offset.  It is still a struct, so you need to use System.Nullable<DateTimeOffest> if you want to be able to have a null value. A DateTimeOffset value is not tied to a particular time zone, but can originate from any of a variety of time zones.  For example, there are can multiple timezones that represent the same offset such as UTC –6:00 which can be Central Time, Central American, Saskatchewan, or Guadalajara.  So you don’t know the timezone that the datetime represents, but you do know the offset.  This is all you need to perform comparisons to other DateTimeOffsets.

180px-PrimemeridianThe offset value represents the time difference between the current time and Greenwich Mean Time (GMT) this is known as Coordinated Universal Time (UTC).  GMT historically is the time when the sun crosses the Prime Meridian line which is located a 0 Longitude. IT is measured from the Greenwich Meridian Line at the Royal Observatory in Greenwich, England.  This is the place from where all time zones are measured. Even the atomic clocks of the world are adjusted by leap seconds to maintain synchronicity with GMT.

So why is UTC so important to software developers?  This may be an obvious answer to most, but if you haven’t been exposed to this, it’s because many applications need to be globalized and may be run in different timezones.  If someone enters in a date and time, is that relative to their timezone or the timezone the server is sitting on.  This can be vastly different and can really cause problems in your application.  Comparing all dates and times to the relative time of GMT allows applications to understand what the date and time actually represent.

What does DateTime and DateTimeOffest look like

Console.WriteLine(DateTime.Now);
Console.WriteLine(DateTimeOffset.Now);
 
datetime1
 
This print out shows the basic difference in the two types.  The DateTime shows the Date and Time, while the DateTimeOffset shows the Date, Time, and offset.  This offset represents the difference from GMT.  In this case 4 hours behind GMT.

How to convert from DateTime to DateTimeOffset

DateTime d1 = DateTime.Now;
DateTimeOffset o1 = new DateTimeOffset(d1);
DateTimeOffset of1 = new DateTimeOffset(d1, new TimeSpan(-5, 0, 0));
 
To convert a DateTime into a DateTimeOffset, you just need to pass the DateTime value into one of the constructors of the DateTimeOffset.  You could just pass the DateTime in (as in o1 above), or you can also pass in the DateTime and an offset (as in of1 above).  If you don’t supply an offset, then GMT is assumed.

How to convert from DateTimeOffest to DateTime

DateTimeOffset o2 = DateTimeOffset.Now;
DateTime d2 = o2.DateTime;
 
Converting a DateTimeOffset to a DateTime is easy.  Since the DateTimeOffset value contains all of the data of a DateTime field and more, there is a simple DateTime property on the DateTimeOffset struct that returns a DateTime representation of the value.

How to manually set DateTime and DateTimeOffset

DateTime dt1 = new DateTime(2008, 8, 22, 1, 0, 0);
DateTimeOffset do1 = new DateTimeOffset(2008, 8, 22, 1, 0, 0, new TimeSpan(-5, 0, 0));
Console.WriteLine(dt1);
Console.WriteLine(do1);
 
datetime2 
 
Manually setting a DateTimeOffset is very similar to setting the value of a DateTime.  The only difference is that you can also pass in a TimeSpan as the last argument that represents the GMT offset.

Arithmetic with Datetime and DateTimeOffest

DateTime dateTime1 = DateTime.Now;
DateTime dateTime2 = DateTime.UtcNow;
Console.WriteLine("{0} - {1} =", dateTime1, dateTime2);
Console.WriteLine(dateTime1 - dateTime2);

Console.WriteLine();

DateTimeOffset offset1 = DateTimeOffset.Now;
DateTimeOffset offset2 = DateTimeOffset.UtcNow;
Console.WriteLine("{0} - {1} =", offset1, offset2);
Console.WriteLine(offset1 - offset2);
 

datetime3

With this example we can see that the difference between Now and UtcNow is 0.  This means that the DateTimeOffset sees the UTC version of the time and the local version of the time as equal.  But what about something more complicated? Are 12 PM EST and 9AM PST equal?

DateTimeOffset ao1 = new DateTimeOffset(2008, 8, 22, 12, 0, 0, new TimeSpan(-5, 0, 0));
DateTimeOffset ao2 = new DateTimeOffset(2008, 8, 22, 9, 0, 0, new TimeSpan(-8, 0, 0));
Console.WriteLine(ao1 == ao2);
 
This code creates 2 times.  One is 12 PM August, 22 2008 and the second is 9 AM August, 22 2008.  However, the offsets for each are set for Eastern Standard time and Pacific Standard time respectively.  If we compare these two values, are they equal?  If you guessed “Yes”, then you are right.  The Equals() method of DateTimeOffset knows now to compare against the offsets.  This is incredibly useful when comparing times cared in different time zones.

When to use DateTime or DateTimeOffest

Use DateTimeOffest structure to work with dates and times whose offset (or difference) from UTC is known or when calculations need to be performed on dates that may be from different timezones. The DateTimeOffset value is also more portable from one computer to another than a DateTime value.  DateTimeOffset doesn’t necessarily replace DateTime though.  DateTime is still useful to represent a single date or time or when the timezone information is unknown or not important.  However most developers should explore using DateTimeOffest more in general use especially in enterprise level systems.

DateTime may also be the best type to represent a DateTime from the database since the DateTime fields in most databases don’t store timezone information.  In SQL Server 2008 a DateTimeOffset structure was introduced to the database as well.  This type is very comparable to the DateTimeOffset field in .Net.  So a good rule of thumb may be to use the corresponding types when mapping between SQL Server 2008 and .Net 3.5.

 

Update: Nicholas Allen posted a reminder of how to deal with DateTimeOffest fields when working with svcutil.exe: http://blogs.msdn.com/drnick/archive/2008/09/04/getting-better-time-formats.aspx

DotNetKicks Image

Posted in .Net, C# | 8 Comments »

C# Coding Standards

Posted by Dan Rigsby on 16th August 2006

Coding standards have consistantly been a source of pain for developers. Many are reluctant to accept them because they feel that the way the program is just fine. However when working in a agile environment or an environment where developers work on each other’s code, the need for standards becomes more evident. Money and time can be saved if any develper can quickly navigate code, figure out what is going on, and fix bugs.

On my team here at Interactive Intelligence we adopting more and more agile processes. A few months back I took it upon myself to come up with a standards document for our own coding. Everything we do is in C# so I naturally looked for what other people had put together and what Microsoft recommends. The overall goal was not only to make it easy to work on each other’s code more easily, but also to be able to pick up code snippets and samples from Microsoft and other parties and follow along. The end result has been the C# Coding Standards. This document is ever evolving as do most documents of this kind. It not only contains syntax suggestions, but also makes some developement recommendations.

Two of the biggest arguements about the standards doc are the use of tabs over spaces, and the prefix “m_” for private properties. At this time we prefer tabs as they are a symbol used to represent indention vs. other white spaces. As long as everyone follows the standards and sets all tabs to 4 spaces, then almost all of the benifets of using spaces become void. We prefer the prefix “m_” private properties because CLS compliance clearly states that variables can differ by no more than casing, using “camal case for private and pascal case for everything else” is not an option. The use of just a “_” prefix also isn’t CLS complaint.

Download: C# Coding Standards

Posted in Agile Development, C# | No Comments »