Browse Source

complete custom local time zone feature

Brian Beard 11 years ago
parent
commit
aca99f86c3

+ 3 - 2
Jint.Tests.Ecma/EcmaTest.cs

@@ -25,8 +25,9 @@ namespace Jint.Tests.Ecma
         {
             _lastError = null;
 
-            var engine = new Engine();
-
+            //NOTE: The Date tests in test262 assume the local timezone is Pacific Standard Time
+            var pacificTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
+            var engine = new Engine(cfg => cfg.LocalTimeZone(pacificTimeZone));
 
             // loading driver
 

+ 65 - 48
Jint.Tests/Runtime/EngineTests.cs

@@ -761,65 +761,82 @@ namespace Jint.Tests.Runtime
             var result = engine.Execute("Date.UTC(1970,0,1)").GetCompletionValue().AsNumber();
             Assert.Equal(0, result);
         }
-		
+
         [Fact]
         public void ShouldUseLocalTimeZoneOverride()
         {
-            //var all = TimeZoneInfo.GetSystemTimeZones();
-            //var skip = new[]
-            //{
-            //    "Dateline Standard Time",
-            //    "UTC-11",
-            //    "Hawaiian Standard Time"
-            //};
-            //foreach (var localTimeZone in all)
-            //{
-
-            //    if (skip.Contains(localTimeZone.Id))
-            //    {
-            //        continue;
-            //    }
-
-            //    //var localTimeZone = TimeZoneInfo.Local;
-
-            //    var customHoursOffsetFromLocal = 1;
-            //    var expectedToStringValue = "Mon Feb 02 1990 15:00:00 GMT";
-            //    var expectedGetHoursValue = 15d;
-            //    if (localTimeZone.BaseUtcOffset.Hours > 11)
-            //    {
-            //        customHoursOffsetFromLocal = -1;
-            //        expectedToStringValue = "Mon Feb 02 1990 13:00:00 GMT";
-            //        expectedGetHoursValue = 13d;
-            //    }
-
-                const string customName = "Custom Time";
-                //var customUtcOffset = localTimeZone.BaseUtcOffset.Add(new TimeSpan(customHoursOffsetFromLocal, 0, 0));
-            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName,
-                customName, customName, null, false);
-
-                //var d = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
-
-                //var u = TimeZoneInfo.ConvertTime(d, localTimeZone, TimeZoneInfo.Utc);
-                //var l = TimeZoneInfo.ConvertTime(u, customTimeZone);
+            const string customName = "Custom Time";
+            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName, customName, customName, null, false);
 
-                var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone));
 
+            var epochGetLocalMinutes = engine.Execute("var d = new Date(0); d.getMinutes();").GetCompletionValue().AsNumber();
+            Assert.Equal(11, epochGetLocalMinutes);
 
-                var d1 = engine.Execute("var d = new Date(0); d.getTime();").GetCompletionValue().AsNumber();
-                var d2 = engine.Execute("var d = new Date(Date.UTC(1970,0,1)); d.getTime();").GetCompletionValue().AsNumber();
+            var localEpochGetUtcMinutes = engine.Execute("var d = new Date(1970,0,1); d.getUTCMinutes();").GetCompletionValue().AsNumber();
+            Assert.Equal(-11, localEpochGetUtcMinutes);
 
+            var parseLocalEpoch = engine.Execute("Date.parse('January 1, 1970');").GetCompletionValue().AsNumber();
+            Assert.Equal(-11 * 60 * 1000, parseLocalEpoch);
 
-                var result = engine.Execute("var d1 = new Date(0); var d2 = new Date(Date.UTC(1970,0,1)); d1.getTime() === d2.getTime();").GetCompletionValue().AsBoolean();
-                Assert.Equal(true, result);
-
-                var toStringResult = engine.Execute("var d = new Date(946684800000); d.toString();").GetCompletionValue().AsString();
-                Assert.Equal("Sat Jan 01 2000 00:11:00 GMT", toStringResult);
+            var epochToLocalString = engine.Execute("var d = new Date(0); d.toString();").GetCompletionValue().AsString();
+            Assert.Equal("Thu Jan 01 1970 00:11:00 GMT", epochToLocalString);
+        }
 
-                var getMinutesResult = engine.Execute("var d = new Date(946684800000); d.getMinutes();").GetCompletionValue().AsNumber();
-                Assert.Equal(11, getMinutesResult);
+        [Theory]
+        [InlineData("1970")]
+        [InlineData("1970-01")]
+        [InlineData("1970-01-01")]
+        [InlineData("1970-01-01T00:00")]
+        [InlineData("1970-01-01T00:00:00")]
+        [InlineData("1970-01-01T00:00:00.000")]
+        [InlineData("1970Z")]
+        [InlineData("1970-1Z")]
+        [InlineData("1970-1-1Z")]
+        [InlineData("1970-1-1T0:0Z")]
+        [InlineData("1970-1-1T0:0:0Z")]
+        [InlineData("1970-1-1T0:0:0.0Z")]
+        [InlineData("1970/1Z")]
+        [InlineData("1970/1/1Z")]
+        [InlineData("1970/1/1 0:0Z")]
+        [InlineData("1970/1/1 0:0:0Z")]
+        [InlineData("1970/1/1 0:0:0.0Z")]
+        [InlineData("January 1, 1970 GMT")]
+        [InlineData("1970-01-01T00:00:00.000-00:00")]
+        public void ShouldParseAsUtc(string date)
+        {
+            var engine = new Engine().SetValue("d", date);
+            var result = engine.Execute("Date.parse(d);").GetCompletionValue().AsNumber();
 
-            //}
+            Assert.Equal(0, result);
+        }
 
+        [Theory]
+        [InlineData("1970/01")]
+        [InlineData("1970/01/01")]
+        [InlineData("1970/01/01T00:00")]
+        [InlineData("1970/01/01 00:00")]
+        [InlineData("1970-1")]
+        [InlineData("1970-1-1")]
+        [InlineData("1970-1-1T0:0")]
+        [InlineData("1970-1-1 0:0")]
+        [InlineData("1970/1")]
+        [InlineData("1970/1/1")]
+        [InlineData("1970/1/1T0:0")]
+        [InlineData("1970/1/1 0:0")]
+        [InlineData("01-1970")]
+        [InlineData("01-01-1970")]
+        [InlineData("January 1, 1970")]
+        [InlineData("1970-01-01T00:00:00.000+00:11")]
+        public void ShouldParseAsLocalTime(string date)
+        {
+            const string customName = "Custom Time";
+            var customTimeZone = TimeZoneInfo.CreateCustomTimeZone(customName, new TimeSpan(0, 11, 0), customName, customName, customName, null, false);
+            var engine = new Engine(cfg => cfg.LocalTimeZone(customTimeZone)).SetValue("d", date);
+
+            var result = engine.Execute("Date.parse(d);").GetCompletionValue().AsNumber();
+
+            Assert.Equal(-11 * 60 * 1000, result);
         }
 
     }

+ 37 - 19
Jint/Native/Date/DateConstructor.cs

@@ -46,30 +46,35 @@ namespace Jint.Native.Date
 
             if (!DateTime.TryParseExact(date, new[]
             {
-                "yyyy/MM/ddTH:m:s.fff",
-                "yyyy/MM/dd",
-                "yyyy/MM",
-                "yyyy-MM-ddTH:m:s.fff",
+                "yyyy-MM-ddTHH:mm:ss.FFF",
+                "yyyy-MM-ddTHH:mm:ss",
+                "yyyy-MM-ddTHH:mm",
                 "yyyy-MM-dd",
                 "yyyy-MM",
-                "yyyy",
-                "THH:m:s.fff",
-                "TH:mm:sm",
-                "THH:mm",
-                "THH"
+                "yyyy"
             }, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out result))
             {
                 if (!DateTime.TryParseExact(date, new[]
                 {
-                    "yyyy/MM/ddTH:m:s.fffK",
-                    "yyyy/MM/ddK",
-                    "yyyy/MMK",
-                    "yyyy-MM-ddTH:m:s.fffK",
-                    "yyyy-MM-ddK",
-                    "yyyy-MMK",
+                    "yyyy-M-dTH:m:s.FFFK",
+                    "yyyy/M/dTH:m:s.FFFK",
+                    "yyyy-M-dTH:m:sK",
+                    "yyyy/M/dTH:m:sK",
+                    "yyyy-M-dTH:mK",
+                    "yyyy/M/dTH:mK",
+                    "yyyy-M-d H:m:s.FFFK",
+                    "yyyy/M/d H:m:s.FFFK",
+                    "yyyy-M-d H:m:sK",
+                    "yyyy/M/d H:m:sK",
+                    "yyyy-M-d H:mK",
+                    "yyyy/M/d H:mK",
+                    "yyyy-M-dK",
+                    "yyyy/M/dK",
+                    "yyyy-MK",
+                    "yyyy/MK",
                     "yyyyK",
-                    "THH:m:s.fffK",
-                    "TH:mm:smK",
+                    "THH:mm:ss.FFFK",
+                    "THH:mm:ssK",
                     "THH:mmK",
                     "THHK"
                 }, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out result))
@@ -206,9 +211,22 @@ namespace Jint.Native.Date
             return TypeConverter.ToInteger(time);
         }
 
-        public static double FromDateTime(DateTime dt)
+        public double FromDateTime(DateTime dt)
         {
-            return System.Math.Floor((dt.ToUniversalTime() - Epoch).TotalMilliseconds);
+            var convertToUtcAfter = (dt.Kind == DateTimeKind.Unspecified);
+
+            var dateAsUtc = dt.Kind == DateTimeKind.Local
+                ? dt.ToUniversalTime()
+                : DateTime.SpecifyKind(dt, DateTimeKind.Utc);
+
+            var result = (dateAsUtc - Epoch).TotalMilliseconds;
+
+            if (convertToUtcAfter)
+            {
+                result = PrototypeObject.Utc(result);
+            }
+
+            return System.Math.Floor(result);
         }
     }
 }

+ 7 - 12
Jint/Native/Date/DatePrototype.cs

@@ -335,7 +335,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private JsValue SetUTCMilliseconds(JsValue thisObj, JsValue[] arguments)
+        private static JsValue SetUTCMilliseconds(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.As<DateInstance>().PrimitiveValue;
             var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), TypeConverter.ToNumber(arguments.At(0)));
@@ -355,7 +355,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private JsValue SetUTCSeconds(JsValue thisObj, JsValue[] arguments)
+        private static JsValue SetUTCSeconds(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.As<DateInstance>().PrimitiveValue;
             var s = TypeConverter.ToNumber(arguments.At(0));
@@ -378,7 +378,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private JsValue SetUTCMinutes(JsValue thisObj, JsValue[] arguments)
+        private static JsValue SetUTCMinutes(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.As<DateInstance>().PrimitiveValue;
             var m = TypeConverter.ToNumber(arguments.At(0));
@@ -403,7 +403,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private JsValue SetUTCHours(JsValue thisObj, JsValue[] arguments)
+        private static JsValue SetUTCHours(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.As<DateInstance>().PrimitiveValue;
             var h = TypeConverter.ToNumber(arguments.At(0));
@@ -426,7 +426,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private JsValue SetUTCDate(JsValue thisObj, JsValue[] arguments)
+        private static JsValue SetUTCDate(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.As<DateInstance>().PrimitiveValue;
             var dt = TypeConverter.ToNumber(arguments.At(0));
@@ -447,7 +447,7 @@ namespace Jint.Native.Date
             return u;
         }
 
-        private JsValue SetUTCMonth(JsValue thisObj, JsValue[] arguments)
+        private static JsValue SetUTCMonth(JsValue thisObj, JsValue[] arguments)
         {
             var t = thisObj.As<DateInstance>().PrimitiveValue;
             var m = TypeConverter.ToNumber(arguments.At(0));
@@ -866,14 +866,9 @@ namespace Jint.Native.Date
 
         public DateTime ToLocalTime(DateTime t)
         {
-            if (t.Kind == DateTimeKind.Local)
-            {
-                return t;
-            }
-
             if (t.Kind == DateTimeKind.Unspecified)
             {
-                t = DateTime.SpecifyKind(t, DateTimeKind.Utc);
+                return t;
             }
 
             return TimeZoneInfo.ConvertTime(t, Engine.Options.GetLocalTimeZone());