Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / corlib / Test / System / TimeZoneTest.cs
1 //
2 // TimeZoneTest.cs - NUnit Test Cases for the System.TimeZone struct
3 //
4 // Authors:
5 //      Martin Baulig (martin@gnome.org)
6 //      Sebastien Pouliot  <sebastien@ximian.com>
7 //
8 //   (C) 2002 Martin Baulig
9 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
10 //
11
12 using NUnit.Framework;
13 using System;
14 using System.IO;
15 using System.Threading;
16 using System.Globalization;
17 using System.Reflection;
18 using System.Runtime.Serialization.Formatters.Binary;
19
20 namespace MonoTests.System {
21
22 [TestFixture]
23 public class TimeZoneTest {
24
25         private void CET (TimeZone t1) 
26         {
27                 Assert.IsTrue("CET" == t1.StandardName || "W. Europe Standard Time" == t1.StandardName, "A01");
28                 Assert.IsTrue("CEST" == t1.DaylightName || "W. Europe Daylight Time" == t1.DaylightName, "A02");
29         
30                 DaylightTime d1 = t1.GetDaylightChanges (2002);
31                 Assert.AreEqual("03/31/2002 02:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "A03");
32                 Assert.AreEqual("10/27/2002 03:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "A04");
33                 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "A05");
34         
35                 DaylightTime d2 = t1.GetDaylightChanges (1996);
36                 Assert.AreEqual("03/31/1996 02:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "A06");
37                 Assert.AreEqual("10/27/1996 03:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "A07");
38                 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "A08");
39         
40                 DateTime d3 = new DateTime (2002,2,25);
41                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "A09");
42                 DateTime d4 = new DateTime (2002,4,2);
43                 Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "A10");
44                 DateTime d5 = new DateTime (2002,11,4);
45                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "A11");
46         
47                 Assert.AreEqual(36000000000L, t1.GetUtcOffset (d3).Ticks, "A12");
48                 Assert.AreEqual(72000000000L, t1.GetUtcOffset (d4).Ticks, "A13");
49                 Assert.AreEqual(36000000000L, t1.GetUtcOffset (d5).Ticks, "A14");
50
51                 // Test TimeZone methods with UTC DateTime in DST.
52                 DateTime d6 = d4.ToUniversalTime ();
53                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "A15");
54                 Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "A16");
55         }
56
57         private void EST (TimeZone t1) 
58         {
59                 Assert.IsTrue("EST" == t1.StandardName || "Eastern Standard Time" == t1.StandardName, "B01");
60                 Assert.IsTrue("EDT" == t1.DaylightName || "Eastern Daylight Time" == t1.DaylightName, "B02");
61
62                 DaylightTime d1 = t1.GetDaylightChanges (2002);
63                 Assert.AreEqual("04/07/2002 02:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "B03");
64                 Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "B04");
65                 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "B05");
66
67                 DaylightTime d2 = t1.GetDaylightChanges (1996);
68                 Assert.AreEqual("04/07/1996 02:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "B06");
69                 Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "B07");
70                 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "B08");
71
72                 DateTime d3 = new DateTime (2002,2,25);
73                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "B09");
74                 DateTime d4 = new DateTime (2002,4,8);
75                 Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "B10");
76                 
77                 DateTime d5 = new DateTime (2002,11,4);
78                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "B11");
79
80                 Assert.AreEqual(-180000000000L, t1.GetUtcOffset (d3).Ticks, "B12");
81                 Assert.AreEqual(-144000000000L, t1.GetUtcOffset (d4).Ticks, "B13");
82                 Assert.AreEqual(-180000000000L, t1.GetUtcOffset (d5).Ticks, "B14");
83
84                 // Test TimeZone methods with UTC DateTime in DST.
85                 DateTime d6 = d4.ToUniversalTime ();
86                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "B15");
87                 Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "B16");
88         }
89
90         private void TST (TimeZone t1) 
91         {
92                 Assert.AreEqual("Tokyo Standard Time", t1.StandardName, "C01");
93                 Assert.AreEqual("Tokyo Standard Time", t1.DaylightName, "C02");
94
95                 DateTime d3 = new DateTime (2002,2,25);
96                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "C09");
97                 DateTime d4 = new DateTime (2002,4,8);
98                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d4), "C10");
99                 DateTime d5 = new DateTime (2002,11,4);
100                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "C11");
101
102                 Assert.AreEqual(324000000000L, t1.GetUtcOffset (d3).Ticks, "C12");
103                 Assert.AreEqual(324000000000L, t1.GetUtcOffset (d4).Ticks, "C13");
104                 Assert.AreEqual(324000000000L, t1.GetUtcOffset (d5).Ticks, "C14");
105         }
106
107         private void GMT (TimeZone t1) {
108                 // Probably wont work on MS.NET, but is better than nothing. Where do
109                 // we change our implementation to match theirs?
110                 
111                 Assert.AreEqual("GMT", t1.StandardName, "D01");
112                 Assert.IsTrue("BST" == t1.DaylightName || "IST" == t1.DaylightName, "D02");
113         
114                 DaylightTime d1 = t1.GetDaylightChanges (2002);
115                 Assert.AreEqual("03/31/2002 01:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "D03");
116                 Assert.AreEqual("10/27/2002 02:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "D04");
117                 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "D05");
118         
119                 DaylightTime d2 = t1.GetDaylightChanges (1996);
120                 Assert.AreEqual("03/31/1996 01:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "D06");
121                 Assert.AreEqual("10/27/1996 02:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "D07");
122                 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "D08");
123         
124                 DateTime d3 = new DateTime (2002,2,25);
125                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d3), "D09");
126                 DateTime d4 = new DateTime (2002,4,2);
127                 Assert.AreEqual(true, t1.IsDaylightSavingTime (d4), "D10");
128                 DateTime d5 = new DateTime (2002,11,4);
129                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d5), "D11");
130         
131                 Assert.AreEqual(0L, t1.GetUtcOffset (d3).Ticks, "D12");
132                 Assert.AreEqual(36000000000L, t1.GetUtcOffset (d4).Ticks, "D13");
133                 Assert.AreEqual(0L, t1.GetUtcOffset (d5).Ticks, "D14");
134
135                 // Test TimeZone methods with UTC DateTime in DST.
136                 DateTime d6 = d4.ToUniversalTime ();
137                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "D15");
138                 Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "D16");
139         }
140
141         private void NZST(TimeZone t1) {
142                 Assert.AreEqual("NZST", t1.StandardName, "E01");
143                 Assert.AreEqual("NZDT", t1.DaylightName, "E02");
144
145                 DaylightTime d1 = t1.GetDaylightChanges (2013);
146                 Assert.AreEqual("09/29/2013 02:00:00", d1.Start.ToString ("G", CultureInfo.InvariantCulture), "E03");
147                 Assert.AreEqual("04/07/2013 03:00:00", d1.End.ToString ("G", CultureInfo.InvariantCulture), "E04");
148                 Assert.AreEqual(36000000000L, d1.Delta.Ticks, "E05");
149
150                 DaylightTime d2 = t1.GetDaylightChanges (2001);
151                 Assert.AreEqual("10/07/2001 02:00:00", d2.Start.ToString ("G", CultureInfo.InvariantCulture), "E06");
152                 Assert.AreEqual("03/18/2001 03:00:00", d2.End.ToString ("G", CultureInfo.InvariantCulture), "E07");
153                 Assert.AreEqual(36000000000L, d2.Delta.Ticks, "E08");
154
155                 DateTime d3 = new DateTime(2013,02,15);
156                 Assert.AreEqual(true, t1.IsDaylightSavingTime (d3), "E09");
157                 DateTime d4 = new DateTime(2013,04,30);
158                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d4), "E10");
159                 DateTime d5 = new DateTime(2013,11,03);
160                 Assert.AreEqual(true, t1.IsDaylightSavingTime (d5), "E11");
161
162                 Assert.AreEqual(36000000000L /*hour*/ * 13L, t1.GetUtcOffset (d3).Ticks, "E12");
163                 Assert.AreEqual(36000000000L /*hour*/ * 12L, t1.GetUtcOffset (d4).Ticks, "E13");
164                 Assert.AreEqual(36000000000L /*hour*/ * 13L, t1.GetUtcOffset (d5).Ticks, "E14");
165
166                 // Test TimeZone methods with UTC DateTime in DST.
167                 DateTime d6 = d5.ToUniversalTime ();
168                 Assert.AreEqual(false, t1.IsDaylightSavingTime (d6), "E15");
169                 Assert.AreEqual(0, t1.GetUtcOffset (d6).Ticks, "E16");
170         }
171
172         [Test]
173         public void TestCtors ()
174         {
175                 TimeZone t1 = TimeZone.CurrentTimeZone;
176                 switch (t1.StandardName) {
177                         case "W. Europe Standard Time":
178                         case "CET":
179                                 CET (t1);
180                                 break;
181                         case "Eastern Standard Time":
182                         case "EST":
183                                 EST (t1);
184                                 break;
185                         case "Tokyo Standard Time":
186                                 TST (t1);
187                                 break;
188                         case "GMT":
189                                 GMT (t1);
190                                 break;
191                         case "NZST":
192                                 NZST (t1);
193                                 break;
194                         default:
195                                 NUnit.Framework.Assert.Ignore ("Your time zone (" + t1.StandardName + ") isn't defined in the test case");
196                                 break;
197                 }
198         }
199
200         [Test]
201         public void CurrentTimeZone_SerializationRoundtrip ()
202         {
203                 TimeZone tz = TimeZone.CurrentTimeZone;
204                 BinaryFormatter bf = new BinaryFormatter ();
205                 MemoryStream ms = new MemoryStream ();
206                 bf.Serialize (ms, tz);
207
208                 ms.Position = 0;
209                 TimeZone clone = (TimeZone) bf.Deserialize (ms);
210
211                 Assert.AreEqual (tz.DaylightName, clone.DaylightName, "DaylightName");
212                 Assert.AreEqual (tz.StandardName, clone.StandardName, "StandardName");
213         }
214
215         static private byte[] serialized_timezone = {
216                 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 
217                 0x1C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6E, 0x74, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x54, 
218                 0x69, 0x6D, 0x65, 0x5A, 0x6F, 0x6E, 0x65, 0x04, 0x00, 0x00, 0x00, 0x17, 0x6D, 0x5F, 0x43, 0x61, 0x63, 0x68, 0x65, 0x64, 0x44, 0x61, 
219                 0x79, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x43, 0x68, 0x61, 0x6E, 0x67, 0x65, 0x73, 0x0D, 0x6D, 0x5F, 0x74, 0x69, 0x63, 0x6B, 0x73, 0x4F, 
220                 0x66, 0x66, 0x73, 0x65, 0x74, 0x0E, 0x6D, 0x5F, 0x73, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x4E, 0x61, 0x6D, 0x65, 0x0E, 0x6D, 
221                 0x5F, 0x64, 0x61, 0x79, 0x6C, 0x69, 0x67, 0x68, 0x74, 0x4E, 0x61, 0x6D, 0x65, 0x03, 0x00, 0x01, 0x01, 0x1C, 0x53, 0x79, 0x73, 0x74, 
222                 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x48, 0x61, 0x73, 0x68, 0x74, 0x61, 0x62, 
223                 0x6C, 0x65, 0x09, 0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x29, 0x17, 0xD6, 0xFF, 0xFF, 0xFF, 0x06, 0x03, 0x00, 0x00, 0x00, 0x15, 
224                 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6E, 0x20, 0x53, 0x74, 0x61, 0x6E, 0x64, 0x61, 0x72, 0x64, 0x20, 0x54, 0x69, 0x6D, 0x65, 0x0A, 
225                 0x04, 0x02, 0x00, 0x00, 0x00, 0x1C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 
226                 0x6E, 0x73, 0x2E, 0x48, 0x61, 0x73, 0x68, 0x74, 0x61, 0x62, 0x6C, 0x65, 0x07, 0x00, 0x00, 0x00, 0x0A, 0x4C, 0x6F, 0x61, 0x64, 0x46, 
227                 0x61, 0x63, 0x74, 0x6F, 0x72, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x08, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x72, 0x65, 0x72, 
228                 0x10, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6F, 0x64, 0x65, 0x50, 0x72, 0x6F, 0x76, 0x69, 0x64, 0x65, 0x72, 0x08, 0x48, 0x61, 0x73, 0x68, 
229                 0x53, 0x69, 0x7A, 0x65, 0x04, 0x4B, 0x65, 0x79, 0x73, 0x06, 0x56, 0x61, 0x6C, 0x75, 0x65, 0x73, 0x00, 0x00, 0x03, 0x03, 0x00, 0x05, 
230                 0x05, 0x0B, 0x08, 0x1C, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 
231                 0x2E, 0x49, 0x43, 0x6F, 0x6D, 0x70, 0x61, 0x72, 0x65, 0x72, 0x24, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6D, 0x2E, 0x43, 0x6F, 0x6C, 0x6C, 
232                 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x73, 0x2E, 0x49, 0x48, 0x61, 0x73, 0x68, 0x43, 0x6F, 0x64, 0x65, 0x50, 0x72, 0x6F, 0x76, 0x69, 
233                 0x64, 0x65, 0x72, 0x08, 0xEC, 0x51, 0x38, 0x3F, 0x03, 0x00, 0x00, 0x00, 0x0A, 0x0A, 0x0B, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 
234                 0x00, 0x09, 0x05, 0x00, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x08, 0xCC, 0x07, 0x00, 0x00, 0x08, 
235                 0x08, 0xD5, 0x07, 0x00, 0x00, 0x08, 0x08, 0xD2, 0x07, 0x00, 0x00, 0x10, 0x05, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x09, 0x06, 
236                 0x00, 0x00, 0x00, 0x09, 0x07, 0x00, 0x00, 0x00, 0x09, 0x08, 0x00, 0x00, 0x00, 0x04, 0x06, 0x00, 0x00, 0x00, 0x21, 0x53, 0x79, 0x73, 
237                 0x74, 0x65, 0x6D, 0x2E, 0x47, 0x6C, 0x6F, 0x62, 0x61, 0x6C, 0x69, 0x7A, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2E, 0x44, 0x61, 0x79, 0x6C, 
238                 0x69, 0x67, 0x68, 0x74, 0x54, 0x69, 0x6D, 0x65, 0x03, 0x00, 0x00, 0x00, 0x07, 0x6D, 0x5F, 0x73, 0x74, 0x61, 0x72, 0x74, 0x05, 0x6D, 
239                 0x5F, 0x65, 0x6E, 0x64, 0x07, 0x6D, 0x5F, 0x64, 0x65, 0x6C, 0x74, 0x61, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x0C, 0x00, 0x10, 0xFA, 0x0F, 
240                 0x3D, 0xF2, 0xBC, 0x88, 0x00, 0x50, 0xD5, 0xB1, 0xC1, 0x91, 0xBD, 0x88, 0x00, 0x68, 0xC4, 0x61, 0x08, 0x00, 0x00, 0x00, 0x01, 0x07, 
241                 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x50, 0x23, 0xFA, 0x07, 0x06, 0xC7, 0x88, 0x00, 0xD0, 0xE2, 0xC4, 0x0C, 0xAB, 0xC7, 
242                 0x88, 0x00, 0x68, 0xC4, 0x61, 0x08, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x50, 0x0C, 0x0F, 
243                 0xEF, 0xAB, 0xC3, 0x88, 0x00, 0x90, 0xE7, 0xB0, 0x73, 0x4B, 0xC4, 0x88, 0x00, 0x68, 0xC4, 0x61, 0x08, 0x00, 0x00, 0x00, 0x0B
244         };
245
246         [Test]
247         [Category ("NotWorking")] 
248         // 1.x - deserialize but strings are null
249         // 2.x - eexception when creating a datetime with a negative value
250         public void DeserializeKnownValue ()
251         {
252                 MemoryStream ms = new MemoryStream (serialized_timezone);
253                 BinaryFormatter bf = new BinaryFormatter ();
254                 TimeZone tz = (TimeZone) bf.Deserialize (ms);
255                 Assert.AreEqual ("Eastern Daylight Time", tz.DaylightName, "DaylightName");
256                 Assert.AreEqual ("Eastern Standard Time", tz.StandardName, "StandardName");
257         }
258
259         [Test]
260         public void ToLocalTimeAtDSTBoundaries ()
261         {
262                 TimeZone tz = TimeZone.CurrentTimeZone;
263                 DateTime dst_start_utc = tz.GetDaylightChanges(2007).Start.ToUniversalTime ();
264
265                 if (dst_start_utc == DateTime.MinValue)
266                         Assert.Ignore ("Couldn't get beginning of daylight saving time in 2007.");
267                 Assert.IsTrue (tz.ToLocalTime (dst_start_utc.Subtract (new TimeSpan (0, 1, 0))) < tz.ToLocalTime (dst_start_utc), "0:1:59 < 0:3:00");
268                 Assert.IsTrue (tz.ToLocalTime (dst_start_utc) < tz.ToLocalTime (dst_start_utc.Add (new TimeSpan (0, 1, 0))), "0:3:00 < 0:3:01");
269                 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");
270                 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");
271                 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");
272         }
273
274                 [Test]
275                 public void GetUTCNowAtDSTBoundaries ()
276                 {
277                         TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 2, 0, 0), 3, 5, DayOfWeek.Sunday);
278
279                         TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule(new DateTime(1, 1, 1, 3, 0, 0), 10, 5, DayOfWeek.Sunday);
280
281                         TimeSpan delta = TimeSpan.FromMinutes(60.0);
282                         TimeZoneInfo.AdjustmentRule adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(new DateTime(1970, 1, 1), DateTime.MaxValue.Date, delta, startTransition, endTransition);
283                         TimeZoneInfo.TransitionTime startTrans = adjustment.DaylightTransitionStart;
284                         TimeZoneInfo.TransitionTime endTrans = adjustment.DaylightTransitionEnd;
285                         TimeZoneInfo.AdjustmentRule[] adjustments = { adjustment };
286
287                         TimeZoneInfo tzInfo = TimeZoneInfo.CreateCustomTimeZone("MY Standard Time", TimeSpan.Zero, "MST", "MST", "MDT", adjustments);
288
289                         // There is no .NET API to set timezone. Use reflection to assign time zone to the TimeZoneInfo.local field.
290                         FieldInfo localTimeZone = typeof(TimeZoneInfo).GetField("local", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
291                         localTimeZone.SetValue(null, tzInfo);
292
293                         DateTime st = new DateTime(2016, 3, 27, 1, 0, 0, DateTimeKind.Local);
294                         Assert.IsTrue (!tzInfo.IsDaylightSavingTime(st));       
295                         Assert.IsTrue (!tzInfo.IsAmbiguousTime(st));
296                         Assert.IsTrue ((TimeZoneInfo.ConvertTimeToUtc(st).Hour == 1));
297                         st = new DateTime(2016, 3, 27, 3, 0, 0, DateTimeKind.Local);
298                         Assert.IsTrue (tzInfo.IsDaylightSavingTime(st));        
299                         Assert.IsTrue (!tzInfo.IsAmbiguousTime(st));
300                         Assert.IsTrue ((TimeZoneInfo.ConvertTimeToUtc(st).Hour == 2));
301                         st = new DateTime(2016, 10, 30, 2, 0, 0, DateTimeKind.Local);
302                         Assert.IsTrue (tzInfo.IsDaylightSavingTime(st));        
303                         Assert.IsTrue (!tzInfo.IsAmbiguousTime(st));
304                         Assert.IsTrue ((TimeZoneInfo.ConvertTimeToUtc(st).Hour == 1));
305                         st = new DateTime(2016, 10, 30, 3, 0, 0, DateTimeKind.Local);
306                         Assert.IsTrue (!tzInfo.IsDaylightSavingTime(st));       
307                         Assert.IsTrue (tzInfo.IsAmbiguousTime(st));
308                         Assert.IsTrue ((TimeZoneInfo.ConvertTimeToUtc(st).Hour == 3));
309                         st = new DateTime(2016, 10, 30, 4, 0, 0, DateTimeKind.Local);
310                         Assert.IsTrue (!tzInfo.IsDaylightSavingTime(st));       
311                         Assert.IsTrue (!tzInfo.IsAmbiguousTime(st));
312                         Assert.IsTrue ((TimeZoneInfo.ConvertTimeToUtc(st).Hour == 4));
313                 }
314
315                 [Test]
316                 public void GetUtcOffsetAtDSTBoundary ()
317                 {
318                         /*
319                          * Getting a definitive list of timezones which do or don't observe Daylight
320                          * Savings is difficult (can't say America's or USA definitively) and lengthy see 
321                          *
322                          * http://en.wikipedia.org/wiki/Daylight_saving_time_by_country
323                          *
324                          * as a good starting point for a list.
325                          *
326                          * The following are SOME of the timezones/regions which do support daylight savings.
327                          *
328                          * Pacific/Auckland
329                          * Pacific/Sydney
330                          * USA (EST, CST, MST, PST, AKST) note this does not cover all states or regions
331                          * Europe/London (GMT)
332                          * CET (member states of the European Union)
333                          *
334                          * This test should work in all the above timezones
335                          */
336
337
338                         TimeZone tz = TimeZone.CurrentTimeZone;
339                         int year = DateTime.Now.Year;
340                         DaylightTime daylightChanges = tz.GetDaylightChanges(year);
341                         DateTime dst_end = daylightChanges.End;
342
343                         if (dst_end == DateTime.MinValue)
344                                 Assert.Ignore (tz.StandardName + " did not observe daylight saving time during " + year + ".");
345
346                         var standardOffset = tz.GetUtcOffset(daylightChanges.Start.AddMinutes(-1));
347                         var dstOffset = tz.GetUtcOffset(daylightChanges.Start.AddMinutes(61));
348
349                         Assert.AreEqual(standardOffset, tz.GetUtcOffset (dst_end));
350                         Assert.AreEqual(dstOffset, tz.GetUtcOffset (dst_end.Add (daylightChanges.Delta.Negate ().Add (TimeSpan.FromSeconds(1)))));
351                         Assert.AreEqual(dstOffset, tz.GetUtcOffset (dst_end.Add(daylightChanges.Delta.Negate ())));
352                         Assert.AreEqual(dstOffset, tz.GetUtcOffset (dst_end.Add(daylightChanges.Delta.Negate ().Add (TimeSpan.FromSeconds(-1)))));
353                 }
354
355
356                 [Test]
357                 public void StaticProperties ()
358                 {
359                         Assert.IsNotNull (TimeZoneInfo.Local, "Local");
360                         Assert.IsNotNull (TimeZoneInfo.Utc, "Utc");
361                 }
362                 
363                 [Test]
364                 public void FindSystemTimeZoneById ()
365                 {
366                         TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById (TimeZoneInfoTest.MapTimeZoneId ("Canada/Eastern"));
367                         Assert.IsTrue ("EDT" == tzi.DaylightName || "Eastern Daylight Time" == tzi.DaylightName, "DaylightName");
368                         Assert.IsTrue ("EST" == tzi.StandardName || "Eastern Standard Time" == tzi.StandardName, "StandardName");
369                         Assert.IsTrue (tzi.SupportsDaylightSavingTime, "SupportsDaylightSavingTime");
370                 }
371
372                 [Test]
373                 public void OldEraToLocalTime ()
374                 {
375                         TimeSpan offset = TimeSpan.Zero;
376                         var dto = new DateTimeOffset (new DateTime (1900, 1, 1).Ticks, offset);
377
378                         // Should never throw
379                         dto.ToLocalTime ();
380                 }
381
382 #if !WIN_PLATFORM
383                 // On device we cannot read the OS file system to look for /etc/localtime
384                 // and /usr/share/zoneinfo - so we must initialize the BCL TimeZoneInfo
385                 // from NSTimeZoneInfo. The tests here check the code paths between the
386                 // two types - if they break then TimeZoneInfo work work at all
387                 // ref: http://bugzilla.xamarin.com/show_bug.cgi?id=1790
388                 
389                 bool incomplete_data_on_simulator_only_bug;
390
391                 [Test]
392                 public void GetSystemTimeZones ()
393                 {
394                         // if test is executed a second time then it report less than 400 (about 127) items available
395                         if (incomplete_data_on_simulator_only_bug)
396                                 Assert.Ignore ("known to fail on some iOS simulator versions - see source comments");
397                         
398                         try {
399                                 Assert.That (TimeZoneInfo.GetSystemTimeZones ().Count, Is.GreaterThan (400), "GetSystemTimeZones");
400                         } catch (NullReferenceException) {
401                                 // that's a weird one. It failed on iOS 5.1 *beta* simulator (on Lion) but it worked on *final*
402                                 // now it fails on Snow Leopard the same way (incomplete data) with iOS5 simulator (OS update ?)
403                                 // but it *never*ever* failed on devices
404                                 incomplete_data_on_simulator_only_bug = true;
405 #if MONOTOUCH
406
407 #if XAMCORE_2_0
408                                 if (ObjCRuntime.Runtime.Arch == ObjCRuntime.Arch.SIMULATOR)
409 #elif MONOTOUCH
410                                 if (MonoTouch.ObjCRuntime.Runtime.Arch == MonoTouch.ObjCRuntime.Arch.SIMULATOR)
411 #endif
412                                         Assert.Ignore ("known to fail on some iOS simulator versions - see source comments");
413 #endif // MONOTOUCH
414                         }
415                 }
416 #endif
417         }
418 }