Converting DateTime values to arbitrary TimeZones
Dealing with dates and times across geographies is an ongoing challenge for many people. One of the aspects of that challenge is that in .NET, it is not easily possible to format a time for display, using an arbitrary timezone. It is possible of course, but it requires too much work.
Now comes word of the PublicDomain project on CodePlex. This project is completely public domain, and includes a variety of classes that address different topics. One of those topics is the issue of time zones.
The TzTimeZone class included in that project is a good one. It lets your app instantiate any arbitrary timezone (US Pacific, or the timezone in Paris, or the timezone in Shanghai) and then use that thing. One use case is to format a time value (DateTime) into a format which makes sense in the specified timezone. So if I have a time of 12noon in New York, I can format that same DateTime value for the timezone in Shanghai. This addresses a narrow but very common use case in distributed applications. This is commonly needed in heterogeneous distributed apps, for example where a Java-based service is running in NYC and is connected to a .NET service that is running in Shanghai. This class makes it really simple.
Just by reading the description of what the class does, you might be tempted to conclude that this is a very simple class. Actually it is pretty simple in concept but in execution it gets very complex, because there are differences with timezone shifts and "Daylight savings time" type issues, both currently and also going back in time. The DST shifts for various timezones did not happen at the same time in 2007 as they did in 2004. All of this intellligence is encapsulated into the TzTimeZone class.
Here's a quick sample that illustrates the new capability provided by the TzTimeZone class (I've also attached this source code to this post):
1 // DifferentTimeZones.cs
2 //
3 // This sample illustrates the use of the TzTimeZone class that is included in the
4 // PublicDomain project on Codeplex: https://www.codeplex.com/publicdomain.
5 //
6 // The System.TimeZone as included in .NET 2.0 does not permit an
7 // application to instantiate a TimeZone object given a shorthand name of
8 // the timezone, or a UTC offset. Instead, the System.TimeZone class
9 // "knows" about the local timezone but doesn't do much else. This makes
10 // it difficult to take an arbitrary time (say, 3:13pm, October 4th 2006,
11 // in Los Angeles) and format it for display in an arbitrary other timezone
12 // (say, Paris).
13 //
14 // The TzTimeZone class provides a model for a number of different
15 // timezones, including their offsets from UTC and the rules they apply for
16 // daylight savings time.
17 //
18 // With this new set of classes, it is possible to instantiate a timezone
19 // from a well-known set of named instances. It is also easy to format a
20 // time value w.r.t. any arbitrary (named) timezone. In particular, it is
21 // easy to take a time like (3:13pm October 4th 2006, in Los Angeles) and
22 // format it for display in Paris.
23 //
24 // Mon, 08 Oct 2007 13:37
25
26
27 using System;
28 using PublicDomain; // for TzTmeZone, TzDateTime, etc
29
30
31 public class ShowDifferentTimeZones
32 {
33
34 public static DateTime GenerateTime()
35 {
36 System.Random rnd= new System.Random();
37 System.DateTime value;
38 int[] data= new int[] {
39 2005+rnd.Next(4), // year
40 rnd.Next(12)+1, // month
41 rnd.Next(28)+1, // dayOfMonth
42 rnd.Next(24), // hourOfDay
43 rnd.Next(60), // minute
44 rnd.Next(60) // second
45 };
46
47 value= new System.DateTime(data[0],
48 data[1],
49 data[2],
50 data[3],
51 data[4],
52 data[5]);
53 return value;
54 }
55
56
57 int _count= 0;
58 System.DateTime _time;
59
60 public void SetTime(System.DateTime time)
61 {
62 _time= time.ToUniversalTime();
63 _count = 0;
64 }
65
66 public void ShowZones()
67 {
68 // Local timezone
69 ShowOneZone(TzTimeZone.CurrentTimeZone);
70
71 // other cities
72 ShowOneZone(TzTimeZone.GetTimeZone(TzConstants.TimezoneAmericaNewYork));
73 ShowOneZone(TzTimeZone.GetTimeZone(TzConstants.TimezoneAmericaLosAngeles));
74 ShowOneZone(TzTimeZone.GetTimeZone(TzConstants.TimezoneAmericaArgentinaBuenosAires));
75 ShowOneZone(TzTimeZone.GetTimeZone(TzConstants.TimezoneEuropeParis));
76 ShowOneZone(TzTimeZone.GetTimeZone(TzConstants.TimezoneAsiaTokyo));
77 ShowOneZone(TzTimeZone.GetTimeZone(TzConstants.TimezoneAsiaShanghai));
78 }
79
80
81 private void ShowOneZone(TzTimeZone zone)
82 {
83 string formatString= "{0,-32} {1,-8} {2,-10} {3,10} {4,-32}";
84 if (_count == 0)
85 {
86 Console.WriteLine();
87 Console.WriteLine(formatString, "standard name",
88 "Is DST?",
89 "short name",
90 "UTC offset",
91 "the time");
92 Console.WriteLine("--------------------------------------------------------------------------------------------");
93 _count++;
94 }
95
96 //TzDateTime dt1 = TzDateTime.Now(zone1);
97
98 // Note: be careful using the TzDateTime constructor!
99 // --------------------------------------------------
100 // the following form says: create a new TzDateTime, and override any timezone
101 // information and set it to the given. If I am in Chicago and I pass in a time of 8:45am
102 // and specify the zone as "paris" , then I will get a TzDateTime of 8:45am in Paris.
103 //TzDateTime dt1 = new TzDateTime(_time, zone);
104
105 // These two statements say - give me a new TzDateTime, and set the preferred "attached"
106 // timezone for this datetime be as specified. If I am in Chicago and pass in a time of 8:45am,
107 // and a zone of "paris", then I will get a TzDateTime that is 5:45pm in Paris.
108 TzDateTime dt1 = new TzDateTime(_time);
109 dt1.TimeZone= zone;
110
111 string TimeStringRelativeToSpecifiedZone=
112 dt1.DateTimeLocal.ToString("G") + " " + zone.GetAbbreviation();
113
114 Console.WriteLine(formatString,
115 zone.ToString(),
116 zone.IsDaylightSavingTime(dt1.DateTimeUtc),
117 zone.GetAbbreviation(),
118 zone.GetUtcOffset(dt1.DateTimeUtc),
119 TimeStringRelativeToSpecifiedZone);
120
121 // key
122 }
123
124
125
126
127 public void Run()
128 {
129 Console.WriteLine("\nHello from the TimeZones demonstration app.");
130
131 Console.WriteLine("\nIn the simplest case, we want to display a time, "+
132 "or more accurately, format a time value for display,"+
133 "with respect to a given timezone. Example:");
134
135 System.DateTime theTime = System.DateTime.Now;
136 TzDateTime dt1 = new TzDateTime(theTime, TzTimeZone.CurrentTimeZone);
137
138 TzDateTime dt2 = new TzDateTime(theTime.ToUniversalTime());
139 // here we explicitly apply a timezone
140 dt2.TimeZone= TzTimeZone.ZoneUsEastern;
141
142 Console.WriteLine("In '{0}' the time is: {1}\n"+
143 "This timezone is also known as '{2}' and the time might be written as {3}\n"+
144 "In '{4}' the same time is written as: {5}",
145 TimeZone.CurrentTimeZone.StandardName,
146 theTime.ToString("G"), // + " " + dt1.TimeZone.GetAbbreviation(),
147 dt1.TimeZone.ToString(),
148 dt1.DateTimeLocal.ToString("G") + " " + dt1.TimeZone.GetAbbreviation(),
149 dt2.TimeZone.ToString(),
150 dt2.DateTimeLocal.ToString("G") + " " + dt2.TimeZone.GetAbbreviation());
151
152
153
154 Console.WriteLine("\nNow a more general illustration. In each table, the times are all the same:");
155
156
157 SetTime(System.DateTime.Now);
158 ShowZones();
159
160 SetTime(GenerateTime());
161 ShowZones();
162 }
163
164
165
166
167
168 static void Main(String[] args)
169 {
170 try
171 {
172 ShowDifferentTimeZones me= new ShowDifferentTimeZones();
173 me.Run();
174 }
175 catch (Exception ex1)
176 {
177 Console.WriteLine("Exception: {0}", ex1);
178 }
179 }
180 }
181
Comments
- Anonymous
October 12, 2007
great examples, bookmarking now