[480178] Fix handling of surrogate characters.
[mono.git] / mcs / class / corlib / Test / System / DateTimeOffsetTest.cs
1 //
2 // DateTimeOffsetTest.cs - NUnit Test Cases for the System.DateTimeOffset struct
3 //
4 // Authors:
5 //      Stephane Delcroix  (sdelcroix@novell.com)
6 //
7 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
8 //
9
10 using System.Globalization;
11 using NUnit.Framework;
12 using System;
13
14 namespace MonoTests.System {
15
16         [TestFixture]
17         public class DateTimeOffsetTest
18         {
19                 //ctor exception checking...
20                 [Test]
21                 [ExpectedException (typeof (ArgumentException))]
22                 public void UtcWithWrongOffset ()
23                 {
24                         DateTime dt = DateTime.SpecifyKind (DateTime.Now, DateTimeKind.Utc);
25                         TimeSpan offset = new TimeSpan (2, 0, 0);
26                         new DateTimeOffset (dt, offset);
27                 }
28
29                 [Test]
30                 [ExpectedException (typeof (ArgumentException))]
31                 public void LocalWithWrongOffset ()
32                 {
33                         DateTime dt = DateTime.SpecifyKind (DateTime.Now, DateTimeKind.Local);
34                         TimeSpan offset = TimeZone.CurrentTimeZone.GetUtcOffset (dt) + new TimeSpan (1,0,0);
35                         new DateTimeOffset (dt, offset);
36                 }
37
38                 [Test]
39                 [ExpectedException (typeof (ArgumentException))]
40                 public void OffsetNotInWholeminutes ()
41                 {
42                         DateTime dt = DateTime.SpecifyKind (DateTime.Now, DateTimeKind.Unspecified);
43                         TimeSpan offset = new TimeSpan (1,0,59);
44                         new DateTimeOffset (dt, offset);
45                 }
46
47                 [Test]
48                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
49                 public void OffsetOutOfRange1 ()
50                 {
51                         DateTime dt = DateTime.SpecifyKind (DateTime.Now, DateTimeKind.Unspecified);
52                         TimeSpan offset = new TimeSpan (14, 1, 0);
53                         new DateTimeOffset (dt, offset);
54                 }
55
56                 [Test]
57                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
58                 public void OffsetOutOfRange2 ()
59                 {
60                         DateTime dt = DateTime.SpecifyKind (DateTime.Now, DateTimeKind.Unspecified);
61                         TimeSpan offset = new TimeSpan (-14, -1, 0);
62                         new DateTimeOffset (dt, offset);
63                 }
64
65                 [Test]
66                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
67                 public void UtcDateTimeOutOfRange1 ()
68                 {
69                         DateTime dt = DateTime.SpecifyKind (DateTime.MinValue, DateTimeKind.Unspecified);
70                         TimeSpan offset = new TimeSpan (1, 0, 0);
71                         new DateTimeOffset (dt, offset);
72                 }
73
74                 [Test]
75                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
76                 public void UtcDateTimeOutOfRange2 ()
77                 {
78                         DateTime dt = DateTime.SpecifyKind (DateTime.MaxValue, DateTimeKind.Unspecified);
79                         TimeSpan offset = new TimeSpan (-1, 0, 0);
80                         new DateTimeOffset (dt, offset);
81                 }
82
83                 [Test]
84                 public void CompareTwoDateInDiffTZ ()
85                 {
86                         DateTimeOffset dt1 = new DateTimeOffset (2007, 12, 16, 15, 06, 00, new TimeSpan (1, 0, 0));
87                         DateTimeOffset dt2 = new DateTimeOffset (2007, 12, 16, 9, 06, 00, new TimeSpan (-5, 0, 0));
88                         DateTimeOffset dt3 = new DateTimeOffset (2007, 12, 16, 14, 06, 00, new TimeSpan (1, 0, 0));
89                         object o = dt1;
90                         Assert.IsTrue (dt1.CompareTo (dt2) == 0);
91                         Assert.IsTrue (DateTimeOffset.Compare (dt1, dt2) == 0);
92                         Assert.IsTrue (dt1 == dt2);
93                         Assert.IsTrue (dt1.Equals (dt2));
94                         Assert.IsFalse (dt1 == dt3);
95                         Assert.IsTrue (dt1 != dt3);
96                         Assert.IsFalse (dt1.EqualsExact (dt2));
97                         Assert.IsTrue (dt1.CompareTo (dt3) > 0);
98                         Assert.IsTrue (((IComparable)dt1).CompareTo (o) == 0);
99                 }
100
101                 [Test]
102                 public void UtcDateTime ()
103                 {
104                         DateTimeOffset dt = new DateTimeOffset (2007, 12, 16, 15, 49, 00, new TimeSpan (1, 0, 0));
105                         object o = dt.UtcDateTime;
106                         Assert.IsTrue (o is DateTime);
107                         Assert.IsTrue (dt.UtcDateTime == new DateTime (2007,12,16,14,49,00,DateTimeKind.Utc));
108                 }
109
110                 [Test]
111                 public void ParameterlessToString ()
112                 {
113                         DateTimeOffset dt = new DateTimeOffset (2007, 12, 18, 12, 16, 30, new TimeSpan (1, 0, 0));
114                         Assert.AreEqual ("12/18/2007 12:16:30 PM +01:00", dt.ToString (new CultureInfo ("en-us")));
115                         dt = new DateTimeOffset (2007, 12, 18, 12, 16, 30, new TimeSpan (-5, 0, 0));
116                         Assert.AreEqual ("12/18/2007 12:16:30 PM -05:00", dt.ToString (new CultureInfo ("en-us")));
117                         dt = new DateTimeOffset (2007, 12, 18, 12, 16, 30, TimeSpan.Zero);
118                         Assert.AreEqual ("12/18/2007 12:16:30 PM +00:00", dt.ToString (new CultureInfo ("en-us")));
119                 }
120
121                 [Test]
122                 public void ToStringWithCultureInfo ()
123                 {
124                         DateTimeOffset dto = new DateTimeOffset(2007, 5, 1, 9, 0, 0, TimeSpan.Zero);
125                         Assert.AreEqual ("05/01/2007 09:00:00 +00:00", dto.ToString (CultureInfo.InvariantCulture));
126                         Assert.AreEqual ("5/1/2007 9:00:00 AM +00:00", dto.ToString (new CultureInfo ("en-us")));
127                         Assert.AreEqual ("01/05/2007 09:00:00 +00:00", dto.ToString (new CultureInfo ("fr-fr")));
128                         Assert.AreEqual ("01.05.2007 09:00:00 +00:00", dto.ToString (new CultureInfo ("de-DE")));
129                         Assert.AreEqual ("01/05/2007 9:00:00 +00:00", dto.ToString (new CultureInfo ("es-ES")));
130                 }
131
132                 [Test]
133                 [ExpectedException (typeof (FormatException))]
134                 public void ToStringExceptionalCase1 ()
135                 {
136                         DateTimeOffset.Now.ToString (";");
137                 }
138
139                 [Test]
140                 [ExpectedException (typeof (FormatException))]
141                 public void ToStringExceptionalCase2 ()
142                 {
143                         DateTimeOffset.Now.ToString ("U");
144                 }
145
146                 [Test]
147                 public void ToStringWithFormat ()
148                 {
149                         DateTimeOffset dto = new DateTimeOffset (2007, 10, 31, 21, 0, 0, new TimeSpan(-8, 0, 0));
150                         Assert.AreEqual ("10/31/2007", dto.ToString ("d", new CultureInfo ("en-us")));
151                         Assert.AreEqual ("Wednesday, October 31, 2007", dto.ToString ("D", new CultureInfo ("en-us")));
152                         Assert.AreEqual ("9:00 PM", dto.ToString ("t", new CultureInfo ("en-us")));
153                         Assert.AreEqual ("9:00:00 PM", dto.ToString ("T", new CultureInfo ("en-us")));
154                         Assert.AreEqual ("Wednesday, October 31, 2007 9:00 PM", dto.ToString ("f", new CultureInfo ("en-us")));
155                         Assert.AreEqual ("Wednesday, October 31, 2007 9:00:00 PM", dto.ToString ("F", new CultureInfo ("en-us")));
156                         Assert.AreEqual ("10/31/2007 9:00 PM", dto.ToString ("g", new CultureInfo ("en-us")));
157                         Assert.AreEqual ("10/31/2007 9:00:00 PM", dto.ToString ("G", new CultureInfo ("en-us")));
158                         Assert.AreEqual ("October 31", dto.ToString ("M", new CultureInfo ("en-us")));
159                         Assert.AreEqual (dto.ToString ("m", new CultureInfo ("en-us")), dto.ToString ("M", new CultureInfo ("en-us")));
160                         Assert.AreEqual ("Thu, 01 Nov 2007 05:00:00 GMT", dto.ToString ("R", new CultureInfo ("en-us")));
161                         Assert.AreEqual (dto.ToString ("r", new CultureInfo ("en-us")), dto.ToString ("R", new CultureInfo ("en-us")));
162                         Assert.AreEqual ("2007-10-31T21:00:00", dto.ToString ("s", new CultureInfo ("en-us")));
163                         Assert.AreEqual ("2007-11-01 05:00:00Z", dto.ToString ("u", new CultureInfo ("en-us")));
164                         Assert.AreEqual ("October, 2007", dto.ToString ("Y", new CultureInfo ("en-us")));
165                         Assert.AreEqual (dto.ToString ("y", new CultureInfo ("en-us")), dto.ToString ("Y", new CultureInfo ("en-us")));
166                 }
167
168                 [Test]
169                 public void ToStringWithFormatAndCulture ()
170                 {
171                         DateTimeOffset dto = new DateTimeOffset (2007, 11, 1, 9, 0, 0, new TimeSpan(-7, 0, 0));
172                         string format = "dddd, MMM dd yyyy HH:mm:ss zzz";
173                         if (CultureInfo.CurrentCulture == CultureInfo.InvariantCulture)
174                                 Assert.AreEqual ("Thursday, Nov 01 2007 09:00:00 -07:00", dto.ToString (format, null as DateTimeFormatInfo), "ts1");
175                         Assert.AreEqual ("Thursday, Nov 01 2007 09:00:00 -07:00", dto.ToString (format, CultureInfo.InvariantCulture), "ts2");
176                         Assert.AreEqual ("jeudi, nov. 01 2007 09:00:00 -07:00", dto.ToString (format, new CultureInfo ("fr-FR")), "ts3");
177                         Assert.AreEqual ("jueves, nov 01 2007 09:00:00 -07:00", dto.ToString (format, new CultureInfo ("es-ES")), "ts4");
178                 }
179
180                 [Test]
181                 public void ParseExactDatesOnly ()
182                 {
183                         DateTimeOffset dto = DateTimeOffset.Now;
184                         CultureInfo fp = CultureInfo.InvariantCulture;
185
186                         string[] formats = {
187                                 "d",
188                                 "M/dd/yyyy",
189                                 "M/d/y",
190                                 "M/d/yy",
191 //                              "M/d/yyy", // this fails on .NET 2.0 (3.5) and 4.0
192                                 "M/d/yyyy",
193                                 "M/d/yyyyy",
194                                 "M/d/yyyyyy",
195                                 "M/dd/yyyy",
196                                 "MM/dd/yyyy",
197                         };
198
199                         foreach (string format in formats)
200                         {
201                                 string serialized = dto.ToString (format, fp);
202                                 //Console.WriteLine ("{0} {1} {2}", format, dto, serialized);
203                                 Assert.AreEqual (dto.Date, DateTimeOffset.ParseExact (serialized, format, fp).Date, format);
204
205                         }
206                 }
207
208                 [Test]
209                 public void ParseExactTest ()
210                 {
211                         CultureInfo fp = CultureInfo.InvariantCulture;
212                         DateTimeOffset[] dtos = {
213                                 new DateTimeOffset (2008, 01, 14, 13, 21, 0, new TimeSpan (1,0,0)),
214                                 new DateTimeOffset (2008, 01, 14, 13, 21, 0, new TimeSpan (-5,0,0)),
215                         };
216
217                         string[] formats = {
218                                 "M/dd/yyyy HH:m zzz",  "MM/dd/yyyy HH:m zzz",
219                                 "M/d/yyyy HH:m zzz",   "MM/d/yyyy HH:m zzz",
220                                 "M/dd/yy HH:m zzz",    "MM/dd/yy HH:m zzz",
221                                 "M/d/yy HH:m zzz",     "M/d/yy HH:m zzz",
222                                 "M/dd/yyyy H:m zzz",   "MM/dd/yyyy H:m zzz",
223                                 "M/d/yyyy H:m zzz",    "MM/d/yyyy H:m zzz",
224                                 "M/dd/yy H:m zzz",     "MM/dd/yy H:m zzz",
225                                 "M/d/yy H:m zzz",      "MM/d/yy H:m zzz",
226                                 "M/dd/yyyy HH:mm zzz", "MM/dd/yyyy HH:mm zzz",
227                                 "M/d/yyyy HH:mm zzz",  "MM/d/yyyy HH:mm zzz",
228                                 "M/dd/yy HH:mm zzz",   "MM/dd/yy HH:mm zzz",
229                                 "M/d/yy HH:mm zzz",    "M/d/yy HH:mm zzz",
230                                 "M/dd/yyyy H:m zzz",   "MM/dd/yyyy H:m zzz",
231                                 "M/d/yyyy H:m zzz",    "MM/d/yyyy H:m zzz",
232                                 "M/dd/yy H:m zzz",     "MM/dd/yy H:m zzz",
233                                 "M/d/yy H:m zzz",      "M/d/yy H:m zzz",
234                                 "ddd dd MMM yyyy h:mm tt zzz", 
235                         };
236
237                         foreach (DateTimeOffset dto in dtos)
238                                 foreach (string format in formats)
239                                 {
240                                         string serialized = dto.ToString (format, fp);
241                                         //Console.WriteLine ("{0} {1} {2}", format, dto, serialized);
242                                         Assert.AreEqual (dto, DateTimeOffset.ParseExact (serialized, format, fp), format);
243                                 }
244                 }
245
246                 //
247                 // Tests that we can parse the K format specifier which is a 4 digit offset
248                 // see bug 589227
249                 //
250                 [Test]
251                 public void ParseExactWithKFormat ()
252                 {
253                         DateTimeOffset o = DateTimeOffset.ParseExact ("Wed Mar 17 22:25:08 +0000 2010", "ddd MMM d H:m:ss K yyyy", CultureInfo.InvariantCulture);
254                 }
255                 
256                 [Test]
257                 public void ParseExactYearFormat ()
258                 {
259                         CultureInfo fp = CultureInfo.InvariantCulture;
260                         DateTimeOffset[] dtos = {
261                                 new DateTimeOffset (2008, 01, 14, 13, 21, 0, new TimeSpan (1,0,0)),
262                                 new DateTimeOffset (2008, 01, 14, 13, 21, 0, new TimeSpan (-5,0,0)),
263                                 new DateTimeOffset (1978, 02, 16, 13, 21, 0, new TimeSpan (2,0,0)),
264                                 new DateTimeOffset (999, 9, 9, 9, 9, 0, new TimeSpan (3,0,0)),
265                         };
266
267                         string[] formats = {
268 //                              "M/d/yyy H:m zzz", // fails under .NET 2.0 and 4.0.
269                                 "M/d/yyyy H:m zzz",
270                                 "M/d/yyyyy H:m zzz",
271                                 "M/d/yyyyyy H:m zzz",
272                                 "M/d/yyyyyyy H:m zzz",
273                         };
274
275                         foreach (DateTimeOffset dto in dtos)
276                                 foreach (string format in formats)
277                                 {
278                                         string serialized = dto.ToString (format, fp);
279                                         //Console.WriteLine ("{0} {1} {2}", format, dto, serialized);
280                                         Assert.AreEqual (dto, DateTimeOffset.ParseExact (serialized, format, fp), format);
281                                 }
282                         
283                 }
284
285                 [Test]
286                 public void ParseExactOffsetFormat ()
287                 {
288                         CultureInfo fp = CultureInfo.InvariantCulture;
289                         string[] dates = {
290                                 "13/Oct/2009:22:35:35 +09:00",
291                                 "13/Oct/2009:22:35:35 +0900",
292                                 "13/Oct/2009:22:35:35 +09:30",
293                                 "13/Oct/2009:22:35:35 +0930",
294                         };
295                         TimeSpan[] offsets = {
296                                 new TimeSpan (9,0,0),
297                                 new TimeSpan (9,0,0),
298                                 new TimeSpan (9,30,0),
299                                 new TimeSpan (9,30,0),
300                         };
301
302                         for (int i = 0; i < dates.Length; i++)
303                                 Assert.AreEqual(offsets[i], DateTimeOffset.ParseExact (dates[i], "d/MMM/yyyy:HH:mm:ss zzz", fp).Offset, dates[i]);
304                 }
305
306                 [Test]
307                 [ExpectedException (typeof (FormatException))]
308                 public void ParseExactYearException ()
309                 {
310                         CultureInfo fp = CultureInfo.InvariantCulture;
311                         string format = "M/d/yyyy H:m zzz";
312                         string date = "1/15/999 10:58 +01:00";
313                         DateTimeOffset.ParseExact(date, format, fp);    
314                 }
315
316                 [Test]
317                 [ExpectedException (typeof (FormatException))]
318                 public void ParseExactFormatException1 ()
319                 {
320                         CultureInfo fp = CultureInfo.InvariantCulture;
321                         string format = "d";
322                         string date = "1/14/2008";
323                         DateTimeOffset.ParseExact(date, format, fp);
324                 }
325
326                 [Test]
327                 [ExpectedException (typeof (FormatException))]
328                 public void ParseExactFormatException2 ()
329                 {
330                         CultureInfo fp = CultureInfo.InvariantCulture;
331                         string format = "ddd dd MMM yyyy h:mm tt zzz";
332                         string date = "Mon 14 Jan 2008 2:56 PM +01";
333                         DateTimeOffset.ParseExact(date, format, fp);
334                 }
335
336                 [Test]
337                 [ExpectedException (typeof (FormatException))]
338                 public void ParseExactFormatException3 ()
339                 {
340                         CultureInfo fp = CultureInfo.InvariantCulture;
341                         string format = "ddd dd MMM yyyy h:mm tt zzz";
342                         string date = "Mon 14 Jan 2008 2:56 PM +01:1";
343                         DateTimeOffset.ParseExact(date, format, fp);
344                 }
345
346                 [Test]
347                 [ExpectedException (typeof (FormatException))]
348                 public void ParseExactFormatException4 ()
349                 {
350                         CultureInfo fp = CultureInfo.InvariantCulture;
351                         string format = "ddd dd MMM yyyy h:mm tt zzz";
352                         string date = "Mon 14 Jan 2008 2:56 PM +01: 00";
353                         DateTimeOffset.ParseExact(date, format, fp);
354                 }
355
356                 [Test]
357                 public void ParseExactWithSeconds ()
358                 {
359                         CultureInfo fp = CultureInfo.InvariantCulture;
360                         DateTimeOffset[] dtos = {
361                                 new DateTimeOffset (2008, 01, 14, 13, 21, 25, new TimeSpan (1,0,0)),
362                                 new DateTimeOffset (2008, 01, 14, 13, 21, 5, new TimeSpan (-5,0,0)),
363                         };
364
365                         string[] formats = {
366                                 "dddd, dd MMMM yyyy HH:mm:ss zzz",
367                         };
368
369                         foreach (DateTimeOffset dto in dtos)
370                                 foreach (string format in formats)
371                                 {
372                                         string serialized = dto.ToString (format, fp);
373                                         //Console.WriteLine ("{0} {1} {2}", format, dto, serialized);
374                                         Assert.AreEqual (dto, DateTimeOffset.ParseExact (serialized, format, fp), format);
375                                 }
376                 }
377
378                 [Test]
379                 public void ParseDateOnly ()
380                 {
381                         DateTimeOffset dto = DateTimeOffset.Parse ("2009/06/14");
382                         Assert.AreEqual (14, dto.Day, "Day");
383                         Assert.AreEqual (6, dto.Month, "Month");
384                         Assert.AreEqual (2009, dto.Year, "Year");
385                 }
386
387                 [Test]
388                 public void ParseTimeOnly ()
389                 {
390                         DateTimeOffset dto = DateTimeOffset.Parse ("2:3:4");
391                         Assert.AreEqual (2, dto.Hour, "Hour");
392                         Assert.AreEqual (3, dto.Minute, "Minute");
393                         Assert.AreEqual (4, dto.Second, "Second");
394                 }
395
396                 [Test]
397                 public void ParseTimeTZ ()
398                 {
399                         DateTimeOffset dto = DateTimeOffset.Parse ("2:30:40 +3:4");
400                         Assert.AreEqual (2, dto.Hour, "Hour");
401                         Assert.AreEqual (30, dto.Minute, "Minute");
402                         Assert.AreEqual (40, dto.Second, "Second");
403                         Assert.AreEqual (3, dto.Offset.Hours, "Offset Hours");
404                         Assert.AreEqual (4, dto.Offset.Minutes, "Offset Minutes");
405                 }
406
407                 [Test]
408                 public void ParseTimePMTZ ()
409                 {
410                         DateTimeOffset dto = DateTimeOffset.Parse ("3:30:40 PM -3:4");
411                         Assert.AreEqual (15, dto.Hour, "Hour");
412                         Assert.AreEqual (30, dto.Minute, "Minute");
413                         Assert.AreEqual (40, dto.Second, "Second");
414                         Assert.AreEqual (-3, dto.Offset.Hours, "Offset Hours");
415                         Assert.AreEqual (-4, dto.Offset.Minutes, "Offset Minutes");
416                 }
417
418                 [Test]
419                 public void ParseFull1 ()
420                 {
421                         DateTimeOffset dto = DateTimeOffset.Parse ("2009/06/14 2:30:40 AM -03:04");
422                         Assert.AreEqual (14, dto.Day, "Day");
423                         Assert.AreEqual (6, dto.Month, "Month");
424                         Assert.AreEqual (2009, dto.Year, "Year");
425                         Assert.AreEqual (2, dto.Hour, "Hour");
426                         Assert.AreEqual (30, dto.Minute, "Minute");
427                         Assert.AreEqual (40, dto.Second, "Second");
428                         Assert.AreEqual (-3, dto.Offset.Hours, "Offset Hours");
429                         Assert.AreEqual (-4, dto.Offset.Minutes, "Offset Minutes");
430                 }
431
432                 [Test]
433                 [ExpectedException (typeof (FormatException))]
434                 public void ParseUnderflow ()
435                 {
436                         DateTimeOffset.Parse ("01/01/0001 0:0 +09:00", new CultureInfo ("en-US"));
437                 }
438
439                 [Test]
440                 [ExpectedException (typeof (FormatException))]
441                 public void ParseOverflow ()
442                 {
443                         DateTimeOffset.Parse ("12/31/9999 23:59 -09:00", new CultureInfo ("en-US"));
444                 }
445
446                 [Test]
447                 public void ParseExactWithFractions ()
448                 {
449                         CultureInfo fp = CultureInfo.InvariantCulture;
450                         DateTimeOffset[] dtos = {
451                                 new DateTimeOffset (2008, 1, 15, 14, 36, 44, 900, TimeSpan.Zero),
452                         };
453
454                         string[] formats = {
455                                 "M/d/yyyy H:m:ss,f zzz",
456                                 "M/d/yyyy H:m:ss,ff zzz",
457                                 "M/d/yyyy H:m:ss,fff zzz",
458                                 "M/d/yyyy H:m:ss,ffff zzz",
459                                 "M/d/yyyy H:m:ss,fffff zzz",
460                                 "M/d/yyyy H:m:ss,ffffff zzz",
461                                 "M/d/yyyy H:m:ss,fffffff zzz",
462                                 "M/d/yyyy H:m:ss,F zzz",
463                                 "M/d/yyyy H:m:ss,FF zzz",
464                                 "M/d/yyyy H:m:ss,FFF zzz",
465                                 "M/d/yyyy H:m:ss,FFFF zzz",
466                                 "M/d/yyyy H:m:ss,FFFFF zzz",
467                                 "M/d/yyyy H:m:ss,FFFFFF zzz",
468                                 "M/d/yyyy H:m:ss,FFFFFFF zzz",
469                         };
470
471                         foreach (DateTimeOffset dto in dtos)
472                                 foreach (string format in formats)
473                                 {
474                                         string serialized = dto.ToString (format, fp);
475                                         //Console.WriteLine ("{0} {1} {2}", format, dto, serialized);
476                                         Assert.AreEqual (dto, DateTimeOffset.ParseExact (serialized, format, fp), format);
477                                 }
478                 }
479
480                 [Test]
481                 public void ParseExactPreserveFractions ()
482                 {
483                         var s = "1999-06-10T21:27:03.1147764+02:00";
484                         var d = DateTimeOffset.ParseExact (s, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
485                         Assert.AreEqual (630646468231147764, d.Ticks, "#1");
486                 }
487
488                 [Test]
489                 public void EqualsObject ()
490                 {
491                         DateTimeOffset offset1 = new DateTimeOffset ();
492                         Assert.IsFalse (offset1.Equals (null), "null"); // found using Gendarme :)
493                         Assert.IsTrue (offset1.Equals (offset1), "self");
494                         DateTimeOffset offset2 = new DateTimeOffset (DateTime.Today);
495                         Assert.IsFalse (offset1.Equals (offset2), "1!=2");
496                         Assert.IsFalse (offset2.Equals (offset1), "2!=1");
497                 }
498
499                 [Test]
500                 public void Serialization()
501                 {
502                         global::System.IO.MemoryStream dst = new global::System.IO.MemoryStream ();
503                         global::System.Runtime.Serialization.IFormatter fmtr
504                                 = new global::System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
505                         for (int i = 0; i < SerializationCases.Length; ++i) {
506                                 dst.SetLength (0);
507                                 DateTimeOffset cur = SerializationCases[i].Input;
508                                 fmtr.Serialize (dst, cur);
509                                 String result = BitConverter.ToString (dst.GetBuffer (), 0, (int)dst.Length);
510                                 Assert.AreEqual (SerializationCases[i].ResultBinaryString, result, "resultToString #" + i);
511                         }//for
512                 }
513
514                 [Test]
515                 public void Deserialization()
516                 {
517                         global::System.Runtime.Serialization.IFormatter fmtr
518                                 = new global::System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
519                         global::System.IO.MemoryStream src;
520                         for (int i = 0; i < SerializationCases.Length; ++i) {
521                                 src = new global::System.IO.MemoryStream (
522                                         BitConverter_ByteArray_FromString (SerializationCases[i].ResultBinaryString));
523                                 DateTimeOffset result = (DateTimeOffset)fmtr.Deserialize (src);
524 #if false // DUMP_TO_CONSOLE
525                                 Console.WriteLine ("#{0} input.o/s : {1}", i, SerializationCases[i].Input.Offset);
526                                 Console.WriteLine ("#{0} result.o/s: {1}", i, result.Offset);
527                                 Console.WriteLine ("#{0} input.dt : {1}={1:R}={1:u}", i, SerializationCases[i].Input.DateTime);
528                                 Console.WriteLine ("#{0} result.dt: {1}={1:R}={1:u}", i, result.DateTime);
529                                 Console.WriteLine ("#{0} input.dtK: {1}", i, SerializationCases[i].Input.DateTime.Kind);
530                                 Console.WriteLine ("#{0} input : {1}={1:R}={1:u}", i, SerializationCases[i].Input);
531                                 Console.WriteLine ("#{0} result: {1}={1:R}={1:u}", i, result);
532 #endif
533                                 Assert.AreEqual (SerializationCases[i].Input.Offset, result.Offset, ".Offset #" + i);
534                                 Assert.AreEqual (SerializationCases[i].Input.DateTime, result.DateTime, ".DateTime #" + i);
535                                 Assert.AreEqual (SerializationCases[i].Input, result, "equals #" + i);
536                                 // DateTimeOffset always stores as Kind==Unspecified
537                                 Assert.AreEqual (DateTimeKind.Unspecified, SerializationCases[i].Input.DateTime.Kind, ".DateTime.Kind==unspec #" + i);
538                                 Assert.AreEqual (SerializationCases[i].Input.DateTime.Kind, result.DateTime.Kind, ".DateTime.Kind #" + i);
539                         }//for
540                 }
541
542                 public class TestRow
543                 {
544                         public DateTimeOffset Input;
545                         public String ResultBinaryString;
546
547                         public TestRow(DateTimeOffset input, String resultBinaryString)
548                         {
549                                 this.Input = input;
550                                 this.ResultBinaryString = resultBinaryString;
551                         }
552                 }
553                 readonly TestRow[] SerializationCases = {
554                         // Multiple tests of Unspecified and different timezone offsets; one 
555                         // for UTC; and one for Local which is disabled as it suits only a machine
556                         // in GMT or similar.
557 #if ___MACHINE_TIMEZONE_HAS_ZERO_OFFSET
558                         // The "new DateTimeOffset(new DateTime(...)))" expression results in a 
559                         // DTO that has an offset set to the machine timezone offset.  So, as 
560                         // with the test case at the bottom we can't test this around the world.
561                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50)),
562                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
563                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
564                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
565                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
566                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
567                                 + "FC-C8-08-00-00-0B"),
568 #endif
569                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (0, 0, 0)),
570                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
571                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
572                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
573                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
574                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
575                                 + "FC-C8-08-00-00-0B"),
576                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (1, 0, 0)),
577                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
578                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
579                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
580                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
581                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-D1-B0-96-78-"
582                                 + "FC-C8-08-3C-00-0B"),
583                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (0, 30, 0)),
584                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
585                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
586                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
587                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
588                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-05-93-C7-7C-"
589                                 + "FC-C8-08-1E-00-0B"),
590                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (-5, 0, 0)),
591                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
592                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
593                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
594                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
595                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-41-4B-E1-AA-"
596                                 + "FC-C8-08-D4-FE-0B"),
597                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (-10, 30, 0)),
598                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
599                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
600                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
601                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
602                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-15-3F-99-D0-"
603                                 + "FC-C8-08-C6-FD-0B"),
604                         // invalid case: .ctor ArgEx "non whole minutes"
605                         //      new DateTimeOffset(new DateTime(2007, 01, 02, 12, 30, 50), new TimeSpan(1, 2, 3));
606                         //----
607                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50, DateTimeKind.Utc)),
608                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
609                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
610                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
611                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
612                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
613                                 + "FC-C8-08-00-00-0B"),
614                         //----
615 #if ___MACHINE_TIMEZONE_HAS_ZERO_OFFSET
616                         // Local needs offset to be the same as the machine timezone,
617                         // not easy to cope with the tests being run around the world!
618                         // This one works in UK, etc.
619                         new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50, DateTimeKind.Local), new TimeSpan (0,0,0)),
620                                 "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
621                                 + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
622                                 + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
623                                 + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
624                                 + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
625                                 + "FC-C8-08-00-00-0B"),
626 #endif
627                 };
628
629                 static byte[] BitConverter_ByteArray_FromString(String hexString)
630                 {
631                         String[] numbers = hexString.Split('-');
632                         byte[] result = new byte[numbers.Length];
633                         for (int i = 0; i < numbers.Length; ++i) {
634                                 byte x = Byte.Parse (numbers[i], NumberStyles.HexNumber, global::System.Globalization.CultureInfo.InvariantCulture);
635                                 result[i] = x;
636                         }
637                         return result;
638                 }
639                 
640                 [Test]
641                 public void ArithmeticAccrossDSTBoudaries ()
642                 {
643                         DateTime dt = new DateTime (633954393584177800, DateTimeKind.Local); //Dec 3, 2009, 12:16
644                         DateTimeOffset dto = new DateTimeOffset (dt);
645                         DateTimeOffset dto2 = dto.AddDays (-60); //Should cross the late Oct boundary in most part of the world
646                         Assert.AreEqual (dto.Offset, dto2.Offset);
647                         Assert.AreEqual (dt.AddDays (-60), dto2.DateTime);
648                 }
649         }
650 }
651