|
@@ -2,6 +2,8 @@
|
|
|
using System.Globalization;
|
|
|
using System.Runtime.CompilerServices;
|
|
|
using Jint.Collections;
|
|
|
+using Jint.Native.Object;
|
|
|
+using Jint.Native.Symbol;
|
|
|
using Jint.Runtime;
|
|
|
using Jint.Runtime.Descriptors;
|
|
|
using Jint.Runtime.Interop;
|
|
@@ -11,8 +13,14 @@ namespace Jint.Native.Date
|
|
|
/// <summary>
|
|
|
/// http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5
|
|
|
/// </summary>
|
|
|
- public sealed class DatePrototype : DateInstance
|
|
|
+ public sealed class DatePrototype : ObjectInstance
|
|
|
{
|
|
|
+ // ES6 section 20.3.1.1 Time Values and Time Range
|
|
|
+ private const double MinYear = -1000000.0;
|
|
|
+ private const double MaxYear = -MinYear;
|
|
|
+ private const double MinMonth = -10000000.0;
|
|
|
+ private const double MaxMonth = -MinMonth;
|
|
|
+
|
|
|
private DateConstructor _dateConstructor;
|
|
|
|
|
|
private DatePrototype(Engine engine)
|
|
@@ -25,7 +33,6 @@ namespace Jint.Native.Date
|
|
|
var obj = new DatePrototype(engine)
|
|
|
{
|
|
|
_prototype = engine.Object.PrototypeObject,
|
|
|
- PrimitiveValue = double.NaN,
|
|
|
_dateConstructor = dateConstructor
|
|
|
};
|
|
|
|
|
@@ -34,57 +41,91 @@ namespace Jint.Native.Date
|
|
|
|
|
|
protected override void Initialize()
|
|
|
{
|
|
|
+ const PropertyFlag lengthFlags = PropertyFlag.Configurable;
|
|
|
+ const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
|
|
|
+
|
|
|
_properties = new StringDictionarySlim<PropertyDescriptor>(50)
|
|
|
{
|
|
|
["constructor"] = new PropertyDescriptor(_dateConstructor, PropertyFlag.NonEnumerable),
|
|
|
- ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0), true, false, true),
|
|
|
- ["toDateString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toDateString", ToDateString, 0), true, false, true),
|
|
|
- ["toTimeString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toTimeString", ToTimeString, 0), true, false, true),
|
|
|
- ["toLocaleString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString, 0), true, false, true),
|
|
|
- ["toLocaleDateString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleDateString", ToLocaleDateString, 0), true, false, true),
|
|
|
- ["toLocaleTimeString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleTimeString", ToLocaleTimeString, 0), true, false, true),
|
|
|
- ["valueOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "valueOf", ValueOf, 0), true, false, true),
|
|
|
- ["getTime"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getTime", GetTime, 0), true, false, true),
|
|
|
- ["getFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getFullYear", GetFullYear, 0), true, false, true),
|
|
|
- ["getYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getYear", GetYear, 0), true, false, true),
|
|
|
- ["getUTCFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCFullYear", GetUTCFullYear, 0), true, false, true),
|
|
|
- ["getMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getMonth", GetMonth, 0), true, false, true),
|
|
|
- ["getUTCMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCMonth", GetUTCMonth, 0), true, false, true),
|
|
|
- ["getDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getDate", GetDate, 0), true, false, true),
|
|
|
- ["getUTCDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCDate", GetUTCDate, 0), true, false, true),
|
|
|
- ["getDay"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getDay", GetDay, 0), true, false, true),
|
|
|
- ["getUTCDay"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCDay", GetUTCDay, 0), true, false, true),
|
|
|
- ["getHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getHours", GetHours, 0), true, false, true),
|
|
|
- ["getUTCHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCHours", GetUTCHours, 0), true, false, true),
|
|
|
- ["getMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getMinutes", GetMinutes, 0), true, false, true),
|
|
|
- ["getUTCMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCMInutes", GetUTCMinutes, 0), true, false, true),
|
|
|
- ["getSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getSeconds", GetSeconds, 0), true, false, true),
|
|
|
- ["getUTCSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCSeconds", GetUTCSeconds, 0), true, false, true),
|
|
|
- ["getMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getMilliseconds", GetMilliseconds, 0), true, false, true),
|
|
|
- ["getUTCMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCMilliseconds", GetUTCMilliseconds, 0), true, false, true),
|
|
|
- ["getTimezoneOffset"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getTimezoneOffset", GetTimezoneOffset, 0), true, false, true),
|
|
|
- ["setTime"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setTime", SetTime, 1), true, false, true),
|
|
|
- ["setMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setMilliseconds", SetMilliseconds, 1), true, false, true),
|
|
|
- ["setUTCMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCMilliseconds", SetUTCMilliseconds, 1), true, false, true),
|
|
|
- ["setSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setSeconds", SetSeconds, 2), true, false, true),
|
|
|
- ["setUTCSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCSeconds", SetUTCSeconds, 2), true, false, true),
|
|
|
- ["setMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setMinutes", SetMinutes, 3), true, false, true),
|
|
|
- ["setUTCMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCMinutes", SetUTCMinutes, 3), true, false, true),
|
|
|
- ["setHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setHours", SetHours, 4), true, false, true),
|
|
|
- ["setUTCHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCHours", SetUTCHours, 4), true, false, true),
|
|
|
- ["setDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setDate", SetDate, 1), true, false, true),
|
|
|
- ["setUTCDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCDate", SetUTCDate, 1), true, false, true),
|
|
|
- ["setMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setMonth", SetMonth, 2), true, false, true),
|
|
|
- ["setUTCMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCMonth", SetUTCMonth, 2), true, false, true),
|
|
|
- ["setFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setFullYear", SetFullYear, 3), true, false, true),
|
|
|
- ["setYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setYear", SetYear, 1), true, false, true),
|
|
|
- ["setUTCFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCFullYear ", SetUTCFullYear, 3), true, false, true),
|
|
|
- ["toUTCString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toUTCString", ToUtcString, 0), true, false, true),
|
|
|
- ["toISOString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toISOString", ToISOString, 0), true, false, true),
|
|
|
- ["toJSON"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toJSON", ToJSON, 1), true, false, true)
|
|
|
+ ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toDateString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toDateString", ToDateString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toTimeString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toTimeString", ToTimeString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toLocaleString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toLocaleDateString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleDateString", ToLocaleDateString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toLocaleTimeString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toLocaleTimeString", ToLocaleTimeString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["valueOf"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "valueOf", ValueOf, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getTime"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getTime", GetTime, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getFullYear", GetFullYear, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getYear", GetYear, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCFullYear", GetUTCFullYear, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getMonth", GetMonth, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCMonth", GetUTCMonth, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getDate", GetDate, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCDate", GetUTCDate, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getDay"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getDay", GetDay, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCDay"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCDay", GetUTCDay, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getHours", GetHours, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCHours", GetUTCHours, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getMinutes", GetMinutes, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCMinutes", GetUTCMinutes, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getSeconds", GetSeconds, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCSeconds", GetUTCSeconds, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getMilliseconds", GetMilliseconds, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getUTCMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getUTCMilliseconds", GetUTCMilliseconds, 0, lengthFlags), propertyFlags),
|
|
|
+ ["getTimezoneOffset"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "getTimezoneOffset", GetTimezoneOffset, 0, lengthFlags), propertyFlags),
|
|
|
+ ["setTime"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setTime", SetTime, 1, lengthFlags), propertyFlags),
|
|
|
+ ["setMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setMilliseconds", SetMilliseconds, 1, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCMilliseconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCMilliseconds", SetUTCMilliseconds, 1, lengthFlags), propertyFlags),
|
|
|
+ ["setSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setSeconds", SetSeconds, 2, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCSeconds"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCSeconds", SetUTCSeconds, 2, lengthFlags), propertyFlags),
|
|
|
+ ["setMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setMinutes", SetMinutes, 3, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCMinutes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCMinutes", SetUTCMinutes, 3, lengthFlags), propertyFlags),
|
|
|
+ ["setHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setHours", SetHours, 4, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCHours"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCHours", SetUTCHours, 4, lengthFlags), propertyFlags),
|
|
|
+ ["setDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setDate", SetDate, 1, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCDate"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCDate", SetUTCDate, 1, lengthFlags), propertyFlags),
|
|
|
+ ["setMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setMonth", SetMonth, 2, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCMonth"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCMonth", SetUTCMonth, 2, lengthFlags), propertyFlags),
|
|
|
+ ["setFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setFullYear", SetFullYear, 3, lengthFlags), propertyFlags),
|
|
|
+ ["setYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setYear", SetYear, 1, lengthFlags), propertyFlags),
|
|
|
+ ["setUTCFullYear"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "setUTCFullYear", SetUTCFullYear, 3, lengthFlags), propertyFlags),
|
|
|
+ ["toUTCString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toUTCString", ToUtcString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toISOString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toISOString", ToISOString, 0, lengthFlags), propertyFlags),
|
|
|
+ ["toJSON"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toJSON", ToJSON, 1, lengthFlags), propertyFlags),
|
|
|
+ [GlobalSymbolRegistry.ToPrimitive] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "[Symbol.toPrimitive]", ToPrimitive, 1, PropertyFlag.Configurable), PropertyFlag.Configurable),
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ private JsValue ToPrimitive(JsValue thisObject, JsValue[] arguments)
|
|
|
+ {
|
|
|
+ if (!(thisObject is ObjectInstance oi))
|
|
|
+ {
|
|
|
+ return ExceptionHelper.ThrowTypeError<JsValue>(_engine);
|
|
|
+ }
|
|
|
+
|
|
|
+ var hint = arguments.At(0);
|
|
|
+ if (!hint.IsString())
|
|
|
+ {
|
|
|
+ return ExceptionHelper.ThrowTypeError<JsValue>(_engine);
|
|
|
+ }
|
|
|
+
|
|
|
+ Types tryFirst = Types.None;
|
|
|
+ if (hint == "default" || hint == "string")
|
|
|
+ {
|
|
|
+ tryFirst = Types.String;
|
|
|
+ }
|
|
|
+ else if (hint == "number")
|
|
|
+ {
|
|
|
+ tryFirst = Types.Number;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return ExceptionHelper.ThrowTypeError<JsValue>(_engine);
|
|
|
+ }
|
|
|
+
|
|
|
+ return TypeConverter.OrdinaryToPrimitive(oi, tryFirst);
|
|
|
+ }
|
|
|
+
|
|
|
private JsValue ValueOf(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
return EnsureDateInstance(thisObj).PrimitiveValue;
|
|
@@ -96,7 +137,8 @@ namespace Jint.Native.Date
|
|
|
/// </summary>
|
|
|
private DateInstance EnsureDateInstance(JsValue thisObj)
|
|
|
{
|
|
|
- return thisObj as DateInstance ?? ExceptionHelper.ThrowTypeError<DateInstance>(_engine, "Invalid Date");
|
|
|
+ return thisObj as DateInstance
|
|
|
+ ?? ExceptionHelper.ThrowTypeError<DateInstance>(_engine, "this is not a Date object");
|
|
|
}
|
|
|
|
|
|
public JsValue ToString(JsValue thisObj, JsValue[] arg2)
|
|
@@ -106,7 +148,8 @@ namespace Jint.Native.Date
|
|
|
if (double.IsNaN(dateInstance.PrimitiveValue))
|
|
|
return "Invalid Date";
|
|
|
|
|
|
- return ToLocalTime(dateInstance.ToDateTime()).ToString("ddd MMM dd yyyy HH:mm:ss 'GMT'K", CultureInfo.InvariantCulture);
|
|
|
+ var t = ToLocalTime(dateInstance.ToDateTime());
|
|
|
+ return t.ToString("ddd MMM dd yyyy HH:mm:ss ", CultureInfo.InvariantCulture) + TimeZoneString(t);
|
|
|
}
|
|
|
|
|
|
private JsValue ToDateString(JsValue thisObj, JsValue[] arguments)
|
|
@@ -126,7 +169,16 @@ namespace Jint.Native.Date
|
|
|
if (double.IsNaN(dateInstance.PrimitiveValue))
|
|
|
return "Invalid Date";
|
|
|
|
|
|
- return ToLocalTime(dateInstance.ToDateTime()).ToString("HH:mm:ss 'GMT'K", CultureInfo.InvariantCulture);
|
|
|
+ var t = ToLocalTime(dateInstance.ToDateTime());
|
|
|
+
|
|
|
+ var timeString = t.ToString("HH:mm:ss ", CultureInfo.InvariantCulture);
|
|
|
+ var timeZoneString = TimeZoneString(t);
|
|
|
+ return timeString + timeZoneString;
|
|
|
+ }
|
|
|
+
|
|
|
+ private static string TimeZoneString(DateTimeOffset t)
|
|
|
+ {
|
|
|
+ return t.ToString("'GMT'K", CultureInfo.InvariantCulture).Replace(":", "");
|
|
|
}
|
|
|
|
|
|
private JsValue ToLocaleString(JsValue thisObj, JsValue[] arguments)
|
|
@@ -161,209 +213,191 @@ namespace Jint.Native.Date
|
|
|
|
|
|
private JsValue GetTime(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
- if (double.IsNaN(EnsureDateInstance(thisObj).PrimitiveValue))
|
|
|
+ var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
- return EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ return t;
|
|
|
}
|
|
|
|
|
|
private JsValue GetFullYear(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return YearFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetYear(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return YearFromTime(LocalTime(t)) - 1900;
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCFullYear(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return YearFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetMonth(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return MonthFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCMonth(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return MonthFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetDate(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return DateFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCDate(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return DateFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetDay(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return WeekDay(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCDay(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return WeekDay(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetHours(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return HourFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCHours(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return HourFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetMinutes(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return MinFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCMinutes(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return MinFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetSeconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
- var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return SecFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCSeconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return SecFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetMilliseconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return MsFromTime(LocalTime(t));
|
|
|
}
|
|
|
|
|
|
private JsValue GetUTCMilliseconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return MsFromTime(t);
|
|
|
}
|
|
|
|
|
|
private JsValue GetTimezoneOffset(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
- if (double.IsNaN(t))
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
return JsNumber.DoubleNaN;
|
|
|
}
|
|
|
-
|
|
|
return (int) (t - LocalTime(t))/MsPerMinute;
|
|
|
}
|
|
|
|
|
@@ -375,6 +409,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetMilliseconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), TypeConverter.ToNumber(arguments.At(0)));
|
|
|
var u = TimeClip(Utc(MakeDate(Day(t), time)));
|
|
|
thisObj.As<DateInstance>().PrimitiveValue = u;
|
|
@@ -384,6 +422,12 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetUTCMilliseconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return double.NaN;
|
|
|
+ }
|
|
|
+
|
|
|
var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), TypeConverter.ToNumber(arguments.At(0)));
|
|
|
var u = TimeClip(MakeDate(Day(t), time));
|
|
|
thisObj.As<DateInstance>().PrimitiveValue = u;
|
|
@@ -393,6 +437,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetSeconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var s = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var milli = arguments.Length <= 1 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
|
|
@@ -404,6 +452,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetUTCSeconds(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var s = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var milli = arguments.Length <= 1 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
|
|
@@ -415,6 +467,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetMinutes(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var m = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var s = arguments.Length <= 1 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var milli = arguments.Length <= 2 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
|
|
@@ -427,6 +483,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetUTCMinutes(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var m = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var s = arguments.Length <= 1 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var milli = arguments.Length <= 2 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
|
|
@@ -439,6 +499,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetHours(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var h = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var m = arguments.Length <= 1 ? MinFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var s = arguments.Length <= 2 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
|
|
@@ -452,6 +516,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetUTCHours(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var h = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var m = arguments.Length <= 1 ? MinFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var s = arguments.Length <= 2 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
|
|
@@ -465,8 +533,13 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetDate(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var dt = TypeConverter.ToNumber(arguments.At(0));
|
|
|
- var newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
|
|
|
+ var (year, month, __) = YearMonthDayFromTime(t);
|
|
|
+ var newDate = MakeDate(MakeDay(year, month, dt), TimeWithinDay(t));
|
|
|
var u = TimeClip(Utc(newDate));
|
|
|
thisObj.As<DateInstance>().PrimitiveValue = u;
|
|
|
return u;
|
|
@@ -474,7 +547,11 @@ namespace Jint.Native.Date
|
|
|
|
|
|
private JsValue SetUTCDate(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
- var t = (long) EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var dt = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
|
|
|
var u = TimeClip(newDate);
|
|
@@ -485,6 +562,10 @@ namespace Jint.Native.Date
|
|
|
private JsValue SetMonth(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var m = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var dt = arguments.Length <= 1 ? DateFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
|
|
@@ -495,7 +576,11 @@ namespace Jint.Native.Date
|
|
|
|
|
|
private JsValue SetUTCMonth(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
- var t = (long) EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ var t = EnsureDateInstance(thisObj).PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return JsNumber.DoubleNaN;
|
|
|
+ }
|
|
|
var m = TypeConverter.ToNumber(arguments.At(0));
|
|
|
var dt = arguments.Length <= 1 ? DateFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
|
|
|
var newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
|
|
@@ -555,18 +640,30 @@ namespace Jint.Native.Date
|
|
|
|
|
|
private JsValue ToUtcString(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
- return (thisObj as DateInstance?? ExceptionHelper.ThrowTypeError<DateInstance>(_engine))
|
|
|
- .ToDateTime().ToUniversalTime().ToString("ddd MMM dd yyyy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture);
|
|
|
+ var thisTime = EnsureDateInstance(thisObj);
|
|
|
+ if (!IsFinite(thisTime.PrimitiveValue))
|
|
|
+ {
|
|
|
+ return "Invalid Date";
|
|
|
+ }
|
|
|
+ return thisTime.ToDateTime().ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture);
|
|
|
}
|
|
|
|
|
|
private JsValue ToISOString(JsValue thisObj, JsValue[] arguments)
|
|
|
{
|
|
|
- var t = (thisObj as DateInstance ?? ExceptionHelper.ThrowTypeError<DateInstance>(_engine)).PrimitiveValue;
|
|
|
-
|
|
|
- if (double.IsInfinity(t) || double.IsNaN(t))
|
|
|
+ var thisTime = EnsureDateInstance(thisObj);
|
|
|
+ var t = thisTime.PrimitiveValue;
|
|
|
+ if (!IsFinite(t))
|
|
|
{
|
|
|
ExceptionHelper.ThrowRangeError(_engine);
|
|
|
}
|
|
|
+
|
|
|
+ if (thisTime.DateTimeRangeValid)
|
|
|
+ {
|
|
|
+ // shortcut
|
|
|
+ var dt = thisTime.ToDateTime();
|
|
|
+ return $"{dt.Year:0000}-{dt.Month:00}-{dt.Day:00}T{dt.Hour:00}:{dt.Minute:00}:{dt.Second:00}.{dt.Millisecond:000}Z";
|
|
|
+ }
|
|
|
+
|
|
|
var h = HourFromTime(t);
|
|
|
var m = MinFromTime(t);
|
|
|
var s = SecFromTime(t);
|
|
@@ -575,7 +672,9 @@ namespace Jint.Native.Date
|
|
|
if (m < 0) { m += MinutesPerHour; }
|
|
|
if (s < 0) { s += SecondsPerMinute; }
|
|
|
if (ms < 0) { ms += MsPerSecond; }
|
|
|
- return $"{YearFromTime(t):0000}-{MonthFromTime(t) + 1:00}-{DateFromTime(t):00}T{h:00}:{m:00}:{s:00}.{ms:000}Z";
|
|
|
+
|
|
|
+ var (year, month, day) = YearMonthDayFromTime(t);
|
|
|
+ return $"{year:0000}-{month:00}-{day:00}T{h:00}:{m:00}:{s:00}.{ms:000}Z";
|
|
|
}
|
|
|
|
|
|
private JsValue ToJSON(JsValue thisObj, JsValue[] arguments)
|
|
@@ -615,7 +714,7 @@ namespace Jint.Native.Date
|
|
|
/// <summary>
|
|
|
/// 15.9.1.2
|
|
|
/// </summary>
|
|
|
- public static long TimeWithinDay(long t)
|
|
|
+ public static double TimeWithinDay(double t)
|
|
|
{
|
|
|
var result = t % MsPerDay;
|
|
|
|
|
@@ -632,22 +731,22 @@ namespace Jint.Native.Date
|
|
|
/// </summary>
|
|
|
public static int DaysInYear(double y)
|
|
|
{
|
|
|
- if (!(y%4).Equals(0))
|
|
|
+ if (y%4 != 0)
|
|
|
{
|
|
|
return 365;
|
|
|
}
|
|
|
|
|
|
- if ((y%4).Equals(0) && !(y%100).Equals(0))
|
|
|
+ if (y%4 == 0 && y%100 != 0)
|
|
|
{
|
|
|
return 366;
|
|
|
}
|
|
|
|
|
|
- if ((y%100).Equals(0) && !(y%400).Equals(0))
|
|
|
+ if (y%100 == 0 && y%400 != 0)
|
|
|
{
|
|
|
return 365;
|
|
|
}
|
|
|
|
|
|
- if ((y%400).Equals(0))
|
|
|
+ if (y%400 == 0)
|
|
|
{
|
|
|
return 366;
|
|
|
}
|
|
@@ -679,39 +778,7 @@ namespace Jint.Native.Date
|
|
|
/// </summary>
|
|
|
public static int YearFromTime(double t)
|
|
|
{
|
|
|
- var sign = (t < 0) ? -1 : 1;
|
|
|
- var year = (sign < 0) ? 1969 : 1970;
|
|
|
- for (var timeToTimeZero = (long) t; ;)
|
|
|
- {
|
|
|
- // Subtract the current year's time from the time that's left.
|
|
|
- var timeInYear = DaysInYear(year) * MsPerDay;
|
|
|
- timeToTimeZero -= sign * timeInYear;
|
|
|
-
|
|
|
- // If there's less than the current year's worth of time left, then break.
|
|
|
- if (sign < 0)
|
|
|
- {
|
|
|
- if (sign * timeToTimeZero <= 0)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- year += sign;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (sign * timeToTimeZero < 0)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- year += sign;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
+ var (year, _, _) = YearMonthDayFromTime(t);
|
|
|
return year;
|
|
|
}
|
|
|
|
|
@@ -891,24 +958,29 @@ namespace Jint.Native.Date
|
|
|
|
|
|
public long LocalTza => (long) Engine.Options._LocalTimeZone.BaseUtcOffset.TotalMilliseconds;
|
|
|
|
|
|
- public long DaylightSavingTa(double t)
|
|
|
+ public double DaylightSavingTa(double t)
|
|
|
{
|
|
|
- var timeInYear = t - TimeFromYear(YearFromTime(t));
|
|
|
+ if (double.IsNaN(t))
|
|
|
+ {
|
|
|
+ return t;
|
|
|
+ }
|
|
|
+
|
|
|
+ var year = YearFromTime(t);
|
|
|
+ var timeInYear = t - TimeFromYear(year);
|
|
|
|
|
|
if (double.IsInfinity(timeInYear) || double.IsNaN(timeInYear))
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
- var year = YearFromTime(t);
|
|
|
- if (year < 9999 && year > -9999)
|
|
|
+ if (year < 9999 && year > -9999 && year != 0)
|
|
|
{
|
|
|
// in DateTimeOffset range so we can use it
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
// use similar leap-ed year
|
|
|
- var isLeapYear = InLeapYear(t) == 1;
|
|
|
+ var isLeapYear = InLeapYear((long) t) == 1;
|
|
|
year = isLeapYear ? 2000 : 1999;
|
|
|
}
|
|
|
|
|
@@ -930,9 +1002,14 @@ namespace Jint.Native.Date
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- public long LocalTime(double t)
|
|
|
+ public double LocalTime(double t)
|
|
|
{
|
|
|
- return (long) (t + LocalTza + DaylightSavingTa(t));
|
|
|
+ if (!IsFinite(t))
|
|
|
+ {
|
|
|
+ return double.NaN;
|
|
|
+ }
|
|
|
+
|
|
|
+ return (long) (t + LocalTza + DaylightSavingTa((long) t));
|
|
|
}
|
|
|
|
|
|
public double Utc(double t)
|
|
@@ -988,58 +1065,6 @@ namespace Jint.Native.Date
|
|
|
return (int) milli;
|
|
|
}
|
|
|
|
|
|
- public static int DayFromMonth(int year, int month)
|
|
|
- {
|
|
|
- int day = month * 30;
|
|
|
-
|
|
|
- if (month >= 7)
|
|
|
- {
|
|
|
- day += month/2 - 1;
|
|
|
- }
|
|
|
- else if (month >= 2)
|
|
|
- {
|
|
|
- day += (month - 1)/2 - 1;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- day += month;
|
|
|
- }
|
|
|
-
|
|
|
- if (month >= 2 && InLeapYear(year) == 1)
|
|
|
- {
|
|
|
- day++;
|
|
|
- }
|
|
|
-
|
|
|
- return day;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- public static int DaysInMonth(int month, int leap)
|
|
|
- {
|
|
|
- month = month%12;
|
|
|
-
|
|
|
- switch ((long) month)
|
|
|
- {
|
|
|
- case 0:
|
|
|
- case 2:
|
|
|
- case 4:
|
|
|
- case 6:
|
|
|
- case 7:
|
|
|
- case 9:
|
|
|
- case 11:
|
|
|
- return 31;
|
|
|
- case 3:
|
|
|
- case 5:
|
|
|
- case 8:
|
|
|
- case 10:
|
|
|
- return 30;
|
|
|
- case 1:
|
|
|
- return 28 + leap;
|
|
|
- default:
|
|
|
- return ExceptionHelper.ThrowArgumentOutOfRangeException<int>(nameof(month), "invalid month");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
public static double MakeTime(double hour, double min, double sec, double ms)
|
|
|
{
|
|
|
if (!AreFinite(hour, min, sec, ms))
|
|
@@ -1047,10 +1072,10 @@ namespace Jint.Native.Date
|
|
|
return double.NaN;
|
|
|
}
|
|
|
|
|
|
- var h = (long) hour;
|
|
|
- var m = (long) min;
|
|
|
- var s = (long) sec;
|
|
|
- var milli = (long) ms;
|
|
|
+ var h = TypeConverter.ToInteger(hour);
|
|
|
+ var m = TypeConverter.ToInteger(min);
|
|
|
+ var s = TypeConverter.ToInteger(sec);
|
|
|
+ var milli = TypeConverter.ToInteger(ms);
|
|
|
var t = h*MsPerHour + m*MsPerMinute + s*MsPerSecond + milli;
|
|
|
|
|
|
return t;
|
|
@@ -1058,47 +1083,44 @@ namespace Jint.Native.Date
|
|
|
|
|
|
public static double MakeDay(double year, double month, double date)
|
|
|
{
|
|
|
- if (!AreFinite(year, month, date))
|
|
|
+ if ((year < MinYear || year > MaxYear) || month < MinMonth || month > MaxMonth || !AreFinite(year, month, date))
|
|
|
{
|
|
|
return double.NaN;
|
|
|
}
|
|
|
|
|
|
- year = TypeConverter.ToInteger(year);
|
|
|
- month = TypeConverter.ToInteger(month);
|
|
|
- date = TypeConverter.ToInteger(date);
|
|
|
-
|
|
|
- if (month < 0)
|
|
|
- {
|
|
|
- var m = (long) month;
|
|
|
- year += (m - 11) / 12;
|
|
|
- month = (12 + m % 12) % 12;
|
|
|
- }
|
|
|
-
|
|
|
- var sign = (year < 1970) ? -1 : 1;
|
|
|
- long t = (year < 1970) ? 1 : 0;
|
|
|
- int y;
|
|
|
-
|
|
|
- if (sign == -1)
|
|
|
- {
|
|
|
- for (y = 1969; y >= year; y += sign)
|
|
|
- {
|
|
|
- t += sign * DaysInYear(y) * MsPerDay;
|
|
|
- }
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- for (y = 1970; y < year; y += sign)
|
|
|
- {
|
|
|
- t += sign * DaysInYear(y) * MsPerDay;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- for (var m = 0; m < month; m++)
|
|
|
- {
|
|
|
- t += DaysInMonth(m, InLeapYear(t)) * MsPerDay;
|
|
|
- }
|
|
|
-
|
|
|
- return Day(t) + date - 1;
|
|
|
+ var y = (long) TypeConverter.ToInteger(year);
|
|
|
+ var m = (long) TypeConverter.ToInteger(month);
|
|
|
+ y += m / 12;
|
|
|
+ m %= 12;
|
|
|
+ if (m < 0) {
|
|
|
+ m += 12;
|
|
|
+ y -= 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // kYearDelta is an arbitrary number such that:
|
|
|
+ // a) kYearDelta = -1 (mod 400)
|
|
|
+ // b) year + kYearDelta > 0 for years in the range defined by
|
|
|
+ // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
|
|
|
+ // Jan 1 1970. This is required so that we don't run into integer
|
|
|
+ // division of negative numbers.
|
|
|
+ // c) there shouldn't be an overflow for 32-bit integers in the following
|
|
|
+ // operations.
|
|
|
+ const int kYearDelta = 399999;
|
|
|
+ const int kBaseDay =
|
|
|
+ 365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 -
|
|
|
+ (1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400;
|
|
|
+
|
|
|
+ long dayFromYear = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 -
|
|
|
+ (y + kYearDelta) / 100 + (y + kYearDelta) / 400 - kBaseDay;
|
|
|
+
|
|
|
+ if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) {
|
|
|
+ var dayFromMonth = new [] {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
|
|
|
+ dayFromYear += dayFromMonth[m];
|
|
|
+ } else {
|
|
|
+ var dayFromMonthLeapYear = new [] {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
|
|
|
+ dayFromYear += dayFromMonthLeapYear[m];
|
|
|
+ }
|
|
|
+ return dayFromYear - 1 + TypeConverter.ToInteger(date);
|
|
|
}
|
|
|
|
|
|
public static double MakeDate(double day, double time)
|
|
@@ -1113,7 +1135,7 @@ namespace Jint.Native.Date
|
|
|
|
|
|
public static double TimeClip(double time)
|
|
|
{
|
|
|
- if (!AreFinite(time))
|
|
|
+ if (!IsFinite(time))
|
|
|
{
|
|
|
return double.NaN;
|
|
|
}
|
|
@@ -1127,24 +1149,124 @@ namespace Jint.Native.Date
|
|
|
}
|
|
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
|
- private static bool AreFinite(double value)
|
|
|
+ private static bool IsFinite(double value)
|
|
|
{
|
|
|
return !double.IsNaN(value) && !double.IsInfinity(value);
|
|
|
}
|
|
|
|
|
|
private static bool AreFinite(double value1, double value2)
|
|
|
{
|
|
|
- return AreFinite(value1) && AreFinite(value2);
|
|
|
+ return IsFinite(value1) && IsFinite(value2);
|
|
|
}
|
|
|
|
|
|
private static bool AreFinite(double value1, double value2, double value3)
|
|
|
{
|
|
|
- return AreFinite(value1) && AreFinite(value2) && AreFinite(value3);
|
|
|
+ return IsFinite(value1) && IsFinite(value2) && IsFinite(value3);
|
|
|
}
|
|
|
|
|
|
private static bool AreFinite(double value1, double value2, double value3, double value4)
|
|
|
{
|
|
|
- return AreFinite(value1) && AreFinite(value2) && AreFinite(value3) && AreFinite(value4);
|
|
|
+ return IsFinite(value1) && IsFinite(value2) && IsFinite(value3) && IsFinite(value4);
|
|
|
+ }
|
|
|
+ private readonly struct Date
|
|
|
+ {
|
|
|
+ public Date(int year, int month, int day)
|
|
|
+ {
|
|
|
+ Year = year;
|
|
|
+ Month = month;
|
|
|
+ Day = day;
|
|
|
+ }
|
|
|
+
|
|
|
+ public readonly int Year;
|
|
|
+ public readonly int Month;
|
|
|
+ public readonly int Day;
|
|
|
+
|
|
|
+ public void Deconstruct(out int year, out int month, out int day)
|
|
|
+ {
|
|
|
+ year = Year;
|
|
|
+ month = Month;
|
|
|
+ day = Day;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static readonly int[] kDaysInMonths = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
|
|
+
|
|
|
+ private static Date YearMonthDayFromTime(double t) => YearMonthDayFromDays((long) (t / 1000 / 60 / 60 / 24));
|
|
|
+
|
|
|
+ private static Date YearMonthDayFromDays(long days)
|
|
|
+ {
|
|
|
+ const int kDaysIn4Years = 4 * 365 + 1;
|
|
|
+ const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
|
|
|
+ const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
|
|
|
+ const int kDays1970to2000 = 30 * 365 + 7;
|
|
|
+ const int kDaysOffset =
|
|
|
+ 1000 * kDaysIn400Years + 5 * kDaysIn400Years - kDays1970to2000;
|
|
|
+ const int kYearsOffset = 400000;
|
|
|
+
|
|
|
+
|
|
|
+ days += kDaysOffset;
|
|
|
+ var year = 400 * (days / kDaysIn400Years) - kYearsOffset;
|
|
|
+ days %= kDaysIn400Years;
|
|
|
+
|
|
|
+ days--;
|
|
|
+ var yd1 = days / kDaysIn100Years;
|
|
|
+ days %= kDaysIn100Years;
|
|
|
+ year += 100 * yd1;
|
|
|
+
|
|
|
+ days++;
|
|
|
+ var yd2 = days / kDaysIn4Years;
|
|
|
+ days %= kDaysIn4Years;
|
|
|
+ year += 4 * yd2;
|
|
|
+
|
|
|
+ days--;
|
|
|
+ var yd3 = days / 365;
|
|
|
+ days %= 365;
|
|
|
+ year += yd3;
|
|
|
+
|
|
|
+ var is_leap = (yd1 == 0 || yd2 != 0) && yd3 == 0;
|
|
|
+
|
|
|
+ days += is_leap ? 1 : 0;
|
|
|
+ var month = 0;
|
|
|
+ var day = 0;
|
|
|
+
|
|
|
+ // Check if the date is after February.
|
|
|
+ if (days >= 31 + 28 + (is_leap ? 1 : 0))
|
|
|
+ {
|
|
|
+ days -= 31 + 28 + (is_leap ? 1 : 0);
|
|
|
+ // Find the date starting from March.
|
|
|
+ for (int i = 2; i < 12; i++)
|
|
|
+ {
|
|
|
+ if (days < kDaysInMonths[i])
|
|
|
+ {
|
|
|
+ month = i;
|
|
|
+ day = (int) (days + 1);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ days -= kDaysInMonths[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Check January and February.
|
|
|
+ if (days < 31)
|
|
|
+ {
|
|
|
+ month = 0;
|
|
|
+ day = (int) (days + 1);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ month = 1;
|
|
|
+ day = (int) (days - 31 + 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return new Date((int) year, month, day);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override string ToString()
|
|
|
+ {
|
|
|
+ return "Date.prototype";
|
|
|
}
|
|
|
}
|
|
|
}
|