Base types, Collections, Diagnostics, IO, RegEx…
Extended Time Zone support is one of the most requested features in the BCL. System.TimeZone provides some basic support for converting from your machine Time Zone to UTC and vice versa, but it doesn’t have support to convert… say from Pacific Standard Time to Eastern Standard Time. In the “Orcas” September CTP, you’ll see that the BCL team has added a new class named “System.TimeZone2” that will allow you to:
- Convert a DateTime from one time zone (not necessarily your machine’s time zone) to another
- Get an object that describes your local time zone
- Get an array of objects that describes all the available time zones on your machine
- Serialize a time zone into a string
- Create your own time zone object to represent any custom time zones
The best part about this is that… if you are on an Vista machine… all of those functionality will have Vista’s Dynamic Time Zone support, because our calculations are done with the time zone data available on your OS.
Without further ado, let me start by showing you some samples:
1) Getting the Local time zone on your machine:
2) Get all the time zone available on your machine and put it in a list box.
ListBox CreateTimeZoneListBox(ReadOnlyCollection<TimeZone2> systemTimeZones)
// Get all the time zone from your machine
systemTimeZones = TimeZone2.GetSystemTimeZones();
// Fill a list box
ListBox list = new ListBox();
foreach (TimeZone2 timeZone in systemTimeZones)
3) Get a particular time zone from the operating system by passing in an “Id”
The “Id” of your system time zone is basically the registry key name. A list can be found here.
// Get a particular time zone
// e.g. Time in Seattle
TimeZone2 pacificTZ =
TimeZone2.FindSystemTimeZoneById(“Pacific Standard Time”);
// e.g. Time in Hong Kong
TimeZone2 hongKongTZ =
TimeZone2.FindSystemTimeZoneById(“China Standard Time”);
// e.g. Time in Sydney
TimeZone2 sydneyTZ =
TimeZone2.FindSystemTimeZoneById(“AUS Eastern Standard Time”);
4) Get the information of a particular time zone
void PrintTimeZoneInformation(TimeZone2 timeZone)
// Prints the display name of the time zone
// “Pacific Standard Time” will print
// “(GMT-08:00) Pacific Time (US & Canada); Tijuana”
// Prints the base UTC Offset of the time zone
// Prints the UTC Offset of the time zone at a certain time
DateTime manOnMoon = new DateTime(1969, 9, 9);
// Prints whether a certain time is in the time zone’s daylight
// saving period
// Prints whether a certain time is in the missing hour
// during a daylight savings transition. I.e. during spring ahead
DateTime springAhead = new DateTime(2006, 4, 2, 2, 30, 0);
// Prints whether a certain time is the duplicate hour
// during a daylight savings transition. I.e. during fall back
DateTime fallBack = new DateTime(2006, 10, 29, 1, 30, 0);
5) Converting from one time zone to another… Oh Yeah!
This new class allows you to do conversions in two different ways:
a) Convert using TimeZone2.Id
b) Convert using TimeZone2 object
If you already have a TimeZone2 object handy, you can simply convert by passing in the TimeZone2 object.
// Let’s convert my favourite show…
// Battlestar Galactica Season 3 premier!
DateTime bsgSeason3 = new DateTime(2006, 10, 6, 9, 0, 0);
// What time is it in Hawaii when the BCL team and I are watching it?
DateTime bsgSeason3Hawaii = TimeZone2.ConvertTimeBySystemTimeZoneId(
“Pacific Standard Time”,
“Hawaiian Standard Time”);
// We can also convert it by passing in TimeZone2 objects!
TimeZone2 pacificTZ = TimeZone2.Local;
TimeZone2 hawaiiTZ =
TimeZone2.FindSystemTimeZoneById(“Hawaiian Standard Time”);
DateTime bsgSeason3Hawaii = TimeZone2.ConvertTime(
// Or… I just want to know what time it is in UTC
DateTime bsgSeason3Utc = TimeZone2.ConvertTimeToUtc(
// Or… from Utc to… Hawaii time
DateTime bsgSeason3Hawaii = TimeZone2.ConvertTimeFromUtc(
A key TimeZone2 concept is the “Time Zone Id”. A Time Zone Id is a string that represents a time zone on the local machine. Microsoft Windows comes preinstalled with over seventy unique time zones! Because there are no standardized ways of enumerating through time zones, we decided to use the Windows Registry Key name as the id to uniquely locate the preinstalled time zones on your machine. The IDs will be the same across all Windows machine regardless of OS language settings and will not be localized. Whereas, TimeZone2.DisplayName is a localized label of the TimeZone2 object. To help you find the “Time Zone Ids”, here is a table of Time Zone Ids and the locations they cover:
- Alphabetically sorted by “Time Zone Ids”
- Sorted by Offsets
The new TimeZone2 class can also allow developers to create their own TimeZone2 objects, compare two TimeZone2 objects, serialize the TimeZone2 object into a string and deserialize a string back to a TimeZone2 object. Since these are more advance features, I will cover them at a later date. I hope this set of examples will help you get started on using TimeZone2!
1) TimeZone2 resides in System.Core.dll. You can find this DLL in “C:\WINDOWS\Microsoft.NET\Framework\v3.5.60905”.
Check out my blog http://blogs.msdn.com/kathykam for more discussion of this new class, usage of the advance features and the design principles that I picked up from working on it!
I have posted my starter guide on the BCL team blog ! I'll post a follow up and advance usage here. :)
While I agree that this functionality is needed, I'm disappointed in both the name of the class and the namespace it was put in.
Since System.TimeZone is taken, why not just create a System.Globalization.TimeZone and mark the original one obsolete?
Do we need to be polluting the System namespace any more? Also, do we really want to resort to the class numbering? That's worse than "TimeZoneEx."
I am sorry you are disappointed in the name. According to the .NET Design Guidelines, if we were to obsolete a class and replace it with a new one. The correct way to do it is to name the new class as <class>2. It is unfortunate that we have to do it, but this class is realy a replacement of the exisiting System.TimeZone class. It doesn't belong in System.Globalization.
According to the Design Guidelines:
"Do use a numeric suffix to indicate a new version of an exisiting API if the existing name of the API is the only name that makes sense"
See page 47 in the .NET Design Guidelines for more details.
I like this new functionality, but I am also very disappointed by the name change, too. If the .NET Design Guidelines require that, you should change them (after all Microsoft wrote them...). Adding a numeric suffix to the class tells you nothing about the differences between the two classes and is very confusing. What happens if you make another change to the TimeZone class, do we have TimeZone, TimeZone2 and TimeZone3 then? And if the original TimeZone class is finally removed, we are stuck with a TimeZone2 class and nobody knows why it is not simply called TimeZone.
Couldn't you simply add the new members to the existing TimeZone class?
If there is really no way to replace the existing class/name, I would still prefer putting the class in another namespace or giving it a more meaningful name like ExtendedTimeZone (I am sure you can come up with an even better name).
Thanks for listening!
Thanks Thomas, we actually have the guideline of using numeric suffixes to new types when we expect previous versions will become entirely superseded by new types - and we like the guidance. The reason is in these cases, we do not want the difference between types to be ambiguous. Having a numeric specifier means "only use the newer type from here out." If we called it something like TimeZoneWithConversion, users may decide to use the original TimeZone class in scenarios where they do not plan on doing conversions, but that is not our intent for users with the type.
FYI The "EX" suffix is particularly problematic because then it becomes even more ugly to ship a third type in the rare case that is required.
Can't say I like the design. Why TimeZone2.Convert...(timeZone, dateTime) and not timeZone.Convert...(dateTime)?
Further more, until this very moment, you're still holding out on the redesign of TimeZone2. I don't see anything that couldn't be done with TimeZone. Heck, several people (including me), already implemented these features based on the appropriate registry keys using the original TimeZone class.
Or, is the real case you've implemented TimeZone2 (in System.Core.dll rather than System.dll), because you can't touch System.dll? I've seen the term "Red bits" several times, and that Orcas would a .NET 2.0 extension, not upgrade. That would explain a lot, but I'd still like TimeZone2 to be an extension of TimeZone.
timeZone.Convert is ambiguous as to whether you are converting to or from. We decided tat having it as a static method is more clear.
After much consideration, we've determined that updating TimeZone would cause too much breaking changes because of the Vista Dynamic Time Zone support. APIs like "GetUtcOffset" and "IsDaylightSavingTime" works on a totally different logic.
Great to see the new functionality. Awful to see the naming choice. Sure, it's in the guidelines but I'd be challenging those guidelines. I can't think of any other type that follows this convention so now would be a good time to challenge.
Please don't send .NET the way of Java: a plethora of confusing naming (guidelines or not) and deprecated crap all over the place. Push the CLR team for a better long-term solution if needs be.
Great job on that new functionality though.
Not that this is a great example...
Didn't I say it two weeks ago that API naming is the most difficult thing? :) My BCL post on System.TimeZone2
I have not looked at the documentation for TimeZone2 yet, so I do not know how much these overlap. If you are replacing TimeZone, then how about making both TimeZone and TimeZone2 derive from the same interface (ITimeZone). That way it will be easier to move current code to the new TimeZone2.
I am still very unhappy about DateTime. I would like to write my own replacement. Would you please either...
1) Provide an IDateTime (and update methods to the new signature), or
2) Unseal DateTime
I'm sorry but this is just horrible, and IMO the guidelines are flat out wrong on this one.
It totally defies the normal way of naming a variable - for what it does. The number appended has no meaning what so ever in regards to the class.
In my mind you have 2 choices:
1) Call it TimeZone and make it a breaking change. Yes, it will hurt some people in a one-time upgrade - but the alternative hurts people all of the time. Have the courage to realize that this really is just a breaking change, and implement it. It's not the first time breaking changes have been introduced in the framework.
2) If it really is so much different than the regular TimeZone, name it after it's purpose, say ConvertibleTimeZone. Yes, this probably requires some thought, but you must be able to do better than TimeZone2.
Appending a number is an ugly, ugly hack, and the author of that particular guideline should be flogged (Brad is that you?). I would hate seeing something like this in the framework:
DateTime3 dt3 = new DateTime3(new TimeZone4);
DateTime2 dt2 = dt3 - new DateTime2(new TimeZone3);
Kathy Kam asked for feedback on Timezone2, so tonight I decided to have a bit of a play and these are
The complete quote from the Framework Design Guidelines is:
"Do use a numeric suffix to indicate a new version of an existing API if the existing name of the API is the only name that makes sense (i.e., it is an industry standard), and adding any meaningful suffix (or changing the name) is not an appropriate option."
So there is no requirement to add a numeric suffix if you can add a "meaningful" suffix or change the name.
What about this?
Basing the internals off of the Windows registry makes sense, as most likely the software will be running on Windows. But TZ does so much more. Is the BCL team even aware of TZ and what it does? And if so, why not match the functionality? TimeZone's are a part of the BCL because people should be able to rely upon them with 100% certainty that they do everything they might need them to do. TimeZone didn't come close, and from what I've read so far, TimeZone2 still doesn't get the job done.