Merge branch 'master' into msbuilddll2
[mono.git] / mcs / class / corlib / Test / System / DateTimeOffsetTest.cs
index c10f9a4aa5d7b75b9decae123a3b74448cabd7e7..3bc65a8204b3beb05743dd022ee26e45b11e4dc5 100644 (file)
@@ -3,11 +3,12 @@
 //
 // Authors:
 //     Stephane Delcroix  (sdelcroix@novell.com)
+//     Marek Safar (marek.safar@gmail.com)
 //
 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
+// Copyright 2012 Xamarin, Inc (http://www.xamarin.com)
 //
 
-#if NET_2_0
 using System.Globalization;
 using NUnit.Framework;
 using System;
@@ -96,7 +97,7 @@ namespace MonoTests.System {
                        Assert.IsTrue (dt1 != dt3);
                        Assert.IsFalse (dt1.EqualsExact (dt2));
                        Assert.IsTrue (dt1.CompareTo (dt3) > 0);
-                       Assert.IsTrue (dt1.CompareTo (o) == 0);
+                       Assert.IsTrue (((IComparable)dt1).CompareTo (o) == 0);
                }
 
                [Test]
@@ -162,7 +163,7 @@ namespace MonoTests.System {
                        Assert.AreEqual (dto.ToString ("r", new CultureInfo ("en-us")), dto.ToString ("R", new CultureInfo ("en-us")));
                        Assert.AreEqual ("2007-10-31T21:00:00", dto.ToString ("s", new CultureInfo ("en-us")));
                        Assert.AreEqual ("2007-11-01 05:00:00Z", dto.ToString ("u", new CultureInfo ("en-us")));
-                       Assert.AreEqual ("October, 2007", dto.ToString ("Y", new CultureInfo ("en-us")));
+                       Assert.AreEqual ("October 2007", dto.ToString ("Y", new CultureInfo ("en-us")));
                        Assert.AreEqual (dto.ToString ("y", new CultureInfo ("en-us")), dto.ToString ("Y", new CultureInfo ("en-us")));
                }
 
@@ -189,7 +190,7 @@ namespace MonoTests.System {
                                "M/dd/yyyy",
                                "M/d/y",
                                "M/d/yy",
-                               "M/d/yyy",
+//                             "M/d/yyy", // this fails on .NET 2.0 (3.5) and 4.0
                                "M/d/yyyy",
                                "M/d/yyyyy",
                                "M/d/yyyyyy",
@@ -232,7 +233,10 @@ namespace MonoTests.System {
                                "M/d/yyyy H:m zzz",    "MM/d/yyyy H:m zzz",
                                "M/dd/yy H:m zzz",     "MM/dd/yy H:m zzz",
                                "M/d/yy H:m zzz",      "M/d/yy H:m zzz",
-                               "ddd dd MMM yyyy h:mm tt zzz", 
+                               "ddd dd MMM yyyy h:mm tt zzz",
+                               "o", "O",
+                               "r", "R",
+                               "u",
                        };
 
                        foreach (DateTimeOffset dto in dtos)
@@ -243,6 +247,24 @@ namespace MonoTests.System {
                                        Assert.AreEqual (dto, DateTimeOffset.ParseExact (serialized, format, fp), format);
                                }
                }
+
+               //
+               // Tests that we can parse the K format specifier which is a 4 digit offset
+               // see bug 589227
+               //
+               [Test]
+               public void ParseExactWithKFormat ()
+               {
+                       DateTimeOffset o = DateTimeOffset.ParseExact ("Wed Mar 17 22:25:08 +0000 2010", "ddd MMM d H:m:ss K yyyy", CultureInfo.InvariantCulture);
+               }
+
+               [Test]
+               public void ParseExactCustomFormat ()
+               {
+                       var dt = DateTimeOffset.ParseExact ("Sunday, 06-Nov-94 08:49:37 GMT", "dddd, dd'-'MMM'-'yy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture);
+                       Assert.AreEqual (new DateTimeOffset (1994, 11, 6, 8, 49, 37, TimeZone.CurrentTimeZone.GetUtcOffset (DateTime.Now)), dt);
+               }
+               
                [Test]
                public void ParseExactYearFormat ()
                {
@@ -255,7 +277,7 @@ namespace MonoTests.System {
                        };
 
                        string[] formats = {
-                               "M/d/yyy H:m zzz",
+//                             "M/d/yyy H:m zzz", // fails under .NET 2.0 and 4.0.
                                "M/d/yyyy H:m zzz",
                                "M/d/yyyyy H:m zzz",
                                "M/d/yyyyyy H:m zzz",
@@ -272,6 +294,27 @@ namespace MonoTests.System {
                        
                }
 
+               [Test]
+               public void ParseExactOffsetFormat ()
+               {
+                       CultureInfo fp = CultureInfo.InvariantCulture;
+                       string[] dates = {
+                               "13/Oct/2009:22:35:35 +09:00",
+                               "13/Oct/2009:22:35:35 +0900",
+                               "13/Oct/2009:22:35:35 +09:30",
+                               "13/Oct/2009:22:35:35 +0930",
+                       };
+                       TimeSpan[] offsets = {
+                               new TimeSpan (9,0,0),
+                               new TimeSpan (9,0,0),
+                               new TimeSpan (9,30,0),
+                               new TimeSpan (9,30,0),
+                       };
+
+                       for (int i = 0; i < dates.Length; i++)
+                               Assert.AreEqual(offsets[i], DateTimeOffset.ParseExact (dates[i], "d/MMM/yyyy:HH:mm:ss zzz", fp).Offset, dates[i]);
+               }
+
                [Test]
                [ExpectedException (typeof (FormatException))]
                public void ParseExactYearException ()
@@ -322,6 +365,16 @@ namespace MonoTests.System {
                        DateTimeOffset.ParseExact(date, format, fp);
                }
 
+               [Test]
+               [ExpectedException (typeof (FormatException))]
+               public void ParseExactFormatException5 ()
+               {
+                       CultureInfo fp = CultureInfo.InvariantCulture;
+                       string format = "U";
+                       string date = "Mon 14 Jan 2008 2:56 PM +01: 00";
+                       DateTimeOffset.ParseExact (date, format, fp);
+               }
+
                [Test]
                public void ParseExactWithSeconds ()
                {
@@ -344,6 +397,74 @@ namespace MonoTests.System {
                                }
                }
 
+               [Test]
+               public void ParseDateOnly ()
+               {
+                       DateTimeOffset dto = DateTimeOffset.Parse ("2009/06/14");
+                       Assert.AreEqual (14, dto.Day, "Day");
+                       Assert.AreEqual (6, dto.Month, "Month");
+                       Assert.AreEqual (2009, dto.Year, "Year");
+               }
+
+               [Test]
+               public void ParseTimeOnly ()
+               {
+                       DateTimeOffset dto = DateTimeOffset.Parse ("2:3:4");
+                       Assert.AreEqual (2, dto.Hour, "Hour");
+                       Assert.AreEqual (3, dto.Minute, "Minute");
+                       Assert.AreEqual (4, dto.Second, "Second");
+               }
+
+               [Test]
+               public void ParseTimeTZ ()
+               {
+                       DateTimeOffset dto = DateTimeOffset.Parse ("2:30:40 +3:4");
+                       Assert.AreEqual (2, dto.Hour, "Hour");
+                       Assert.AreEqual (30, dto.Minute, "Minute");
+                       Assert.AreEqual (40, dto.Second, "Second");
+                       Assert.AreEqual (3, dto.Offset.Hours, "Offset Hours");
+                       Assert.AreEqual (4, dto.Offset.Minutes, "Offset Minutes");
+               }
+
+               [Test]
+               public void ParseTimePMTZ ()
+               {
+                       DateTimeOffset dto = DateTimeOffset.Parse ("3:30:40 PM -3:4");
+                       Assert.AreEqual (15, dto.Hour, "Hour");
+                       Assert.AreEqual (30, dto.Minute, "Minute");
+                       Assert.AreEqual (40, dto.Second, "Second");
+                       Assert.AreEqual (-3, dto.Offset.Hours, "Offset Hours");
+                       Assert.AreEqual (-4, dto.Offset.Minutes, "Offset Minutes");
+               }
+
+               [Test]
+               public void ParseFull1 ()
+               {
+                       DateTimeOffset dto = DateTimeOffset.Parse ("2009/06/14 2:30:40 AM -03:04");
+                       Assert.AreEqual (14, dto.Day, "Day");
+                       Assert.AreEqual (6, dto.Month, "Month");
+                       Assert.AreEqual (2009, dto.Year, "Year");
+                       Assert.AreEqual (2, dto.Hour, "Hour");
+                       Assert.AreEqual (30, dto.Minute, "Minute");
+                       Assert.AreEqual (40, dto.Second, "Second");
+                       Assert.AreEqual (-3, dto.Offset.Hours, "Offset Hours");
+                       Assert.AreEqual (-4, dto.Offset.Minutes, "Offset Minutes");
+               }
+
+               [Test]
+               [ExpectedException (typeof (FormatException))]
+               public void ParseUnderflow ()
+               {
+                       DateTimeOffset.Parse ("01/01/0001 0:0 +09:00", new CultureInfo ("en-US"));
+               }
+
+               [Test]
+               [ExpectedException (typeof (FormatException))]
+               public void ParseOverflow ()
+               {
+                       DateTimeOffset.Parse ("12/31/9999 23:59 -09:00", new CultureInfo ("en-US"));
+               }
+
                [Test]
                public void ParseExactWithFractions ()
                {
@@ -378,6 +499,14 @@ namespace MonoTests.System {
                                }
                }
 
+               [Test]
+               public void ParseExactPreserveFractions ()
+               {
+                       var s = "1999-06-10T21:27:03.1147764+02:00";
+                       var d = DateTimeOffset.ParseExact (s, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
+                       Assert.AreEqual (630646468231147764, d.Ticks, "#1");
+               }
+
                [Test]
                public void EqualsObject ()
                {
@@ -388,7 +517,157 @@ namespace MonoTests.System {
                        Assert.IsFalse (offset1.Equals (offset2), "1!=2");
                        Assert.IsFalse (offset2.Equals (offset1), "2!=1");
                }
+
+               [Test]
+               public void Serialization()
+               {
+                       global::System.IO.MemoryStream dst = new global::System.IO.MemoryStream ();
+                       global::System.Runtime.Serialization.IFormatter fmtr
+                               = new global::System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
+                       for (int i = 0; i < SerializationCases.Length; ++i) {
+                               dst.SetLength (0);
+                               DateTimeOffset cur = SerializationCases[i].Input;
+                               fmtr.Serialize (dst, cur);
+                               String result = BitConverter.ToString (dst.GetBuffer (), 0, (int)dst.Length);
+                               Assert.AreEqual (SerializationCases[i].ResultBinaryString, result, "resultToString #" + i);
+                       }//for
+               }
+
+               [Test]
+               public void Deserialization()
+               {
+                       global::System.Runtime.Serialization.IFormatter fmtr
+                               = new global::System.Runtime.Serialization.Formatters.Binary.BinaryFormatter ();
+                       global::System.IO.MemoryStream src;
+                       for (int i = 0; i < SerializationCases.Length; ++i) {
+                               src = new global::System.IO.MemoryStream (
+                                       BitConverter_ByteArray_FromString (SerializationCases[i].ResultBinaryString));
+                               DateTimeOffset result = (DateTimeOffset)fmtr.Deserialize (src);
+#if false // DUMP_TO_CONSOLE
+                               Console.WriteLine ("#{0} input.o/s : {1}", i, SerializationCases[i].Input.Offset);
+                               Console.WriteLine ("#{0} result.o/s: {1}", i, result.Offset);
+                               Console.WriteLine ("#{0} input.dt : {1}={1:R}={1:u}", i, SerializationCases[i].Input.DateTime);
+                               Console.WriteLine ("#{0} result.dt: {1}={1:R}={1:u}", i, result.DateTime);
+                               Console.WriteLine ("#{0} input.dtK: {1}", i, SerializationCases[i].Input.DateTime.Kind);
+                               Console.WriteLine ("#{0} input : {1}={1:R}={1:u}", i, SerializationCases[i].Input);
+                               Console.WriteLine ("#{0} result: {1}={1:R}={1:u}", i, result);
+#endif
+                               Assert.AreEqual (SerializationCases[i].Input.Offset, result.Offset, ".Offset #" + i);
+                               Assert.AreEqual (SerializationCases[i].Input.DateTime, result.DateTime, ".DateTime #" + i);
+                               Assert.AreEqual (SerializationCases[i].Input, result, "equals #" + i);
+                               // DateTimeOffset always stores as Kind==Unspecified
+                               Assert.AreEqual (DateTimeKind.Unspecified, SerializationCases[i].Input.DateTime.Kind, ".DateTime.Kind==unspec #" + i);
+                               Assert.AreEqual (SerializationCases[i].Input.DateTime.Kind, result.DateTime.Kind, ".DateTime.Kind #" + i);
+                       }//for
+               }
+
+               public class TestRow
+               {
+                       public DateTimeOffset Input;
+                       public String ResultBinaryString;
+
+                       public TestRow(DateTimeOffset input, String resultBinaryString)
+                       {
+                               this.Input = input;
+                               this.ResultBinaryString = resultBinaryString;
+                       }
+               }
+               readonly TestRow[] SerializationCases = {
+                       // Multiple tests of Unspecified and different timezone offsets; one 
+                       // for UTC; and one for Local which is disabled as it suits only a machine
+                       // in GMT or similar.
+#if ___MACHINE_TIMEZONE_HAS_ZERO_OFFSET
+                       // The "new DateTimeOffset(new DateTime(...)))" expression results in a 
+                       // DTO that has an offset set to the machine timezone offset.  So, as 
+                       // with the test case at the bottom we can't test this around the world.
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
+                               + "FC-C8-08-00-00-0B"),
+#endif
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (0, 0, 0)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
+                               + "FC-C8-08-00-00-0B"),
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (1, 0, 0)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-D1-B0-96-78-"
+                               + "FC-C8-08-3C-00-0B"),
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (0, 30, 0)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-05-93-C7-7C-"
+                               + "FC-C8-08-1E-00-0B"),
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (-5, 0, 0)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-41-4B-E1-AA-"
+                               + "FC-C8-08-D4-FE-0B"),
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50), new TimeSpan (-10, 30, 0)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-15-3F-99-D0-"
+                               + "FC-C8-08-C6-FD-0B"),
+                       // invalid case: .ctor ArgEx "non whole minutes"
+                       //      new DateTimeOffset(new DateTime(2007, 01, 02, 12, 30, 50), new TimeSpan(1, 2, 3));
+                       //----
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50, DateTimeKind.Utc)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
+                               + "FC-C8-08-00-00-0B"),
+                       //----
+#if ___MACHINE_TIMEZONE_HAS_ZERO_OFFSET
+                       // Local needs offset to be the same as the machine timezone,
+                       // not easy to cope with the tests being run around the world!
+                       // This one works in UK, etc.
+                       new TestRow (new DateTimeOffset (new DateTime (2007, 01, 02, 12, 30, 50, DateTimeKind.Local), new TimeSpan (0,0,0)),
+                               "00-01-00-00-00-FF-FF-FF-FF-01-00-00-00-00-00-00-"
+                               + "00-04-01-00-00-00-15-53-79-73-74-65-6D-2E-44-61-"
+                               + "74-65-54-69-6D-65-4F-66-66-73-65-74-02-00-00-00-"
+                               + "08-44-61-74-65-54-69-6D-65-0D-4F-66-66-73-65-74-"
+                               + "4D-69-6E-75-74-65-73-00-00-0D-07-00-39-75-F8-80-"
+                               + "FC-C8-08-00-00-0B"),
+#endif
+               };
+
+               static byte[] BitConverter_ByteArray_FromString(String hexString)
+               {
+                       String[] numbers = hexString.Split('-');
+                       byte[] result = new byte[numbers.Length];
+                       for (int i = 0; i < numbers.Length; ++i) {
+                               byte x = Byte.Parse (numbers[i], NumberStyles.HexNumber, global::System.Globalization.CultureInfo.InvariantCulture);
+                               result[i] = x;
+                       }
+                       return result;
+               }
+               
+               [Test]
+               public void ArithmeticAccrossDSTBoudaries ()
+               {
+                       DateTime dt = new DateTime (633954393584177800, DateTimeKind.Local); //Dec 3, 2009, 12:16
+                       DateTimeOffset dto = new DateTimeOffset (dt);
+                       DateTimeOffset dto2 = dto.AddDays (-60); //Should cross the late Oct boundary in most part of the world
+                       Assert.AreEqual (dto.Offset, dto2.Offset);
+                       Assert.AreEqual (dt.AddDays (-60), dto2.DateTime);
+               }
        }
 }
-#endif