Time Zones in the .NET Framework [Anthony Moore]

Time Zones in the .NET Framework [Anthony Moore]

  • Comments 20

The single most requested individual feature for the Base Class Libraries that has not been delivered yet is for support for Time Zones other than Local and UTC. This is a feature we are actively exploring for the next release of the .NET Framework.

 

To tide people over, we recently released an updated sample that supports the following scenarios:

-         Enumeration of Time Zones from the Windows Registry.

-         Conversion of a DateTime instance between Time Zones.

 

The sample can be downloaded from here:

http://download.microsoft.com/download/4/5/5/4555538c-6002-4f04-8c58-2b304af92402/converttimezone.exe

 

The sample is similar to one that was available in the SDK previously. However, the previous sample did not adjust conversions for Daylight Savings Time. This sample does account for Daylight Savings time in the same way that the DateTime class itself accounts for it for local times. In fact, we used some of the same testing code to verify it.

 

For those of you that need Time Zone support, we are definitely interested in finding out what your scenarios are. Here are some examples of scenarios under discussion:

-         Support for retrieving and changing the Local Time Zone.

-         The ability to serialize Time Zone information, for example in the case of storing the information for a recurring meeting.

-         Support for Time Zones with rules that change from year to year.

-         Ability to pick up time zone data from the operating system.

-         Ability to add a custom time zone.

-         A data type with a DateTime and a Time Zone offset.

 

People are often not specific when they request Time Zone support, so if this is something you need, if you can clarify the specific scenarios that are valuable, it will help us build a better product.

  • Something that I would definitely find useful is a data type that supported ToString() formats that could print out the timezone (eg. EST or CST) and an equivalent Parse() or ParseExact() that could parse those 3-letter timezones.  

    IIRC those are only used in North America but the majority of the code I write is for North America so it'd be a very useful addition.
  • My vote is for covering these areas, in order of preference (which you listed, so I'll just steal your words and add some comments):

    - Support for Time Zones with rules that change from year to year
    ---- hopefully for say, given a time zone and a date anywhere from the past 100 years and going forward, you could tell me what the offset is (with daylight savings taken into consideration, obviously)

    - The ability to serialize Time Zone information, for example in the case of storing the information for a recurring meeting

    - A data type with a DateTime and a Time Zone offset
  • Well here is an example of why I want something or something easier. We are a global fortune 500 company, we have plants all over the world in several time zones. Some that follow the rules and some that don’t (i.e. The places that manually change not by some rules.) We have them in the northern hemisphere and the southern (i.e. winter and summer flip flopped). Now where is the problem I have to deal with all the time. Proprietary EDI formats or some other EDI formats. All of our business is manufacturing and we receive EDI formats from all over the world in multiple formats. We are also on a just in time shipping model. Which means we get orders sometimes an hour or two before they must be shipped, and the parts are not even built yet, but there is a truck on it’s way to pick them up. As a side note all EDI formats come in as flat text files.

    Ok easy enough except when you get some order from a customer that is in say West European Time Zone that comes in a proprietary customer format that has the date and time the order is due, but absolutely no time zone in it or UTC offset. This is built this way because a WEST company placed an order to a WEST plant. However, here is the monkey in the works; all the servers are in a data center in the USA in EST. So I can not simply do a Convert.ToDateTime() on the time and process as that will take it as the local time and apply a UTC offset of EST. Also I can not simply set a standard add hours to it because Europe and the USA do not convert daylight savings time at the same time. So there would be a couple weeks in there that we would be off by an hour. I could parse the string and add in a UTC Offset but again when I set that offset it becomes a matter of when are they +1 and when are they + 2. Now I have written a ton of my own algorithms and over time I have refined them pretty well to solve these problems but the countries that do not follow any DST rules and kind of do their own thing and change when ever the government says they will change. It gets even worse like this year I think the US is extending DST so that will change my algorithms. At least I put in a way to manually override any country via and XML config file but still there needs to be an easier way. It would be nice if we just had some thing we could call and figure out what the UTC was in a time zone and have this way be scalable and reliable so every year I do not have to go out and figure out what countries, states, regions, are changing what timezone and when. It is easy to get the UTC Offset of the server and do math but still kind of a hassle. Anyway that has been my pains with the time zones and DST hope that gives you some kind of insight into what at least I would want and how I would use them. Oh yeah and do not even throw parts of India in there with their times off not a normal hour but by half hours that’s even a more brutal calculation.

    I will check out the new sample you have and see how different that is from mine. I think the primary difference is I made my own config files for the when certain places changed times or if they did or didn’t. Oh yeah I know the best thing would be to tell the customer to change and add the UTC offset to the flat files we get. But they are way bigger than us and the answer we pretty much get is that is our standard of doing it. We would love to get this stuff in XML format but I do not see it happening anytime soon.
  • Everything that you've mentioned would be cool, but honestly... the ability to convert a UTC date to any TimeZone would already cover 99% of my needs.
    Of course, the DateTime structure should have some knowledge of which TimeZone it is in, but it shouldn't be a huge problem if this proves to be too difficult. The work-around would be to ensure that one always moves dates around in UTC and only converts them to a specific TimeZone for display purposes. That does come without a performance cost of course, but it would be doable.
    The ability to add custom timezones using code or configuration files would be nice as well.

    By the way, on a sidenote: finally, finally, finally :-)
  • I did talk about a particular time zone issue earlier today....
    And I see that Anthony posted about...
  • I remember I was utterly surprised about System.DateTime having no support for timezones.

    I consider the original timezone offset being part of the precision of a date/time value.

    I'd want a future DateTime data type to correctly support round-tripping (ToString->[Try]Parse in a different TZ) almost all date/time formats found on the web today, including but not limited to the formats used by HTTP/RSS/RDF/ATOM and XML Schema.

    There's a nice write-up at http://www.hackcraft.net/web/datetime/.

    But then again, the large cross-section with localization, e.g. names of days, months, time zones, might make the implementation a real nightmare.
  • Somewhat related:

    Using System.Diagnostic.EventLog.WriteEntry(source, message)

    ...if I am writing messages using a common source, and using the static method, and not concerning myself with initing, opening, closing endIniting the source, the dates of the log entries jump forward one hour when the time changes.
    This is a minor concern for our application, but if there was some more information on exactly what is causing this, I would be interested.

    On another topic, I would have thought that

    DateTime dt1 = DateTime.Now().ToUniniversalTime()

    would equal

    DateTime dt2 = dt1.ToUniversalTime()

    ...but it doesn't.

    As Michael Kaplan echoes Raymond Chen, the complexities here are unintuitive and the problems vary by domain. Good luck in getting this right AND making it interoperate with legacy code.
  • > People are often not specific when they request Time Zone support

    Please support the tz database syntax
    http://www.twinsun.com/tz/tz-link.htm
    ftp://elsie.nci.nih.gov/pub/
  • We’ve taken a break on blogging since shipping Whidbey. As our team is gearing up for Orcas, we decided...
  • This will be a welcome addition to the Framework.  I'm the IT Director for a major relocation company and our business is going global in a big way right now.  

    Increased support for time zones would really be a nice touch and would save us money (since my programmers wouldn't have to write or support the code).  In the meantime, I'll take a look at that demo app.

  • One scenario to consider is converting a time from say UTC to another timezone in the past.  Sounds simple, but what happens if the zone that you're converting to has in the interim changed whether they support DST or even their timezone?

    This happens, and would required a full tracking of each timezone legislative change.  In the US, we've modified the date of when DST starts/stops on several occassions and it's up for change again.  Within the US, parts of Indiana

    I've always thought that the "local" timezone of the participant of the Transaction needs to be recorded alongside the "server" timestamp.  This gives me a persisted view of what the situation was at the time of transaction.  If I only have 1 date to work from and it's in the past, there's no guarantee that it will be the correct TZ conversion unless the underlying libraries keep track of all the law updates per timezone and location.
  • Matthew van Eerde (Maurits) suggests you "support the tz database syntax" and, without elaborating, provides links to the tz database Web page.

    One cannot write software that correctly handles world time zones and daylight saving times (summer times) without a complete, well-maintained database of those data, which are Byzantine. The only such database that exists and can be called authoritative is the tz database, commonly refered to as the Olson database. As the Web page explains, "This database (often called tz or zoneinfo) is used by several implementations, including the GNU C Library used in GNU/Linux, FreeBSD, NetBSD, OpenBSD, Cygwin, DJGPP, HP-UX, IRIX, Mac OS X, OpenVMS, Solaris, Tru64, and UnixWare." In other words, almost everything but Windows.

    The C# code posted here includes comments like this: "In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. Note, the summer in the southern hemisphere begins late in the year." And this: "In northern hemisphere, the daylight saving time starts in the middle of the year." Even if there's some strange truth behind these oddly-worded observations, they have no meaningful relationship to time zone boundaries or daylight saving time conventions. Nothing time zone-wise happens universally in either hemisphere. I'm not sure what the code is attempting to do, or how.
  • Thanks very much everyone for this great feedback. We can apply this directly to decisions about which scenarios within the feature to do and how to prioritize them.

    In particular, it is interesting to see the priority placed on serializing a set of time zone data, and making the system extensible enough to support something like Olson.

    Responses to some specific feedback:

    >>On another topic, I would have thought that

    >>DateTime dt1 = DateTime.Now().ToUniniversalTime()

    >> would equal

    >> DateTime dt2 = dt1.ToUniversalTime()

    That would equal DateTime.UtcNow, but the call to DateTime.Now clobbers the original date.

    >> The C# code posted here includes comments like this: "In southern hemisphere, the daylight saving time starts later in the year, and ends in the beginning of next year. Note, the summer in the southern hemisphere begins late in the year."

    This comment is merely indicating that you need to account for situations where DST starts later in the year and finishes early in the next year, so you will notice the range comparison needs to differ. This usually happens in the Southern hemisphere, but this is logic based on the data and not a heuristic or guess.

    Thanks again for your feedback on this topic. Please keep it coming to help us build a better feature!



  • Thanks for the reply.

    I understand what happens - DateTime has no indication of TimeZone, so it always assumes that "ToUniversalTime() is a local timezone and simply applies the offset.

    Perhaps a better example to show what I mean is that:

    DateTime.UtcNow != DateTime.UtcNow.ToUniversalTime()

    // Even though it is already Universal time, it still re-evaluates. This is obvious if you know the limitations of the class, but not obvious from the method name to a casual user. No big deal, just thought I would point out that in actual code I was writing, I tried converting things to UTC for comparisons, not concerning myself if it had already been done, and it turned out, obviously, incorrect.
  • > DateTime.UtcNow != DateTime.UtcNow.ToUniversalTime()

    This was true in v1.1.  In v2.0, calls to ToUniversalTime() and ToLocalTime() are idempotent.  Calling ToUniversalTime() on DateTime.UtcNow should not change the value at all.  Calling ToUniversalTime on DateTime.Now will convert the value the first time, but future calls will not change the time again.

    (For that specific line, you are evaluating UtcNow twice, so they will be somewhat different.  But I don't think that's what you're referring to.)

    Katy King
    BCL Test
Page 1 of 2 (20 items) 12