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