43. Time zone chart

This problem highlights several techniques and difficulties that arise when dealing with multiple time zones. When the example solution starts, it uses the following code to prepare the program for use:

// Display the time zones.
private void Form1_Load(object sender, EventArgs e)
{
// Don't hide the selection when the ListView doesn't have focus.
timesListView.HideSelection = false;
timesListView.FullRowSelect = true;

// List the time zones.
foreach (TimeZoneInfo info in TimeZoneInfo.GetSystemTimeZones())
{
timeZone0ComboBox.Items.Add(info);
timeZone1ComboBox.Items.Add(info);
}

// In the first ComboBox, select the computer's time zone.
timeZone0ComboBox.SelectedItem = TimeZoneInfo.Local;

// In the second ComboBox, select the first time zone.
timeZone1ComboBox.SelectedIndex = 0;

// Display the first time chart.
MakeTimeChart();
}

The form displays its time zone chart in a ListView control. This code first sets that control's HideSelection property to false so the control keeps its selected row highlighted, even when the control loses the focus. The code also sets the control's FullRowSelect property to true, so clicking on any part of one of the control's rows selects the entire row.

Next, the code loops through the system's time zone information and adds the information to the form's two ComboBox controls.

Sometimes, you can simply assign a ComboBox or ListView control's DataSource property to a collection holding the choices that you want to display. If you do that, however, any controls that use the collection are bound to it. In this example, that would mean that if you selected an entry in one ComboBox, then the other ComboBox would select the same entry. That won't work if you want to let the user select two different time zones.

The code then selects the computer's current time zone in the first ComboBox and the first time zone choice in the second.

The code finishes by calling the following MakeTimeChart method to display the time zone table:

// Make the time chart.
private void MakeTimeChart()
{
timesListView.Items.Clear();

// Make sure we have the values we need.
if (timeZone0ComboBox.SelectedIndex == -1) return;
if (timeZone1ComboBox.SelectedIndex == -1) return;

// Get the selected time zones.
TimeZoneInfo timeZone0 =
timeZone0ComboBox.SelectedItem as TimeZoneInfo;
TimeZoneInfo timeZone1 =
timeZone1ComboBox.SelectedItem as TimeZoneInfo;

// Get midnight in the time zones.
DateTime time0 = new DateTime(
dateTimePicker1.Value.Year,
dateTimePicker1.Value.Month,
dateTimePicker1.Value.Day,
0, 0, 0, DateTimeKind.Unspecified);
DateTime time1 = TimeZoneInfo.ConvertTime(time0, timeZone0,
timeZone1);

// Display the time zone names in the ListView column headers.
if (timeZone0.IsDaylightSavingTime(time0))
timesListView.Columns[0].Text = timeZone0.DaylightName;
else
timesListView.Columns[0].Text = timeZone0.StandardName;
if (timeZone1.IsDaylightSavingTime(time1))
timesListView.Columns[1].Text = timeZone1.DaylightName;
else
timesListView.Columns[1].Text = timeZone1.StandardName;

// Process 24 hours.
for (int hour = 1; hour <= 24; hour++)
{
// Display the time in the first time zone.
string text0 = time0.ToShortTimeString();
if (timeZone0.IsAmbiguousTime(time0)) text0 += " [AMBIGUOUS]";
if (timeZone0.IsInvalidTime(time0)) text0 += " [INVALID]";
ListViewItem item = timesListView.Items.Add(text0);

// Display the time in the second time zone.
if (!timeZone0.IsInvalidTime(time0))
{
time1 = TimeZoneInfo.ConvertTime(time0, timeZone0,
timeZone1);
string text1 = time1.ToShortTimeString();
if (timeZone1.IsAmbiguousTime(time1)) text1 += "
[AMBIGUOUS]";
if (timeZone1.IsInvalidTime(time1)) text1 += " [INVALID]";
if (time0.Date < time1.Date) text1 += " (tomorrow)";
else if (time0.Date > time1.Date) text1 += " (yesterday)";
item.SubItems.Add(text1);
}

// Move to the next hour.
time0 = time0.AddHours(1);
}

// Select the current hour.
DateTime localTime = new DateTime(
dateTimePicker1.Value.Year,
dateTimePicker1.Value.Month,
dateTimePicker1.Value.Day,
DateTime.Now.Hour,
0, 0, DateTimeKind.Unspecified);
localTime = TimeZoneInfo.ConvertTime(localTime,
TimeZoneInfo.Local, timeZone0);
timesListView.Items[localTime.Hour].Selected = true;
timesListView.EnsureVisible(localTime.Hour);
}

This method first clears the ListView control. It then verifies that both time zone choices have been made. (When the program is first loading, this method may be called before both ComboBox controls have been initialized. If that happens, the method simply returns.)

Next, the code gets the two selected time zones. Because the program added TimeZoneInfo objects to the ComboBox controls, the code can convert the selected items back into TimeZoneInfo objects.

The method then gets the date selected by the program's DateTimePicker control. The DateTime structure has a Kind field that indicates the type of time value. That property can be Local (to the computer), Utc (Coordinated Universal Time), or Unspecified. This program starts with times in the time zone selected in the first ComboBox. Because that is not necessarily the computer's local time zone, we need to work with an Unspecified time. Unfortunately, the DateTimePicker control assumes that it is working with local times, so its Value property gives a Local time.

To fix that, the code sets time0 to a new DateTime, initialized with the same year, month, and day selected by the user. It sets the hours, minutes, and seconds to zero, so the time represents midnight on the morning of the selected date.

Now that is has an Unspecified time, the code uses the TimeZoneInfo.ConvertTime method to convert the time from the first time zone to the second.

The time zone values displayed in the ComboBox controls are somewhat unwieldy, so the code displays the time zone names in the ListView control's columns. Notice how the code displays different names depending on whether the selected time is observing Daylight Saving Time.

Next, the method loops over 24 hours to create its table. First, it formats time0 as a short time string. It then checks whether that time is ambiguous or invalid. This is one of the trickiest issues when working with time.

In the United States, if Daylight Saving Time starts on the selected date, then the clocks skip forward an hour at 2:00 AM on that date so the times between 1:59 AM and 3:00 AM do not exist in that time zone. If you look closely at the screenshot in the problem statement, you'll see that 2:00 AM in the first time zone is marked as invalid.

Conversely, if Daylight Saving Time ends on the selected date, then the clocks skip backward an hour at 2:00 AM so that times between 1:00 AM and 1:59 AM occur twice on that day. That makes those hours ambiguous. (If you schedule an appointment for 1:00 AM, do you mean the first one or the second one?)

In the European Union, Summer Time begins and ends at 1:00 UTC. In much of Africa and Asia, and parts of South America, countries do not change their clocks seasonally. Fortunately, you don't need to know all of the rules for every country. You can simply create the appropriate DateTime structure and then use the TimeZoneInfo object's IsAmbiguousTime and IsInvalidTime methods to determine whether a time is ambiguous or invalid.

After it composes a reasonable string for the first time zone, the method adds it to the ListView control.

Next, if the time is valid in the first time zone, the code uses the TimeZoneInfo.ConvertTime method to convert it to the second time zone. (The ConvertTime method throws an exception if the time is invalid.) The code then performs similar steps to build a string for the second time zone. If the new time is during the previous or following day in the second time zone, the code also adds an indication to the new string. After it composes the string for the second time zone, the method displays it as a ListView sub-item.

The code then adds one hour to time0 and repeats the loop until it has displayed the full 24 hours.

The method finishes by selecting the current hour on the selected date. To do that, it creates a new DateTime variable named localTime that represents the selected date's year, month, and day, plus the current hour. It then uses TimeZoneInfo.ConvertTime to convert that time into the first time zone. The method selects the ListView item that corresponds to that hour and ensures that the item is visible.

Download the TimeZoneChart example solution to see additional details.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset