2 // TimeZoneTest.cs - NUnit Test Cases for the System.TimeZone struct
5 // Martin Baulig (martin@gnome.org)
6 // Sebastien Pouliot <sebastien@ximian.com>
8 // (C) 2002 Martin Baulig
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
12 using NUnit.Framework;
15 using System.Threading;
16 using System.Globalization;
17 using System.Runtime.Serialization.Formatters.Binary;
19 namespace MonoTests.System {
22 public class TimeZoneTest {
24 private void CET (TimeZone t1)
26 Assert.AreEqual("CET", t1.StandardName, "A01");
27 Assert.AreEqual("CEST", t1.DaylightName, "A02");
29 DaylightTime d1 = t1.GetDaylightChanges (2002);
30 Assert.AreEqual("03/31/2002 02:00:00", d1.Start.ToString ("G"), "A03");
31 Assert.AreEqual("10/27/2002 03:00:00", d1.End.ToString ("G"), "A04");
32 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "A05");
34 DaylightTime d2 = t1.GetDaylightChanges (1996);
35 Assert.AreEqual("03/31/1996 02:00:00", d2.Start.ToString ("G"), "A06");
36 Assert.AreEqual("10/27/1996 03:00:00", d2.End.ToString ("G"), "A07");
37 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "A08");
39 DateTime d3 = new DateTime (2002,2,25);
40 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "A09");
41 DateTime d4 = new DateTime (2002,4,2);
42 Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "A10");
43 DateTime d5 = new DateTime (2002,11,4);
44 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "A11");
46 Assert.AreEqual(36000000000L, t1.GetUtcOffset (d3).Ticks, "A12");
47 Assert.AreEqual(72000000000L, t1.GetUtcOffset (d4).Ticks, "A13");
48 Assert.AreEqual(36000000000L, t1.GetUtcOffset (d5).Ticks, "A14");
51 private void EST (TimeZone t1)
53 // It could be EST though...
54 //Assert.AreEqual("Eastern Standard Time", t1.StandardName, "B01");
55 //Assert.AreEqual("Eastern Daylight Time", t1.DaylightName, "B02");
57 DaylightTime d1 = t1.GetDaylightChanges (2002);
58 Assert.AreEqual("04/07/2002 02:00:00", d1.Start.ToString ("G"), "B03");
59 Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G"), "B04");
60 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "B05");
62 DaylightTime d2 = t1.GetDaylightChanges (1996);
63 Assert.AreEqual("04/07/1996 02:00:00", d2.Start.ToString ("G"), "B06");
64 Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G"), "B07");
65 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "B08");
67 DateTime d3 = new DateTime (2002,2,25);
68 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "B09");
69 DateTime d4 = new DateTime (2002,4,8);
70 Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "B10");
71 DateTime d5 = new DateTime (2002,11,4);
72 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "B11");
74 Assert.AreEqual(-180000000000L, t1.GetUtcOffset (d3).Ticks, "B12");
75 Assert.AreEqual(-144000000000L, t1.GetUtcOffset (d4).Ticks, "B13");
76 Assert.AreEqual(-180000000000L, t1.GetUtcOffset (d5).Ticks, "B14");
79 private void TST (TimeZone t1)
81 Assert.AreEqual("Tokyo Standard Time", t1.StandardName, "C01");
82 Assert.AreEqual("Tokyo Standard Time", t1.DaylightName, "C02");
84 DateTime d3 = new DateTime (2002,2,25);
85 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "C09");
86 DateTime d4 = new DateTime (2002,4,8);
87 Assert.AreEqual(false, t1.IsDaylightSavingTime (d4), "C10");
88 DateTime d5 = new DateTime (2002,11,4);
89 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "C11");
91 Assert.AreEqual(324000000000L, t1.GetUtcOffset (d3).Ticks, "C12");
92 Assert.AreEqual(324000000000L, t1.GetUtcOffset (d4).Ticks, "C13");
93 Assert.AreEqual(324000000000L, t1.GetUtcOffset (d5).Ticks, "C14");
96 private void GMT (TimeZone t1) {
97 // Probably wont work on MS.NET, but is better than nothing. Where do
98 // we change our implementation to match theirs?
100 Assert.AreEqual("GMT", t1.StandardName, "D01");
101 Assert.IsTrue("BST" == t1.DaylightName || "IST" == t1.DaylightName, "D02");
103 DaylightTime d1 = t1.GetDaylightChanges (2002);
104 Assert.AreEqual("03/31/2002 01:00:00", d1.Start.ToString ("G"), "D03");
105 Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G"), "D04");
106 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "D05");
108 DaylightTime d2 = t1.GetDaylightChanges (1996);
109 Assert.AreEqual("03/31/1996 01:00:00", d2.Start.ToString ("G"), "D06");
110 Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G"), "D07");
111 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "D08");
113 DateTime d3 = new DateTime (2002,2,25);
114 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "D09");
115 DateTime d4 = new DateTime (2002,4,2);
116 Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "D10");
117 DateTime d5 = new DateTime (2002,11,4);
118 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "D11");
120 Assert.AreEqual(0L, t1.GetUtcOffset (d3).Ticks, "D12");
121 Assert.AreEqual(36000000000L, t1.GetUtcOffset (d4).Ticks, "D13");
122 Assert.AreEqual(0L, t1.GetUtcOffset (d5).Ticks, "D14");
125 private void NZST(TimeZone t1) {
126 Assert.AreEqual("NZST", t1.StandardName, "E01");
127 Assert.AreEqual("NZDT", t1.DaylightName, "E02");
129 DaylightTime d1 = t1.GetDaylightChanges (2013);
130 Assert.AreEqual("09/29/2013 02:00:00", d1.Start.ToString ("G"), "E03");
131 Assert.AreEqual("04/07/2013 03:00:00", d1.End.ToString ("G"), "E04");
132 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "E05");
134 DaylightTime d2 = t1.GetDaylightChanges (2001);
135 Assert.AreEqual("10/07/2001 02:00:00", d2.Start.ToString ("G"), "E06");
136 Assert.AreEqual("03/18/2001 03:00:00", d2.End.ToString ("G"), "E07");
137 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "E08");
139 DateTime d3 = new DateTime(2013,02,15);
140 Assert.AreEqual(true, t1.IsDaylightSavingTime (d3), "E09");
141 DateTime d4 = new DateTime(2013,04,30);
142 Assert.AreEqual(false, t1.IsDaylightSavingTime (d4), "E10");
143 DateTime d5 = new DateTime(2013,11,03);
144 Assert.AreEqual(true, t1.IsDaylightSavingTime (d5), "E11");
146 Assert.AreEqual(36000000000L /*hour*/ * 13L, t1.GetUtcOffset (d3).Ticks, "E12");
147 Assert.AreEqual(36000000000L /*hour*/ * 12L, t1.GetUtcOffset (d4).Ticks, "E13");
148 Assert.AreEqual(36000000000L /*hour*/ * 13L, t1.GetUtcOffset (d5).Ticks, "E14");
153 public void TestCtors ()
155 TimeZone t1 = TimeZone.CurrentTimeZone;
156 switch (t1.StandardName) {
160 case "Eastern Standard Time":
164 case "Tokyo Standard Time":
174 NUnit.Framework.Assert.Ignore ("Your time zone (" + t1.StandardName + ") isn't defined in the test case");
180 public void CurrentTimeZone_SerializationRoundtrip ()
182 TimeZone tz = TimeZone.CurrentTimeZone;
183 BinaryFormatter bf = new BinaryFormatter ();
184 MemoryStream ms = new MemoryStream ();
185 bf.Serialize (ms, tz);
188 TimeZone clone = (TimeZone) bf.Deserialize (ms);
190 Assert.AreEqual (tz.DaylightName, clone.DaylightName, "DaylightName");
191 Assert.AreEqual (tz.StandardName, clone.StandardName, "StandardName");
194 static private byte[] serialized_timezone = {
195 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00,
196 0x1C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x54,
197 0x69, 0x6D, 0x65, 0x5A, 0x6F, 0x6E, 0x65, 0x04, 0x00, 0x00, 0x00, 0x17, 0x6D, 0x5F, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x44, 0x61,
198 0x79, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x43, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x73, 0x0D, 0x6D, 0x5F, 0x74, 0x69, 0x63, 0x6B, 0x73, 0x4F,
199 0x66, 0x66, 0x73, 0x65, 0x74, 0x0E, 0x6D, 0x5F, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x4E, 0x61, 0x6D, 0x65, 0x0E, 0x6D,
200 0x5F, 0x64, 0x61, 0x79, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x4E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x01, 0x01, 0x1C, 0x53, 0x79, 0x73, 0x74,
201 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x48, 0x61, 0x73, 0x68, 0x74, 0x61, 0x62,
202 0x6C, 0x65, 0x09, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x29, 0x17, 0xD6, 0xFF, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x15,
203 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6D, 0x65, 0x0A,
204 0x04, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F,
205 0x6E, 0x73, 0x2E, 0x48, 0x61, 0x73, 0x68, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x4C, 0x6F, 0x61, 0x64, 0x46,
206 0x61, 0x63, 0x74, 0x6F, 0x72, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x08, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x72, 0x65, 0x72,
207 0x10, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6F, 0x64, 0x65, 0x50, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x72, 0x08, 0x48, 0x61, 0x73, 0x68,
208 0x53, 0x69, 0x7A, 0x65, 0x04, 0x4B, 0x65, 0x79, 0x73, 0x06, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73, 0x00, 0x00, 0x03, 0x03, 0x00, 0x05,
209 0x05, 0x0B, 0x08, 0x1C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73,
210 0x2E, 0x49, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x72, 0x65, 0x72, 0x24, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C,
211 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x49, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6F, 0x64, 0x65, 0x50, 0x72, 0x6F, 0x76, 0x69,
212 0x64, 0x65, 0x72, 0x08, 0xEC, 0x51, 0x38, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
213 0x00, 0x09, 0x05, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x08, 0xCC, 0x07, 0x00, 0x00, 0x08,
214 0x08, 0xD5, 0x07, 0x00, 0x00, 0x08, 0x08, 0xD2, 0x07, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x06,
215 0x00, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x21, 0x53, 0x79, 0x73,
216 0x74, 0x65, 0x6D, 0x2E, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x44, 0x61, 0x79, 0x6C,
217 0x69, 0x67, 0x68, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x07, 0x6D, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x05, 0x6D,
218 0x5F, 0x65, 0x6E, 0x64, 0x07, 0x6D, 0x5F, 0x64, 0x65, 0x6C, 0x74, 0x61, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x0C, 0x00, 0x10, 0xFA, 0x0F,
219 0x3D, 0xF2, 0xBC, 0x88, 0x00, 0x50, 0xD5, 0xB1, 0xC1, 0x91, 0xBD, 0x88, 0x00, 0x68, 0xC4, 0x61, 0x08, 0x00, 0x00, 0x00, 0x01, 0x07,
220 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x50, 0x23, 0xFA, 0x07, 0x06, 0xC7, 0x88, 0x00, 0xD0, 0xE2, 0xC4, 0x0C, 0xAB, 0xC7,
221 0x88, 0x00, 0x68, 0xC4, 0x61, 0x08, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0C, 0x0F,
222 0xEF, 0xAB, 0xC3, 0x88, 0x00, 0x90, 0xE7, 0xB0, 0x73, 0x4B, 0xC4, 0x88, 0x00, 0x68, 0xC4, 0x61, 0x08, 0x00, 0x00, 0x00, 0x0B
226 [Category ("NotWorking")]
227 // 1.x - deserialize but strings are null
228 // 2.x - eexception when creating a datetime with a negative value
229 public void DeserializeKnownValue ()
231 MemoryStream ms = new MemoryStream (serialized_timezone);
232 BinaryFormatter bf = new BinaryFormatter ();
233 TimeZone tz = (TimeZone) bf.Deserialize (ms);
234 Assert.AreEqual ("Eastern Daylight Time", tz.DaylightName, "DaylightName");
235 Assert.AreEqual ("Eastern Standard Time", tz.StandardName, "StandardName");
239 public void ToLocalTimeAtDSTBoundaries ()
241 TimeZone tz = TimeZone.CurrentTimeZone;
242 DateTime dst_start_utc = tz.GetDaylightChanges(2007).Start.ToUniversalTime ();
244 if (dst_start_utc == DateTime.MinValue)
245 Assert.Ignore ("Couldn't get beginning of daylight saving time in 2007.");
246 Assert.IsTrue (tz.ToLocalTime (dst_start_utc.Subtract (new TimeSpan (0, 1, 0))) < tz.ToLocalTime (dst_start_utc), "0:1:59 < 0:3:00");
247 Assert.IsTrue (tz.ToLocalTime (dst_start_utc) < tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (0, 1, 0))), "0:3:00 < 0:3:01");
248 Assert.IsTrue (tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (0, 1, 0))) < tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (0, 59, 0))), "0:3:01 < 0:3:59");
249 Assert.IsTrue (tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (0, 59, 0))) < tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (1, 0, 0))), "0:3:59 < 0:4:00");
250 Assert.IsTrue (tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (1, 0, 0))) < tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (1, 1, 0))), "0:4:00 < 0:4:01");
254 public void GetUtcOffsetAtDSTBoundary ()
257 * Getting a definitive list of timezones which do or don't observe Daylight
258 * Savings is difficult (can't say America's or USA definitively) and lengthy see
260 * http://en.wikipedia.org/wiki/Daylight_saving_time_by_country
262 * as a good starting point for a list.
264 * The following are SOME of the timezones/regions which do support daylight savings.
268 * USA (EST, CST, MST, PST, AKST) note this does not cover all states or regions
269 * Europe/London (GMT)
270 * CET (member states of the European Union)
272 * This test should work in all the above timezones
276 TimeZone tz = TimeZone.CurrentTimeZone;
277 int year = DateTime.Now.Year;
278 DaylightTime daylightChanges = tz.GetDaylightChanges(year);
279 DateTime dst_end = daylightChanges.End;
281 if (dst_end == DateTime.MinValue)
282 Assert.Ignore (tz.StandardName + " did not observe daylight saving time during " + year + ".");
284 var standardOffset = tz.GetUtcOffset(daylightChanges.Start.AddMinutes(-1));
286 Assert.AreEqual(standardOffset, tz.GetUtcOffset (dst_end));
287 Assert.AreEqual(standardOffset, tz.GetUtcOffset (dst_end.Add (daylightChanges.Delta.Negate ().Add (TimeSpan.FromSeconds(1)))));
288 Assert.AreEqual(standardOffset, tz.GetUtcOffset (dst_end.Add(daylightChanges.Delta.Negate ())));
289 Assert.AreNotEqual(standardOffset, tz.GetUtcOffset (dst_end.Add(daylightChanges.Delta.Negate ().Add (TimeSpan.FromSeconds(-1)))));
294 public void StaticProperties ()
296 Assert.IsNotNull (TimeZoneInfo.Local, "Local");
297 Assert.IsNotNull (TimeZoneInfo.Utc, "Utc");
301 public void FindSystemTimeZoneById ()
303 TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById ("Canada/Eastern");
304 Assert.AreEqual ("EDT", tzi.DaylightName, "DaylightName");
305 Assert.AreEqual ("EST", tzi.StandardName, "StandardName");
306 Assert.IsTrue (tzi.SupportsDaylightSavingTime, "SupportsDaylightSavingTime");
310 // On device we cannot read the OS file system to look for /etc/localtime
311 // and /usr/share/zoneinfo - so we must initialize the BCL TimeZoneInfo
312 // from NSTimeZoneInfo. The tests here check the code paths between the
313 // two types - if they break then TimeZoneInfo work work at all
314 // ref: http://bugzilla.xamarin.com/show_bug.cgi?id=1790
316 bool incomplete_data_on_simulator_only_bug;
319 public void GetSystemTimeZones ()
321 // if test is executed a second time then it report less than 400 (about 127) items available
322 if (incomplete_data_on_simulator_only_bug)
323 Assert.Ignore ("known to fail on some iOS simulator versions - see source comments");
326 Assert.That (TimeZoneInfo.GetSystemTimeZones ().Count, Is.GreaterThan (400), "GetSystemTimeZones");
327 } catch (NullReferenceException) {
328 // that's a weird one. It failed on iOS 5.1 *beta* simulator (on Lion) but it worked on *final*
329 // now it fails on Snow Leopard the same way (incomplete data) with iOS5 simulator (OS update ?)
330 // but it *never*ever* failed on devices
331 incomplete_data_on_simulator_only_bug = true;
333 if (ObjCRuntime.Runtime.Arch == ObjCRuntime.Arch.SIMULATOR)
335 if (MonoTouch.ObjCRuntime.Runtime.Arch == MonoTouch.ObjCRuntime.Arch.SIMULATOR)
337 Assert.Ignore ("known to fail on some iOS simulator versions - see source comments");