In mid-2003, someone in the Lounge asked for a list of time zones. I said that I had one, but the data was in a CodeBase/FoxBase file. Chris Maunder asked if I could retrieve that data and submit it to CodeProject. After procrastinating a few weeks, I decided to go ahead and not only extract the data, but to write a program to edit that data.
Of course, the simple project soon got more complex, then I had to move. Finally, almost two months after starting, it's mostly done. I say mostly, since I'm quite sure there are several bugs in the program and plenty of whistles and bells I could add, but it does fulfill the basic requirement of editing the time zone list.
For the curious, the
CTimeZone class was written to handle a situation in a client/server project where individual clients were sending data from multiple time zones. This data had to be filtered at the server according to the time-of-day restrictions local to the source of the data. In other words, we had to convert UTC time to local time with daylight saving time [DST] (note that it's saving, not savings) taken into consideration. The Win32 API provides no help in this situation.
CTimeZone is the core class of the
TimeZoneEditor applet. The current incarnation requires MFC, though this could quite easily be modified for your own purposes. I intentionally made all the data members
public. To enforce my own conventions, I should have added helper functions, but I wanted to keep the class as flexible as possible.
The class is commented, though not as well as it could be, so I won't bother repeating those comments here, but one difference between this class and the Win32
TIME_ZONE_INFORMATION structure is that I added
week to my
Date structure, whereas
TIME_ZONE_INFORMATION uses the
Day data member to specify this.
There is an enigma when resolving DST for a given time; when DST ends, the clocks are set back by one hour (i.e. from 2:00 a.m. to 1:00 a.m.) creating an overlap. If your base time for that zone is within this hour, you cannot determine whether it is daylight saving or standard time.
CTimeZone solves this by requiring that all times be expressed in standard time. In other words, any time falling within this hour is assumed to be standard time.
(Your clock doesn't have this problem since it's a state machine, so to speak. When DST ends, at the given time you set the clocks back and change the state to standard time simultaneously.)
TimeZoneEditor is used to edit the time zone data (see below). It is an MFC document/view application with a few dialog boxes. Besides the
CTimeZone class, the application uses three other classes that may be of interest to you:
CBSortPtrArray is from a class library I developed years ago for my own use and that of my employers/clients (the "CB" prefix is from a company I used to own). As the name implies, it is a sortable templated collection of pointers. There are other ways I could have accomplished what I was doing, but I already had this available and saw no reason to make more work for myself.
CStringArrayPlus is subclassed from MFC's
CStringArray. It adds the ability to sort strings, and some parsing functions which aren't used in this application.
CEditAlpha is subclassed from MFC's
CEdit. It overrides
OnChar and prevents anything but the letters A-Z and, optionally, digits, from being entered.
Time zone data
This is probably the most useful item of this article.
The time zone data is contained in two files. TimeZoneData.tzd is a comma delimited file which contains a list of time zones. Each time zone has a 1-4 character identifier and the information related to that time zone. TimeZoneData.tzd.locations is a comma delimited file containing locations and the identifier of which time zone they are in. (There is a many-to-one relationship between the lines of the latter file and the first one.)
Each location is a country, state, province, territory or island. If the location is part of a country, a comma and the country are added. If the location is a subset of a larger location, a compass direction or a descriptive word is added in parenthesis (i.e. "Saskatchewan (Lloydminster), Canada"). In general, if the vast bulk of the rest of the location falls within a different time zone, no indicator is given (i.e. "Saskatchewan, Canada").
Due to the aforementioned enigma, the end of DST (or "start" of standard time) will be one hour earlier than stated in the rule.
I started working on TimeZoneEditor with Visual Studio .NET (2002) and finished with VS.NET 2003. The
CTimeZone class was originally written using Visual Studio 6.0 and should work with it, but the rest of the app will not.
CTimeZone should work with UNICODE, however I have not yet tested it with that configuration.
While verifying and extending the time zone list, I found a lot of contradictory information. I also found that the time of day the change should be made is hard to find for many locations. In those cases, I have defaulted to use 2:00 a.m..
For more information on time zones, I highly recommend this web site[^]. I discovered this site after I had done most my research and have modified my data to comply with it since it does seem to be most authoritative (in some cases, it actually references a nation's law). However, there is no doubt that locations have changed their laws and/or the various sources are mistaken. Please post any change requests with the subject line "Data Change Request". Include an authoritative reference.
- 25th September, 2004
- CodeProject member Colin Urquhart found a bug in
GetNthDayOfWeek(). After mostly figuring out my own code, I realized there was more than one subtle bug related to this method and
GetNextDayOfWeek(). Colin and I figured out the core problem at the same time, and he made a brilliant suggestion for a fix which I implemented with some modifications. So, great thanks to Colin Urquhart. (And if the code still doesn't work, it's his fault.
- 10th October, 2004
- CodeProject member Eric Woodruff found a bug in
CCalcDlg::OnBnClickedCalc() where the day of week was not being set. To avoid the 2038 problem (not that I'll care - I'll be 76 and hopefully long retired), I chose to convert the time to file time and back again using
- 12th October, 2005
- CodeProject member gooshbob found a bug in
CTimeZone::GetDiff() where the daylight saving time bias wasn't being calculated right. A very important note was added about the United States changing the start and end dates of DST.
- 20th March, 2006
- In the original code, the method
CTimeZone::ConvertTime() would convert from UTC if the
pSourceZone parameter was NULL and to UTC if it was the same instance that was passed. This latter case was both confusing and problematic. I have moved this functionality to
CTimeZone::ConvertTimeToUTC(). Now, if "local" and "remote" time zones are the same, no conversion will happen. This will break the existing code that depends on the original behavior!
- 10th December, 2006
- Data has been updated to reflect the changes for the Energy Policy Act of 2005 which extended DST for the United States. Those Canadian provinces which follow DST, have adopted the same schedule as the United States. Other changes were made for the state of Indiana and several countries.
- 11th January, 2007
- Data has been updated. DST Bias now defaults to 60, instead of -60.