Merge pull request #1899 from saper/resgencond
[mono.git] / mcs / class / corlib / Test / System / TimeZoneInfoTest.cs
1 /*
2  * TimeZoneInfo.Tests
3  *
4  * Author(s)
5  *      Stephane Delcroix <stephane@delcroix.org>
6  *
7  * Copyright 2011 Xamarin Inc.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining
10  * a copy of this software and associated documentation files (the
11  * "Software"), to deal in the Software without restriction, including
12  * without limitation the rights to use, copy, modify, merge, publish,
13  * distribute, sublicense, and/or sell copies of the Software, and to
14  * permit persons to whom the Software is furnished to do so, subject to
15  * the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be
18  * included in all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27  */
28
29 using System;
30 using System.IO;
31 using System.Runtime.InteropServices;
32 using System.Runtime.Serialization.Formatters.Binary;
33 using System.Collections;
34 using System.Reflection;
35 using System.Globalization;
36
37 using NUnit.Framework;
38 namespace MonoTests.System
39 {
40         public class TimeZoneInfoTest
41         {
42                 static FieldInfo localField;
43                 static FieldInfo cachedDataField;
44                 static object localFieldObj;
45
46                 public static void SetLocal (TimeZoneInfo val)
47                 {
48                         if (localField == null) {
49                                 if (Type.GetType ("Mono.Runtime") != null) {
50                                         localField = typeof (TimeZoneInfo).GetField ("local",
51                                                         BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic);
52                                 } else {
53                                         cachedDataField = typeof (TimeZoneInfo).GetField ("s_cachedData",
54                                                         BindingFlags.Static | BindingFlags.GetField | BindingFlags.NonPublic);
55
56                                         localField = cachedDataField.FieldType.GetField ("m_localTimeZone",
57                                                 BindingFlags.Instance | BindingFlags.GetField | BindingFlags.NonPublic);
58                                 }
59                         }
60
61                         if (cachedDataField != null)
62                                 localFieldObj = cachedDataField.GetValue (null);
63
64                         localField.SetValue (localFieldObj, val);
65                 }
66
67                 [TestFixture]
68                 public class PropertiesTests
69                 {
70                         [Test]
71                         public void GetLocal ()
72                         {
73                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
74                                         Assert.Ignore ("Not running on Unix.");
75                                 TimeZoneInfo local = TimeZoneInfo.Local;
76                                 Assert.IsNotNull (local);
77                                 Assert.IsTrue (true);
78                         }
79
80                         [DllImport ("libc")]
81                         private static extern int readlink (string path, byte[] buffer, int buflen);
82
83                         [Test] // Covers #24958
84                         public void LocalId ()
85                         {
86                                 byte[] buf = new byte [512];
87
88                                 var path = "/etc/localtime";
89                                 try {
90                                         var ret = readlink (path, buf, buf.Length);
91                                         if (ret == -1)
92                                                 return; // path is not a symbolic link, nothing to test
93                                 } catch (DllNotFoundException e) {
94                                         return;
95                                 }
96
97                                 Assert.IsTrue (TimeZoneInfo.Local.Id != "Local", "Local timezone id should not be \"Local\"");
98                         }
99                 }
100
101                 [TestFixture]
102                 public class CreateCustomTimezoneTests
103                 {
104                         [Test]
105                         [ExpectedException (typeof (ArgumentNullException))]
106                         public void IdIsNullException ()
107                         {
108                                 TimeZoneInfo.CreateCustomTimeZone (null, new TimeSpan (0), null, null); 
109                         }
110                 
111                         [Test]
112                         [ExpectedException (typeof (ArgumentException))]
113                         public void IdIsEmptyString ()
114                         {
115                                 TimeZoneInfo.CreateCustomTimeZone ("", new TimeSpan (0), null, null);   
116                         }
117                 
118                         [Test]
119                         [ExpectedException (typeof (ArgumentException))]
120                         public void OffsetIsNotMinutes ()
121                         {
122                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (0, 0, 55), null, null);  
123                         }
124                 
125                         [Test]
126                         [ExpectedException (typeof (ArgumentOutOfRangeException))]
127                         public void OffsetTooBig ()
128                         {
129                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (14, 1, 0), null, null);
130                         }
131                 
132                         [Test]
133                         [ExpectedException (typeof (ArgumentOutOfRangeException))]
134                         public void OffsetTooSmall ()
135                         {
136                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", - new TimeSpan (14, 1, 0), null, null);
137                         }
138                 
139                 #if STRICT
140                         [Test]
141                         [ExpectedException (typeof (ArgumentException))]
142                         public void IdLongerThan32 ()
143                         {
144                                 TimeZoneInfo.CreateCustomTimeZone ("12345678901234567890123456789012345", new TimeSpan (0), null, null);        
145                         }       
146                 #endif
147                 
148                         [Test]
149                         [ExpectedException (typeof (InvalidTimeZoneException))]
150                         public void AdjustmentRulesOverlap ()
151                         {
152                                 TimeZoneInfo.TransitionTime s1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 3, 2, DayOfWeek.Sunday);
153                                 TimeZoneInfo.TransitionTime e1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 10, 2, DayOfWeek.Sunday);
154                                 TimeZoneInfo.AdjustmentRule r1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2000,1,1), new DateTime (2005,1,1), new TimeSpan (1,0,0), s1, e1);
155                                 TimeZoneInfo.TransitionTime s2 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 2, 2, DayOfWeek.Sunday);
156                                 TimeZoneInfo.TransitionTime e2 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 11, 2, DayOfWeek.Sunday);
157                                 TimeZoneInfo.AdjustmentRule r2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2004,1,1), new DateTime (2007,1,1), new TimeSpan (1,0,0), s2, e2);
158                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {r1, r2});
159                         }
160                 
161                         [Test]
162                         [ExpectedException (typeof (InvalidTimeZoneException))]
163                         public void RulesNotOrdered ()
164                         {
165                                 TimeZoneInfo.TransitionTime s1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 3, 2, DayOfWeek.Sunday);
166                                 TimeZoneInfo.TransitionTime e1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 10, 2, DayOfWeek.Sunday);
167                                 TimeZoneInfo.AdjustmentRule r1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2000,1,1), new DateTime (2005,1,1), new TimeSpan (1,0,0), s1, e1);
168                                 TimeZoneInfo.TransitionTime s2 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 2, 2, DayOfWeek.Sunday);
169                                 TimeZoneInfo.TransitionTime e2 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 11, 2, DayOfWeek.Sunday);
170                                 TimeZoneInfo.AdjustmentRule r2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2006,1,1), new DateTime (2007,1,1), new TimeSpan (1,0,0), s2, e2);
171                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {r2, r1});
172                         }
173                 
174                         [Test]
175                         [ExpectedException (typeof (InvalidTimeZoneException))]
176                         public void OffsetOutOfRange ()
177                         {
178                                 TimeZoneInfo.TransitionTime startTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 3, 2, DayOfWeek.Sunday);
179                                 TimeZoneInfo.TransitionTime endTransition = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 10, 2, DayOfWeek.Sunday);
180                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2000,1,1), new DateTime (2005,1,1), new TimeSpan (3,0,0), startTransition, endTransition);
181                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (12,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {rule});
182                         }
183                 
184                         [Test]
185                         [ExpectedException (typeof (InvalidTimeZoneException))]
186                         public void NullRule ()
187                         {
188                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (12,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {null});
189                         }
190                 
191                         [Test]
192                         [ExpectedException (typeof (InvalidTimeZoneException))]
193                         public void MultiplesRulesForDate ()
194                         {
195                                 TimeZoneInfo.TransitionTime s1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 3, 2, DayOfWeek.Sunday);
196                                 TimeZoneInfo.TransitionTime e1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 10, 2, DayOfWeek.Sunday);
197                                 TimeZoneInfo.AdjustmentRule r1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2000,1,1), new DateTime (2005,1,1), new TimeSpan (1,0,0), s1, e1);
198                                 TimeZoneInfo.TransitionTime s2 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 2, 2, DayOfWeek.Sunday);
199                                 TimeZoneInfo.TransitionTime e2 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 11, 2, DayOfWeek.Sunday);
200                                 TimeZoneInfo.AdjustmentRule r2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2005,1,1), new DateTime (2007,1,1), new TimeSpan (1,0,0), s2, e2);
201                                 TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {r1, r2});
202                         }
203
204                         [Test]
205                         public void SupportsDaylightSavingTime_NonEmptyAdjustmentRule ()
206                         {
207                                 TimeZoneInfo.TransitionTime s1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 3, 2, DayOfWeek.Sunday);
208                                 TimeZoneInfo.TransitionTime e1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 10, 2, DayOfWeek.Sunday);
209                                 TimeZoneInfo.AdjustmentRule r1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2000,1,1), new DateTime (2005,1,1), new TimeSpan (1,0,0), s1, e1);
210                                 TimeZoneInfo tz = TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {r1});
211                                 Assert.IsTrue (tz.SupportsDaylightSavingTime);
212                         }
213
214                         [Test]
215                         public void SupportsDaylightSavingTime_EmptyAdjustmentRule ()
216                         {
217                                 TimeZoneInfo tz = TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,null);
218                                 Assert.IsFalse (tz.SupportsDaylightSavingTime);
219                         }
220
221                         [Test]
222                         public void SupportsDaylightSavingTime_NonEmptyAdjustmentRule_DisableDaylightSavingTime ()
223                         {
224                                 TimeZoneInfo.TransitionTime s1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 3, 2, DayOfWeek.Sunday);
225                                 TimeZoneInfo.TransitionTime e1 = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,4,0,0), 10, 2, DayOfWeek.Sunday);
226                                 TimeZoneInfo.AdjustmentRule r1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (new DateTime (2000,1,1), new DateTime (2005,1,1), new TimeSpan (1,0,0), s1, e1);
227                                 TimeZoneInfo tz = TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,new TimeZoneInfo.AdjustmentRule[] {r1}, true);
228                                 Assert.IsFalse (tz.SupportsDaylightSavingTime);
229                         }
230
231                         [Test]
232                         public void SupportsDaylightSavingTime_EmptyAdjustmentRule_DisableDaylightSavingTime ()
233                         {
234                                 TimeZoneInfo tz = TimeZoneInfo.CreateCustomTimeZone ("mytimezone", new TimeSpan (6,0,0),null,null,null,null,true);
235                                 Assert.IsFalse (tz.SupportsDaylightSavingTime);
236                         }
237                 }
238                 
239                 [TestFixture]
240                 public class IsDaylightSavingTimeTests
241                 {
242                         TimeZoneInfo london;
243                 
244                         [SetUp]
245                         public void CreateTimeZones ()
246                         {
247                                 TimeZoneInfo.TransitionTime start = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
248                                 TimeZoneInfo.TransitionTime end = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
249                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
250                                 london = TimeZoneInfo.CreateCustomTimeZone ("Europe/London", new TimeSpan (0), "Europe/London", "British Standard Time", "British Summer Time", new TimeZoneInfo.AdjustmentRule [] {rule});
251                         }
252                 
253                         [Test]
254                         public void NoDSTInUTC ()
255                         {
256                                 DateTime june01 = new DateTime (2007, 06, 01);
257                                 Assert.IsFalse (TimeZoneInfo.Utc.IsDaylightSavingTime (june01));
258                         }
259                 
260                         [Test]
261                         public void DSTInLondon ()
262                         {
263                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
264                                         Assert.Ignore ("Not running on Unix.");
265                                 DateTime june01 = new DateTime (2007, 06, 01);
266                                 DateTime xmas = new DateTime (2007, 12, 25);
267                                 Assert.IsTrue (london.IsDaylightSavingTime (june01), "June 01 is DST in London");
268                                 Assert.IsFalse (london.IsDaylightSavingTime (xmas), "Xmas is not DST in London");
269                         }
270                 
271                         [Test]
272                         public void DSTTransisions ()
273                         {
274                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
275                                         Assert.Ignore ("Not running on Unix.");
276                                 DateTime beforeDST = new DateTime (2007, 03, 25, 0, 59, 59, DateTimeKind.Unspecified);
277                                 DateTime startDST = new DateTime (2007, 03, 25, 2, 0, 0, DateTimeKind.Unspecified);
278                                 DateTime endDST = new DateTime (2007, 10, 28, 1, 59, 59, DateTimeKind.Unspecified);
279                                 DateTime afterDST = new DateTime (2007, 10, 28, 2, 0, 0, DateTimeKind.Unspecified);
280                                 Assert.IsFalse (london.IsDaylightSavingTime (beforeDST), "Just before DST");
281                                 Assert.IsTrue (london.IsDaylightSavingTime (startDST), "the first seconds of DST");
282                                 Assert.IsFalse (london.IsDaylightSavingTime (endDST), "The last seconds of DST");
283                                 Assert.IsFalse (london.IsDaylightSavingTime (afterDST), "Just after DST");
284                         }
285                 
286                         [Test]
287                         public void DSTTransisionsUTC ()
288                         {
289                                 DateTime beforeDST = new DateTime (2007, 03, 25, 0, 59, 59, DateTimeKind.Utc);
290                                 DateTime startDST = new DateTime (2007, 03, 25, 1, 0, 0, DateTimeKind.Utc);
291                                 DateTime endDST = new DateTime (2007, 10, 28, 0, 59, 59, DateTimeKind.Utc);
292                                 DateTime afterDST = new DateTime (2007, 10, 28, 1, 0, 0, DateTimeKind.Utc);
293                                 Assert.IsFalse (london.IsDaylightSavingTime (beforeDST), "Just before DST");
294                                 Assert.IsTrue (london.IsDaylightSavingTime (startDST), "the first seconds of DST");
295                                 Assert.IsTrue (london.IsDaylightSavingTime (endDST), "The last seconds of DST");
296                                 Assert.IsFalse (london.IsDaylightSavingTime (afterDST), "Just after DST");
297                         }
298                 
299                 #if SLOW_TESTS
300                         [Test]
301                         public void MatchTimeZoneBehavior ()
302                         {
303                                 TimeZone tzone = TimeZone.CurrentTimeZone;
304                                 TimeZoneInfo local = TimeZoneInfo.Local;
305                                 for (DateTime date = new DateTime (2007, 01, 01, 0, 0, 0, DateTimeKind.Local); date < new DateTime (2007, 12, 31, 23, 59, 59); date += new TimeSpan (0,1,0)) {
306                                         date = DateTime.SpecifyKind (date, DateTimeKind.Local);
307                                         if (local.IsInvalidTime (date))
308                                                 continue;
309                                         Assert.IsTrue (tzone.IsDaylightSavingTime (date) == local.IsDaylightSavingTime (date));
310                                 }
311                         }
312                 #endif
313                         [Test (Description="Description xambug #17155")]
314                         public void AdjustmentRuleAfterNewYears ()
315                         {
316                                 TimeZoneInfo tz;
317                                 if (Environment.OSVersion.Platform == PlatformID.Unix)
318                                         tz = TimeZoneInfo.FindSystemTimeZoneById ("Pacific/Auckland"); // *nix
319                                 else
320                                         tz = TimeZoneInfo.FindSystemTimeZoneById ("New Zealand Standard Time"); // Windows
321
322                                 // DST start: 9/29/2013 2:00:00 AM
323                                 // DST end: 4/6/2014 3:00:00 AM
324                                 DateTime dt = new DateTime (2014, 1, 9, 23, 0, 0, DateTimeKind.Utc);
325                                 Assert.IsTrue (tz.IsDaylightSavingTime (dt), "#1.1");
326
327                                 // DST start: 9/29/2014 2:00:00 AM
328                                 // DST end: 4/6/2015 3:00:00 AM
329                                 dt = new DateTime (2014, 6, 9, 23, 0, 0, DateTimeKind.Utc);
330                                 Assert.IsFalse (tz.IsDaylightSavingTime (dt), "#2.1");
331
332                                 // DST start: 9/29/2014 2:00:00 AM
333                                 // DST end: 4/6/2015 3:00:00 AM
334                                 dt = new DateTime (2014, 10, 9, 23, 0, 0, DateTimeKind.Utc);
335                                 Assert.IsTrue (tz.IsDaylightSavingTime (dt), "#3.1");
336                         }
337
338                         [Test] //Covers #26008
339                         public void DSTWithFloatingDateRule ()
340                         {
341                                 // Construct a custom time zone where daylight saving time starts on the
342                                 // 2nd Sunday in March.
343                                 var transitionToDaylight = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1, 1, 1, 2, 0, 0), 3, 2, DayOfWeek.Sunday);
344                                 var transitionToStandard = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1, 1, 1, 2, 0, 0), 11, 1, DayOfWeek.Sunday);
345                                 var adjustment = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1, 0, 0), transitionToDaylight, transitionToStandard);
346                                 var timeZone = TimeZoneInfo.CreateCustomTimeZone ("BugCheck", new TimeSpan (-8, 0, 0), "Testing", "Testing Standard", "Testing Daylight", new TimeZoneInfo.AdjustmentRule [] { adjustment });
347                                 // See if March 7, 2014 is listed as being during daylight saving time.
348                                 // If it is DST, then the runtime has the bug that we are looking for.
349                                 Assert.IsFalse (timeZone.IsDaylightSavingTime (new DateTime (2014, 3, 7, 12, 0, 0, DateTimeKind.Unspecified)));
350                         }
351
352                         [Test] //Covers #25050
353                         public void TestAthensDST ()
354                         {
355                                 TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Athens");
356                                 var date = new DateTime (2014, 3, 30 , 2, 0, 0);
357                                 Assert.IsFalse (tzi.IsDaylightSavingTime (date));
358                                 Assert.AreEqual (new TimeSpan (2,0,0), tzi.GetUtcOffset (date));
359                         }
360                 }
361                 
362                 [TestFixture]
363                 public class ConvertTimeTests_LocalUtc : ConvertTimeTests
364                 {
365                         static TimeZoneInfo oldLocal;
366
367                         [SetUp]
368                         public void SetLocal ()
369                         {
370                                 base.CreateTimeZones ();
371
372                                 oldLocal = TimeZoneInfo.Local;
373                                 TimeZoneInfoTest.SetLocal (TimeZoneInfo.Utc);
374                         }
375
376                         [TearDown]
377                         public void RestoreLocal ()
378                         {
379                                 TimeZoneInfoTest.SetLocal (oldLocal);
380                         }
381                 }
382
383                 [TestFixture]
384                 public class ConvertTimeTests
385                 {
386                         TimeZoneInfo london;
387                 
388                         [SetUp]
389                         public void CreateTimeZones ()
390                         {
391                                 TimeZoneInfo.TransitionTime start = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
392                                 TimeZoneInfo.TransitionTime end = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
393                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
394                                 london = TimeZoneInfo.CreateCustomTimeZone ("Europe/London", new TimeSpan (0), "Europe/London", "British Standard Time", "British Summer Time", new TimeZoneInfo.AdjustmentRule [] {rule});
395                         }
396                 
397                         [Test]
398                         [ExpectedException (typeof (ArgumentException))]
399                         public void ConvertFromUtc_KindIsLocalException ()
400                         {
401                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
402                                         throw new ArgumentException ();
403                                 TimeZoneInfo.ConvertTimeFromUtc (new DateTime (2007, 5, 3, 11, 8, 0, DateTimeKind.Local), TimeZoneInfo.Local);  
404                         }
405                 
406                         [Test]
407                         [ExpectedException (typeof (ArgumentNullException))]
408                         public void ConvertFromUtc_DestinationTimeZoneIsNullException ()
409                         {
410                                 TimeZoneInfo.ConvertTimeFromUtc (new DateTime (2007, 5, 3, 11, 8, 0), null);            
411                         }
412                 
413                         [Test]
414                         public void ConvertFromUtc_DestinationIsUTC ()
415                         {
416                                 DateTime now = DateTime.UtcNow;
417                                 DateTime converted = TimeZoneInfo.ConvertTimeFromUtc (now, TimeZoneInfo.Utc);
418                                 Assert.AreEqual (now, converted);
419                         }
420                         
421                         [Test]
422                         public void ConvertFromUTC_ConvertInWinter ()
423                         {
424                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
425                                         Assert.Ignore ("Not running on Unix.");
426                                 DateTime utc = new DateTime (2007, 12, 25, 12, 0, 0);
427                                 DateTime converted = TimeZoneInfo.ConvertTimeFromUtc (utc, london);
428                                 Assert.AreEqual (utc, converted);
429                         }
430                 
431                         [Test]
432                         public void ConvertFromUtc_ConvertInSummer ()
433                         {
434                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
435                                         Assert.Ignore ("Not running on Unix.");
436                                 DateTime utc = new DateTime (2007, 06, 01, 12, 0, 0);
437                                 DateTime converted = TimeZoneInfo.ConvertTimeFromUtc (utc, london);
438                                 Assert.AreEqual (utc + new TimeSpan (1,0,0), converted);
439                         }
440                 
441                         [Test]
442                         public void ConvertToUTC_KindIsUtc ()
443                         {
444                                 DateTime now = DateTime.UtcNow;
445                                 Assert.AreEqual (now.Kind, DateTimeKind.Utc);
446                                 DateTime converted = TimeZoneInfo.ConvertTimeToUtc (now);
447                                 Assert.AreEqual (now, converted);
448                         }
449                 
450                         [Test]
451                         [ExpectedException (typeof (ArgumentException))]
452                         public void ConvertToUTC_KindIsUTCButSourceIsNot ()
453                         {
454                                 TimeZoneInfo.ConvertTimeToUtc (new DateTime (2007, 5, 3, 12, 8, 0, DateTimeKind.Utc), london);
455                         }
456                 
457                         [Test]
458                         [ExpectedException (typeof (ArgumentException))]
459                         public void ConvertToUTC_KindIsLocalButSourceIsNot ()
460                         {
461                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
462                                         throw new ArgumentException ();
463                                 TimeZoneInfo.ConvertTimeToUtc (new DateTime (2007, 5, 3, 12, 8, 0, DateTimeKind.Local), london);        
464                         }
465                 
466                         [Test]
467                         [ExpectedException (typeof (ArgumentException))]
468                         public void ConvertToUTC_InvalidDate ()
469                         {
470                                 TimeZoneInfo.ConvertTimeToUtc (new DateTime (2007, 3, 25, 1, 30, 0), london);
471                         }
472                 
473                         [Test]
474                         [ExpectedException (typeof (ArgumentNullException))]
475                         public void ConvertToUTC_SourceIsNull ()
476                         {
477                                 TimeZoneInfo.ConvertTimeToUtc (new DateTime (2007, 5, 3, 12, 16, 0), null);
478                         }
479                 
480                 #if SLOW_TESTS
481                         [Test]
482                         public void ConvertToUtc_MatchDateTimeBehavior ()
483                         {
484                                 for (DateTime date = new DateTime (2007, 01, 01, 0, 0, 0); date < new DateTime (2007, 12, 31, 23, 59, 59); date += new TimeSpan (0,1,0)) {
485                                         Assert.AreEqual (TimeZoneInfo.ConvertTimeToUtc (date), date.ToUniversalTime ());
486                                 }
487                         }
488                 #endif
489                 
490                         [Test]
491                         public void ConvertFromToUtc ()
492                         {
493                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
494                                         Assert.Ignore ("Not running on Unix.");
495                                 DateTime utc = DateTime.UtcNow;
496                                 Assert.AreEqual (utc.Kind, DateTimeKind.Utc);
497                                 DateTime converted = TimeZoneInfo.ConvertTimeFromUtc (utc, london);
498                                 Assert.AreEqual (converted.Kind, DateTimeKind.Unspecified);
499                                 DateTime back = TimeZoneInfo.ConvertTimeToUtc (converted, london);
500                                 Assert.AreEqual (back.Kind, DateTimeKind.Utc);
501                                 Assert.AreEqual (utc, back);
502                 
503                         }
504
505                         [Test]
506                         public void ConvertTimeToUtc_Overflow ()
507                         {
508                                 var res = TimeZoneInfo.ConvertTimeToUtc (new DateTime (0));
509                                 Assert.AreEqual (res.Kind, DateTimeKind.Utc, "#1");
510
511                                 res = TimeZoneInfo.ConvertTimeToUtc (DateTime.MaxValue);
512                                 Assert.AreEqual (res.Kind, DateTimeKind.Utc, "#2");
513                         }
514
515                         [Test]
516                         public void ConvertFromToUtc_Utc ()
517                         {
518                                 DateTime utc = DateTime.UtcNow;
519                                 Assert.AreEqual (utc.Kind, DateTimeKind.Utc);
520                                 DateTime converted = TimeZoneInfo.ConvertTimeFromUtc (utc, TimeZoneInfo.Utc);
521                                 Assert.AreEqual (DateTimeKind.Utc, converted.Kind);
522                                 DateTime back = TimeZoneInfo.ConvertTimeToUtc (converted, TimeZoneInfo.Utc);
523                                 Assert.AreEqual (back.Kind, DateTimeKind.Utc);
524                                 Assert.AreEqual (utc, back);
525                         }
526
527                         [Test]
528                         public void ConvertFromToLocal ()
529                         {
530                                 DateTime utc = DateTime.UtcNow;
531                                 Assert.AreEqual (utc.Kind, DateTimeKind.Utc);
532                                 DateTime converted = TimeZoneInfo.ConvertTimeFromUtc (utc, TimeZoneInfo.Local);
533                                 var expectedKind = (TimeZoneInfo.Local == TimeZoneInfo.Utc)? DateTimeKind.Utc : DateTimeKind.Local;
534                                 Assert.AreEqual (expectedKind, converted.Kind);
535                                 DateTime back = TimeZoneInfo.ConvertTimeToUtc (converted, TimeZoneInfo.Local);
536                                 Assert.AreEqual (back.Kind, DateTimeKind.Utc);
537                                 Assert.AreEqual (utc, back);
538                         }
539
540                         [Test]
541                         public void ConvertToTimeZone ()
542                         {
543                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
544                                         Assert.Ignore ("Not running on Unix.");
545
546                                 TimeZoneInfo.ConvertTime (DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById("Pacific/Auckland"));
547                         }
548
549                         [Test]
550                         [ExpectedException (typeof (ArgumentNullException))]
551                         public void ConvertTime_DateTime_TimeZoneInfo_DestinationTimeZoneIsNull ()
552                         {
553                                 TimeZoneInfo.ConvertTime (DateTime.Now, null);
554                         }
555
556                         [Test]
557                         public void ConvertTime_DateTime_TimeZoneInfo_DateTimeKindMatch ()
558                         {
559                                 var sdt = new DateTime (2014, 1, 9, 23, 0, 0, DateTimeKind.Utc);
560                                 var ddt = TimeZoneInfo.ConvertTime (sdt, TimeZoneInfo.Utc);
561                                 Assert.AreEqual (ddt.Kind, sdt.Kind, "#1.1");
562                                 Assert.AreEqual (ddt.Kind, DateTimeKind.Utc, "#1.2");
563                                 
564                                 sdt = new DateTime (2014, 1, 9, 23, 0, 0, DateTimeKind.Local);
565                                 ddt = TimeZoneInfo.ConvertTime (sdt, TimeZoneInfo.Local);
566                                 Assert.AreEqual (ddt.Kind, sdt.Kind, "#2.1");
567                                 Assert.AreEqual (ddt.Kind, DateTimeKind.Local, "#2.2");
568
569                                 sdt = new DateTime (2014, 1, 9, 23, 0, 0);
570                                 ddt = TimeZoneInfo.ConvertTime (sdt, TimeZoneInfo.Local);
571                                 var expectedKind = (TimeZoneInfo.Local == TimeZoneInfo.Utc)? DateTimeKind.Utc : sdt.Kind;
572                                 Assert.AreEqual (expectedKind,  ddt.Kind, "#3.1");
573                                 Assert.AreEqual (DateTimeKind.Unspecified, sdt.Kind, "#3.2");
574                         }
575
576                         [Test]
577                         [ExpectedException (typeof (ArgumentNullException))]
578                         public void ConverTime_DateTime_TimeZoneInfo_TimeZoneInfo_SourceTimeZoneIsNull ()
579                         {
580                                 TimeZoneInfo.ConvertTime (DateTime.Now, null, TimeZoneInfo.Local);
581                         }
582
583                         [Test]
584                         [ExpectedException (typeof (ArgumentNullException))]
585                         public void ConverTime_DateTime_TimeZoneInfo_TimeZoneInfo_DestinationTimeZoneIsNull ()
586                         {
587                                 TimeZoneInfo.ConvertTime (DateTime.Now, TimeZoneInfo.Utc, null);
588                         }
589
590                         [Test (Description="Fix for xambug https://bugzilla.xamarin.com/show_bug.cgi?id=17155")]
591                         public void ConvertTime_AdjustmentRuleAfterNewYears ()
592                         {
593                                 TimeZoneInfo tz;
594                                 if (Environment.OSVersion.Platform == PlatformID.Unix)
595                                         tz = TimeZoneInfo.FindSystemTimeZoneById ("Pacific/Auckland"); // *nix
596                                 else
597                                         tz = TimeZoneInfo.FindSystemTimeZoneById ("New Zealand Standard Time"); // Windows
598
599                                 // DST start: 9/29/2013 2:00:00 AM
600                                 // DST end: 4/6/2014 3:00:00 AM
601                                 DateTime sdt = new DateTime (2014, 1, 9, 23, 0, 0, DateTimeKind.Utc);
602                                 DateTime ddt = TimeZoneInfo.ConvertTime (sdt, tz);
603                                 Assert.AreEqual (10, ddt.Day, "#1.1");
604                                 Assert.AreEqual (1, ddt.Month, "#1.2");
605                                 Assert.AreEqual (2014, ddt.Year, "#1.3");
606                                 Assert.AreEqual (12, ddt.Hour, "#1.4");
607                                 Assert.AreEqual (0, ddt.Minute, "#1.5");
608                                 Assert.AreEqual (0, ddt.Second, "#1.6");
609                                 
610                                 // DST start: 9/29/2014 2:00:00 AM
611                                 // DST end: 4/6/2015 3:00:00 AM
612                                 sdt = new DateTime (2014, 6, 9, 23, 0, 0, DateTimeKind.Utc);
613                                 ddt = TimeZoneInfo.ConvertTime (sdt, tz);
614                                 Assert.AreEqual (10, ddt.Day, "#2.1");
615                                 Assert.AreEqual (6, ddt.Month, "#2.2");
616                                 Assert.AreEqual (2014, ddt.Year, "#2.3");
617                                 Assert.AreEqual (11, ddt.Hour, "#2.4");
618                                 Assert.AreEqual (0, ddt.Minute, "#2.5");
619                                 Assert.AreEqual (0, ddt.Second, "#2.6");
620                                 
621                                 // DST start: 9/29/2014 2:00:00 AM
622                                 // DST end: 4/6/2015 3:00:00 AM
623                                 sdt = new DateTime (2014, 10, 9, 23, 0, 0, DateTimeKind.Utc);
624                                 ddt = TimeZoneInfo.ConvertTime (sdt, tz);
625                                 Assert.AreEqual (10, ddt.Day, "#3.1");
626                                 Assert.AreEqual (10, ddt.Month, "#3.2");
627                                 Assert.AreEqual (2014, ddt.Year, "#3.3");
628                                 Assert.AreEqual (12, ddt.Hour, "#3.4");
629                                 Assert.AreEqual (0, ddt.Minute, "#3.5");
630                                 Assert.AreEqual (0, ddt.Second, "#3.6");
631                         }
632
633                         [Test (Description="Fix the bug https://bugzilla.xamarin.com/show_bug.cgi?id=1849")]
634                         public void ConvertTime_AjustmentConvertTimeWithSourceTimeZone () {
635                                 
636                                 TimeZoneInfo easternTimeZone;
637                                 TimeZoneInfo pacificTimeZone;
638
639                                 if (Environment.OSVersion.Platform == PlatformID.Unix) {
640                                         // *nix
641                                         easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById ("US/Eastern");
642                                         pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById ("US/Pacific");   
643                                 }
644                                 else {
645                                         // Windows
646                                         easternTimeZone = TimeZoneInfo.FindSystemTimeZoneById ("Eastern Standard Time");
647                                         pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById ("Pacific Standard Time");
648                                 }
649
650                                 DateTime lastMidnight = new DateTime (new DateTime (2012, 06, 13).Ticks, DateTimeKind.Unspecified);
651                                 DateTime lastMidnightAsEST = TimeZoneInfo.ConvertTime (lastMidnight, pacificTimeZone, easternTimeZone);
652                                 DateTime lastMidnightAsPST = TimeZoneInfo.ConvertTime (lastMidnightAsEST, easternTimeZone, pacificTimeZone);
653                         
654                                 // Last midnight in PST as EST should be 3AM
655                                 DateTime expectedDate = new DateTime (2012, 06, 13, 3, 0, 0);
656
657                                 Assert.AreEqual (expectedDate, lastMidnightAsEST);
658                                 Assert.AreEqual (lastMidnight, lastMidnightAsPST);
659                         }
660                 }
661                 
662                 [TestFixture]
663                 public class IsInvalidTimeTests
664                 {
665                         TimeZoneInfo london;
666                 
667                         [SetUp]
668                         public void CreateTimeZones ()
669                         {
670                                 TimeZoneInfo.TransitionTime start = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
671                                 TimeZoneInfo.TransitionTime end = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
672                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
673                                 london = TimeZoneInfo.CreateCustomTimeZone ("Europe/London", new TimeSpan (0), "Europe/London", "British Standard Time", "British Summer Time", new TimeZoneInfo.AdjustmentRule [] {rule});
674                         }
675                 
676                 #if SLOW_TESTS
677                         [Test]
678                         public void UTCDate ()
679                         {
680                                 for (DateTime date = new DateTime (2007, 01, 01, 0, 0, 0); date < new DateTime (2007, 12, 31, 23, 59, 59); date += new TimeSpan (0,1,0)) {
681                                         date = DateTime.SpecifyKind (date, DateTimeKind.Utc);
682                                         Assert.IsFalse (london.IsInvalidTime (date));
683                                 }
684                         }
685                 #endif
686                         [Test]
687                         public void InvalidDates ()
688                         {
689                                 Assert.IsFalse (london.IsInvalidTime (new DateTime (2007, 03, 25, 0, 59, 59)));
690                                 Assert.IsTrue (london.IsInvalidTime (new DateTime (2007, 03, 25, 1, 0, 0)));
691                                 Assert.IsTrue (london.IsInvalidTime (new DateTime (2007, 03, 25, 1, 59, 59)));
692                                 Assert.IsFalse (london.IsInvalidTime (new DateTime (2007, 03, 25, 2, 0, 0)));
693                         }
694                 }
695                 
696                 [TestFixture]
697                 public class IsAmbiguousTimeTests
698                 {
699                         TimeZoneInfo london;
700                 
701                         [SetUp]
702                         public void CreateTimeZones ()
703                         {
704                                 TimeZoneInfo.TransitionTime start = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
705                                 TimeZoneInfo.TransitionTime end = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
706                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
707                                 london = TimeZoneInfo.CreateCustomTimeZone ("Europe/London", new TimeSpan (0), "Europe/London", "British Standard Time", "British Summer Time", new TimeZoneInfo.AdjustmentRule [] {rule});
708                         }
709                 
710                         [Test]
711                         public void AmbiguousDates ()
712                         {
713                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
714                                         Assert.Ignore ("Not running on Unix.");
715                                 Assert.IsFalse (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 1, 0, 0)));
716                                 Assert.IsTrue (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 1, 0, 1)));
717                                 Assert.IsTrue (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 2, 0, 0)));
718                                 Assert.IsFalse (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 2, 0, 1)));
719                         }
720                 
721                         [Test]
722                         public void AmbiguousUTCDates ()
723                         {
724                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
725                                         Assert.Ignore ("Not running on Unix.");
726                                 Assert.IsFalse (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 0, 0, 0, DateTimeKind.Utc)));
727                                 Assert.IsTrue (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 0, 0, 1, DateTimeKind.Utc)));
728                                 Assert.IsTrue (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 0, 59, 59, DateTimeKind.Utc)));
729                                 Assert.IsFalse (london.IsAmbiguousTime (new DateTime (2007, 10, 28, 1, 0, 0, DateTimeKind.Utc)));
730                         }
731                 
732                 #if SLOW_TESTS
733                         [Test]
734                         public void AmbiguousInUTC ()
735                         {
736                                 for (DateTime date = new DateTime (2007, 01, 01, 0, 0, 0); date < new DateTime (2007, 12, 31, 23, 59, 59); date += new TimeSpan (0,1,0)) {
737                                         Assert.IsFalse (TimeZoneInfo.Utc.IsAmbiguousTime (date));
738                                 }
739                         }
740                 #endif
741                 }
742                 
743                 [TestFixture]
744                 public class GetSystemTimeZonesTests
745                 {
746                         [Test]
747                         public void Identity ()
748                         {
749                                 Assert.AreSame (TimeZoneInfo.GetSystemTimeZones (), TimeZoneInfo.GetSystemTimeZones ());
750                         }
751
752                         [Test]
753                         public void NotEmpty ()
754                         {
755                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
756                                         Assert.Ignore ("Not running on Unix.");
757                                 global::System.Collections.ObjectModel.ReadOnlyCollection<TimeZoneInfo> systemTZ = TimeZoneInfo.GetSystemTimeZones ();
758                                 Assert.IsNotNull(systemTZ, "SystemTZ is null");
759                                 Assert.IsFalse (systemTZ.Count == 0, "SystemTZ is empty");
760                         }
761                 
762                         [Test]
763                         public void ContainsBrussels ()
764                         {
765                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
766                                         Assert.Ignore ("Not running on Unix.");
767                                 global::System.Collections.ObjectModel.ReadOnlyCollection<TimeZoneInfo> systemTZ = TimeZoneInfo.GetSystemTimeZones ();
768                                 foreach (TimeZoneInfo tz in systemTZ) {
769                                         if (tz.Id == "Europe/Brussels")
770                                                 return;
771                                 }
772                                 Assert.Fail ("Europe/Brussels not found in SystemTZ");
773                         }
774
775                         [Test]
776                         public void ReflectionReturnsTheCorrectMethod ()
777                         {
778                                 var method = (MethodInfo) typeof (TimeZoneInfo).GetMember ("GetSystemTimeZones", MemberTypes.Method, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)[0];
779
780                                 var timeZones = (global::System.Collections.ObjectModel.ReadOnlyCollection<TimeZoneInfo>) method.Invoke (null, null);
781                                 Assert.IsTrue (timeZones.Count > 0, "GetSystemTimeZones should not return an empty collection.");
782                         }
783                 }
784                 
785                 [TestFixture]
786                 public class FindSystemTimeZoneByIdTests
787                 {
788                         [Test]
789                         [ExpectedException (typeof (ArgumentNullException))]
790                         public void NullId ()
791                         {
792                                 TimeZoneInfo.FindSystemTimeZoneById (null);
793                         }
794                 
795                         [Test]
796                         [ExpectedException (typeof (TimeZoneNotFoundException))]
797                         public void NonSystemTimezone ()
798                         {
799                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
800                                         throw new TimeZoneNotFoundException ();
801                                 TimeZoneInfo.FindSystemTimeZoneById ("Neverland/The_Lagoon");
802                         }
803                 
804                         [Test]
805                         public void FindBrusselsTZ ()
806                         {
807                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
808                                         Assert.Ignore ("Not running on Unix.");
809                                 TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Brussels");
810                                 Assert.IsNotNull (brussels);
811                         }
812                 
813                         [Test]
814                         public void OffsetIsCorrectInKinshasa ()
815                         {
816                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
817                                         Assert.Ignore ("Not running on Unix.");
818                                 TimeZoneInfo kin = TimeZoneInfo.FindSystemTimeZoneById ("Africa/Kinshasa");
819                                 Assert.AreEqual (new TimeSpan (1,0,0), kin.BaseUtcOffset, "BaseUtcOffset in Kinshasa is not +1h");
820                         }
821                 
822                         [Test]
823                         public void OffsetIsCorrectInBrussels ()
824                         {
825                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
826                                         Assert.Ignore ("Not running on Unix.");
827                                 TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Brussels");
828                                 Assert.AreEqual (new TimeSpan (1,0,0), brussels.BaseUtcOffset, "BaseUtcOffset for Brussels is not +1h");
829                         }
830                 
831                         [Test]
832                         public void NoDSTInKinshasa ()
833                         {
834                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
835                                         Assert.Ignore ("Not running on Unix.");
836                                 TimeZoneInfo kin = TimeZoneInfo.FindSystemTimeZoneById ("Africa/Kinshasa");
837                                 Assert.IsFalse (kin.SupportsDaylightSavingTime);
838                         }
839                 
840                         [Test]
841                         public void BrusselsSupportsDST ()
842                         {
843                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
844                                         Assert.Ignore ("Not running on Unix.");
845                                 TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Brussels");
846                                 Assert.IsTrue (brussels.SupportsDaylightSavingTime);
847                         }
848                 
849                         [Test]
850                         public void MelbourneSupportsDST ()
851                         {
852                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
853                                         Assert.Ignore ("Not running on Unix.");
854                                 TimeZoneInfo melbourne = TimeZoneInfo.FindSystemTimeZoneById ("Australia/Melbourne");
855                                 Assert.IsTrue (melbourne.SupportsDaylightSavingTime);
856                         }
857                 
858                         [Test]
859                         public void RomeAndVaticanSharesTime ()
860                         {
861                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
862                                         Assert.Ignore ("Not running on Unix.");
863                                 TimeZoneInfo rome = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Rome");
864                                 TimeZoneInfo vatican = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Vatican");
865                                 Assert.IsTrue (rome.HasSameRules (vatican));
866                         }
867
868                         [Test]
869                         public void FindSystemTimeZoneById_Local_Roundtrip ()
870                         {
871                                 Assert.AreEqual (TimeZoneInfo.Local.Id, TimeZoneInfo.FindSystemTimeZoneById (TimeZoneInfo.Local.Id).Id);
872                         }
873
874                         [Test]
875                         public void Test326 ()
876                         {
877                                 DateTime utc = DateTime.UtcNow;
878                                 DateTime local = TimeZoneInfo.ConvertTime (utc, TimeZoneInfo.Utc, TimeZoneInfo.FindSystemTimeZoneById (TimeZoneInfo.Local.Id));
879                                 Assert.AreEqual (local, utc + TimeZoneInfo.Local.GetUtcOffset (utc), "ConvertTime/Local");
880                         }
881                 
882                 #if SLOW_TESTS
883                         [Test]
884                         public void BrusselsAdjustments ()
885                         {
886                                 TimeZoneInfo.TransitionTime start = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,2,0,0), 3, 5, DayOfWeek.Sunday);
887                                 TimeZoneInfo.TransitionTime end = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,3,0,0), 10, 5, DayOfWeek.Sunday);
888                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
889                                 TimeZoneInfo brussels = TimeZoneInfo.CreateCustomTimeZone ("Europe/Brussels", new TimeSpan (1, 0, 0), "Europe/Brussels", "", "", new TimeZoneInfo.AdjustmentRule [] {rule});
890                 
891                                 TimeZoneInfo brussels_sys = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Brussels");
892                 
893                                 for (DateTime date = new DateTime (2006, 01, 01, 0, 0, 0, DateTimeKind.Local); date < new DateTime (2007, 12, 31, 23, 59, 59); date += new TimeSpan (0,30,0)) {
894                                         Assert.AreEqual (brussels.GetUtcOffset (date), brussels_sys.GetUtcOffset (date));
895                                         Assert.AreEqual (brussels.IsDaylightSavingTime (date), brussels_sys.IsDaylightSavingTime (date));
896                                 }               
897                         }
898                 #endif
899
900                         [Test]
901                         public void SubminuteDSTOffsets ()
902                         {
903                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
904                                         Assert.Ignore ();
905
906                                 var subMinuteDSTs = new string [] {
907                                         "Europe/Dublin", // Europe/Dublin has a DST offset of 34 minutes and 39 seconds in 1916.
908                                         "Europe/Amsterdam",
909                                         "America/St_Johns",
910                                         "Canada/Newfoundland",
911                                         "Europe/Moscow",
912                                         "Europe/Riga",
913                                         "N/A", // testing that the test doesn't fail with inexistent TZs
914                                 };
915                                 foreach (var tz in subMinuteDSTs) {
916                                         try {
917                                                 TimeZoneInfo.FindSystemTimeZoneById (tz);
918                                         } catch (TimeZoneNotFoundException) {
919                                                 // ok;
920                                         } catch (Exception ex) {
921                                                 Assert.Fail (string.Format ("Failed to load TZ {0}: {1}", tz, ex.ToString ()));
922                                         }
923                                 }
924                         }
925                 }
926                 
927                 [TestFixture]
928                 public class GetAmbiguousTimeOffsetsTests
929                 {
930                         [Test]
931                         [ExpectedException (typeof(ArgumentException))]
932                         public void DateIsNotAmbiguous ()
933                         {
934                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
935                                         throw new ArgumentException ();
936                                 TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Brussels");
937                                 DateTime date = new DateTime (2007, 05, 11, 11, 40, 00);
938                                 brussels.GetAmbiguousTimeOffsets (date);
939                         }
940                 
941                         [Test]
942                         public void AmbiguousOffsets ()
943                         {
944                                 if (Environment.OSVersion.Platform != PlatformID.Unix)
945                                         Assert.Ignore ("Not running on Unix.");
946                                 TimeZoneInfo brussels = TimeZoneInfo.FindSystemTimeZoneById ("Europe/Brussels");
947                                 DateTime date = new DateTime (2007, 10, 28, 2, 30, 00);
948                                 Assert.IsTrue (brussels.IsAmbiguousTime (date));
949                                 Assert.AreEqual (2, brussels.GetAmbiguousTimeOffsets (date).Length);
950                                 Assert.AreEqual (new TimeSpan[] {new TimeSpan (1, 0, 0), new TimeSpan (2, 0, 0)}, brussels.GetAmbiguousTimeOffsets (date));
951                         }
952                 }
953
954                 [TestFixture]
955                 public class HasSameRulesTests
956                 {
957                         [Test]
958                         public void NullAdjustments () //bnc #391011
959                         {
960                                 TimeZoneInfo utc = TimeZoneInfo.Utc;
961                                 TimeZoneInfo custom = TimeZoneInfo.CreateCustomTimeZone ("Custom", new TimeSpan (0), "Custom", "Custom");
962                                 Assert.IsTrue (utc.HasSameRules (custom));
963                         }
964                 }
965
966                 [TestFixture]
967                 public class SerializationTests
968                 {
969                         [Test]
970                         public void Serialization_Deserialization ()
971                         {
972                                 TimeZoneInfo.TransitionTime start = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,1,0,0), 3, 5, DayOfWeek.Sunday);
973                                 TimeZoneInfo.TransitionTime end = TimeZoneInfo.TransitionTime.CreateFloatingDateRule (new DateTime (1,1,1,2,0,0), 10, 5, DayOfWeek.Sunday);
974                                 TimeZoneInfo.AdjustmentRule rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (DateTime.MinValue.Date, DateTime.MaxValue.Date, new TimeSpan (1,0,0), start, end);
975                                 TimeZoneInfo london = TimeZoneInfo.CreateCustomTimeZone ("Europe/London", new TimeSpan (0), "Europe/London", "British Standard Time", "British Summer Time", new TimeZoneInfo.AdjustmentRule [] {rule});
976                                 MemoryStream stream = new MemoryStream ();
977                                 BinaryFormatter formatter = new BinaryFormatter ();
978                                 formatter.Serialize (stream, london);
979                                 stream.Position = 0;
980                                 TimeZoneInfo deserialized = (TimeZoneInfo) formatter.Deserialize (stream);
981                                 stream.Close ();
982                                 stream.Dispose ();
983                                 Assert.IsTrue (london.Equals (deserialized));
984                         }
985                 }
986
987                 [TestFixture]
988                 public class MultipleDaylightSavingTimeTests {
989                         private TimeZoneInfo cairo;
990                         private DateTime dst1Start;
991                         private DateTime dst1End;
992                         private DateTime dst2Start;
993                         private DateTime dst2End;
994
995                         private TimeSpan baseUtcOffset;
996                         private TimeSpan dstUtcOffset;
997                         private TimeSpan dstOffset;
998
999                         [SetUp]
1000                         public void CreateTimeZones ()
1001                         {
1002                                 /*
1003                                 From 1/1/2014 12:00:00 AM to 6/30/2014 12:00:00 AM
1004                                         Delta: 01:00:00
1005                                         Begins at 12:00 AM on 16 May
1006                                         Ends at 1:00 AM on 29 June
1007                                 From 7/1/2014 12:00:00 AM to 12/31/2014 12:00:00 AM
1008                                         Delta: 01:00:00
1009                                         Begins at 12:00 AM on 29 July
1010                                         Ends at 12:00 AM on 26 September
1011                                 */
1012                                 dst1Start = new DateTime (2014, 5, 16);
1013                                 dst1End = new DateTime (2014, 6, 29);
1014                                 dst2Start = new DateTime (2014, 7, 29);
1015                                 dst2End = new DateTime (2014, 9, 26);
1016
1017                                 baseUtcOffset = new TimeSpan (2, 0, 0);
1018                                 dstUtcOffset = new TimeSpan (3, 0, 0);
1019                                 dstOffset = dstUtcOffset - baseUtcOffset;
1020
1021                                 var rule1 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
1022                                         new DateTime (2014, 1, 1), new DateTime (2014, 6, 30), dstOffset,
1023                                         CreateFixedDateRule (dst1Start), CreateFixedDateRule (dst1End));
1024
1025                                 var rule2 = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule (
1026                                         new DateTime (2014, 7, 1), new DateTime (2014, 12, 31), dstOffset,
1027                                         CreateFixedDateRule (dst2Start), CreateFixedDateRule (dst2End));
1028
1029                                 cairo = TimeZoneInfo.CreateCustomTimeZone ("Africa/Cairo", baseUtcOffset, "Africa/Cairo", "EET", "EEST",
1030                                         new [] {rule1, rule2});
1031                         }
1032
1033                         private static TimeZoneInfo.TransitionTime CreateFixedDateRule (DateTime dateTime)
1034                         {
1035                                 var time = new DateTime (dateTime.Ticks - dateTime.Date.Ticks);
1036                                 return TimeZoneInfo.TransitionTime.CreateFixedDateRule (time, dateTime.Month, dateTime.Day);
1037                         }
1038
1039                         [Test]
1040                         public void GetUtcOffset_FromUTC ()
1041                         {
1042                                 var d = dst1Start.Add (-baseUtcOffset);
1043                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1044                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1045                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
1046                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1047
1048                                 d = dst1End.Add (-baseUtcOffset-dstOffset);
1049                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1050                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1051                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
1052                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1053
1054                                 d = dst2Start.Add (-baseUtcOffset);
1055                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1056                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1057                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
1058                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1059
1060                                 d = dst2End.Add (-baseUtcOffset-dstOffset);
1061                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1062                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1063                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
1064                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1065                         }
1066
1067                         [Test]
1068                         public void GetUtcOffset_FromLocal ()
1069                         {
1070                                 var d = dst1Start.Add (-baseUtcOffset);
1071                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1072                                 d = d.ToLocalTime ();
1073                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1074                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
1075                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1076
1077                                 d = dst1End.Add (-baseUtcOffset-dstOffset);
1078                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1079                                 d = d.ToLocalTime ();
1080                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1081                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
1082                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1083
1084                                 d = dst2Start.Add (-baseUtcOffset);
1085                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1086                                 d = d.ToLocalTime ();
1087                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1088                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
1089                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1090
1091                                 d = dst2End.Add (-baseUtcOffset-dstOffset);
1092                                 d = DateTime.SpecifyKind (d, DateTimeKind.Utc);
1093                                 d = d.ToLocalTime ();
1094                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1095                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
1096                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1097                         }
1098
1099                         [Test]
1100                         public void GetUtcOffset_FromUnspecified ()
1101                         {
1102                                 var d = dst1Start.Add (dstOffset);
1103                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1104                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
1105                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1106
1107                                 d = dst1End.Add (-dstOffset);
1108                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1109                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
1110                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1111
1112                                 d = dst2Start.Add (dstOffset);
1113                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1114                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d));
1115                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1116
1117                                 d = dst2End.Add (-dstOffset);
1118                                 Assert.AreEqual(dstUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0,-1))));
1119                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d));
1120                                 Assert.AreEqual(baseUtcOffset, cairo.GetUtcOffset (d.Add (new TimeSpan(0,0,0, 1))));
1121                         }
1122                 }
1123
1124                 [TestFixture]
1125                 public class GetDaylightChanges
1126                 {
1127                         MethodInfo getChanges;
1128
1129                         [SetUp]
1130                         public void Setup ()
1131                         {
1132                                 var flags = BindingFlags.Instance | BindingFlags.NonPublic;
1133                                 getChanges = typeof (TimeZoneInfo).GetMethod ("GetDaylightChanges", flags);
1134                         }
1135
1136                         [Test]
1137                         public void TestSydneyDaylightChanges ()
1138                         {
1139                                 TimeZoneInfo tz;
1140                                 if (Environment.OSVersion.Platform == PlatformID.Unix)
1141                                         tz = TimeZoneInfo.FindSystemTimeZoneById ("Australia/Sydney");
1142                                 else
1143                                         tz = TimeZoneInfo.FindSystemTimeZoneById ("W. Australia Standard Time");
1144
1145                                 var changes = (DaylightTime) getChanges.Invoke (tz, new object [] {2014});
1146
1147                                 Assert.AreEqual (new TimeSpan (1, 0, 0), changes.Delta);
1148                                 Assert.AreEqual (new DateTime (2014, 10, 5, 2, 0, 0), changes.Start);
1149                                 Assert.AreEqual (new DateTime (2014, 4, 6, 3, 0, 0), changes.End);
1150                         }
1151
1152                         [Test]
1153                         public void AllTimeZonesDaylightChanges ()
1154                         {
1155                                 foreach (var tz in TimeZoneInfo.GetSystemTimeZones ()) {
1156                                         try {
1157                                                 for (var year = 1950; year <= 2051; year++)
1158                                                         getChanges.Invoke (tz, new object [] {year} );
1159                                         } catch (Exception e) {
1160                                                 Assert.Fail ("TimeZone " + tz.Id + " exception: " + e.ToString ()); 
1161                                         }
1162                                 }
1163                         }
1164                 }
1165         }
1166 }