DatePrototype.cs 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123
  1. using System;
  2. using System.Globalization;
  3. using Jint.Runtime;
  4. using Jint.Runtime.Descriptors;
  5. using Jint.Runtime.Interop;
  6. namespace Jint.Native.Date
  7. {
  8. /// <summary>
  9. /// http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5
  10. /// </summary>
  11. public sealed class DatePrototype : DateInstance
  12. {
  13. private DatePrototype(Engine engine)
  14. : base(engine)
  15. {
  16. }
  17. public static DatePrototype CreatePrototypeObject(Engine engine, DateConstructor dateConstructor)
  18. {
  19. var obj = new DatePrototype(engine)
  20. {
  21. Prototype = engine.Object.PrototypeObject,
  22. Extensible = true,
  23. PrimitiveValue = double.NaN
  24. };
  25. obj.SetOwnProperty("constructor", new PropertyDescriptor(dateConstructor, PropertyFlag.NonEnumerable));
  26. return obj;
  27. }
  28. public void Configure()
  29. {
  30. FastAddProperty("toString", new ClrFunctionInstance(Engine, "toString", ToString, 0), true, false, true);
  31. FastAddProperty("toDateString", new ClrFunctionInstance(Engine, "toDateString", ToDateString, 0), true, false, true);
  32. FastAddProperty("toTimeString", new ClrFunctionInstance(Engine, "toTimeString", ToTimeString, 0), true, false, true);
  33. FastAddProperty("toLocaleString", new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString, 0), true, false, true);
  34. FastAddProperty("toLocaleDateString", new ClrFunctionInstance(Engine, "toLocaleDateString", ToLocaleDateString, 0), true, false, true);
  35. FastAddProperty("toLocaleTimeString", new ClrFunctionInstance(Engine, "toLocaleTimeString", ToLocaleTimeString, 0), true, false, true);
  36. FastAddProperty("valueOf", new ClrFunctionInstance(Engine, "valueOf", ValueOf, 0), true, false, true);
  37. FastAddProperty("getTime", new ClrFunctionInstance(Engine, "getTime", GetTime, 0), true, false, true);
  38. FastAddProperty("getFullYear", new ClrFunctionInstance(Engine, "getFullYear", GetFullYear, 0), true, false, true);
  39. FastAddProperty("getYear", new ClrFunctionInstance(Engine, "getYear", GetYear, 0), true, false, true);
  40. FastAddProperty("getUTCFullYear", new ClrFunctionInstance(Engine, "getUTCFullYear", GetUTCFullYear, 0), true, false, true);
  41. FastAddProperty("getMonth", new ClrFunctionInstance(Engine, "getMonth", GetMonth, 0), true, false, true);
  42. FastAddProperty("getUTCMonth", new ClrFunctionInstance(Engine, "getUTCMonth", GetUTCMonth, 0), true, false, true);
  43. FastAddProperty("getDate", new ClrFunctionInstance(Engine, "getDate", GetDate, 0), true, false, true);
  44. FastAddProperty("getUTCDate", new ClrFunctionInstance(Engine, "getUTCDate", GetUTCDate, 0), true, false, true);
  45. FastAddProperty("getDay", new ClrFunctionInstance(Engine, "getDay", GetDay, 0), true, false, true);
  46. FastAddProperty("getUTCDay", new ClrFunctionInstance(Engine, "getUTCDay", GetUTCDay, 0), true, false, true);
  47. FastAddProperty("getHours", new ClrFunctionInstance(Engine, "getHours", GetHours, 0), true, false, true);
  48. FastAddProperty("getUTCHours", new ClrFunctionInstance(Engine, "getUTCHours", GetUTCHours, 0), true, false, true);
  49. FastAddProperty("getMinutes", new ClrFunctionInstance(Engine, "getMinutes", GetMinutes, 0), true, false, true);
  50. FastAddProperty("getUTCMinutes", new ClrFunctionInstance(Engine, "getUTCMInutes", GetUTCMinutes, 0), true, false, true);
  51. FastAddProperty("getSeconds", new ClrFunctionInstance(Engine, "getSeconds", GetSeconds, 0), true, false, true);
  52. FastAddProperty("getUTCSeconds", new ClrFunctionInstance(Engine, "getUTCSeconds", GetUTCSeconds, 0), true, false, true);
  53. FastAddProperty("getMilliseconds", new ClrFunctionInstance(Engine, "getMilliseconds", GetMilliseconds, 0), true, false, true);
  54. FastAddProperty("getUTCMilliseconds", new ClrFunctionInstance(Engine, "getUTCMilliseconds", GetUTCMilliseconds, 0), true, false, true);
  55. FastAddProperty("getTimezoneOffset", new ClrFunctionInstance(Engine, "getTimezoneOffset", GetTimezoneOffset, 0), true, false, true);
  56. FastAddProperty("setTime", new ClrFunctionInstance(Engine, "setTime", SetTime, 1), true, false, true);
  57. FastAddProperty("setMilliseconds", new ClrFunctionInstance(Engine, "setMilliseconds", SetMilliseconds, 1), true, false, true);
  58. FastAddProperty("setUTCMilliseconds", new ClrFunctionInstance(Engine, "setUTCMilliseconds", SetUTCMilliseconds, 1), true, false, true);
  59. FastAddProperty("setSeconds", new ClrFunctionInstance(Engine, "setSeconds", SetSeconds, 2), true, false, true);
  60. FastAddProperty("setUTCSeconds", new ClrFunctionInstance(Engine, "setUTCSeconds", SetUTCSeconds, 2), true, false, true);
  61. FastAddProperty("setMinutes", new ClrFunctionInstance(Engine, "setMinutes", SetMinutes, 3), true, false, true);
  62. FastAddProperty("setUTCMinutes", new ClrFunctionInstance(Engine, "setUTCMinutes", SetUTCMinutes, 3), true, false, true);
  63. FastAddProperty("setHours", new ClrFunctionInstance(Engine, "setHours", SetHours, 4), true, false, true);
  64. FastAddProperty("setUTCHours", new ClrFunctionInstance(Engine, "setUTCHours", SetUTCHours, 4), true, false, true);
  65. FastAddProperty("setDate", new ClrFunctionInstance(Engine, "setDate", SetDate, 1), true, false, true);
  66. FastAddProperty("setUTCDate", new ClrFunctionInstance(Engine, "setUTCDate", SetUTCDate, 1), true, false, true);
  67. FastAddProperty("setMonth", new ClrFunctionInstance(Engine, "setMonth", SetMonth, 2), true, false, true);
  68. FastAddProperty("setUTCMonth", new ClrFunctionInstance(Engine, "setUTCMonth", SetUTCMonth, 2), true, false, true);
  69. FastAddProperty("setFullYear", new ClrFunctionInstance(Engine, "setFullYear", SetFullYear, 3), true, false, true);
  70. FastAddProperty("setYear", new ClrFunctionInstance(Engine, "setYear", SetYear, 1), true, false, true);
  71. FastAddProperty("setUTCFullYear", new ClrFunctionInstance(Engine, "setUTCFullYear ", SetUTCFullYear, 3), true, false, true);
  72. FastAddProperty("toUTCString", new ClrFunctionInstance(Engine, "toUTCString", ToUtcString, 0), true, false, true);
  73. FastAddProperty("toISOString", new ClrFunctionInstance(Engine, "toISOString", ToISOString, 0), true, false, true);
  74. FastAddProperty("toJSON", new ClrFunctionInstance(Engine, "toJSON", ToJSON, 1), true, false, true);
  75. }
  76. private JsValue ValueOf(JsValue thisObj, JsValue[] arguments)
  77. {
  78. return EnsureDateInstance(thisObj).PrimitiveValue;
  79. }
  80. /// <summary>
  81. /// Converts a value to a <see cref="DateInstance"/> or throws a TypeError exception.
  82. /// c.f., http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.5
  83. /// </summary>
  84. private DateInstance EnsureDateInstance(JsValue thisObj)
  85. {
  86. return thisObj.TryCast<DateInstance>(value =>
  87. {
  88. ExceptionHelper.ThrowTypeError(_engine, "Invalid Date");
  89. });
  90. }
  91. public JsValue ToString(JsValue thisObj, JsValue[] arg2)
  92. {
  93. return ToLocalTime(EnsureDateInstance(thisObj).ToDateTime()).ToString("ddd MMM dd yyyy HH:mm:ss 'GMT'K", CultureInfo.InvariantCulture);
  94. }
  95. private JsValue ToDateString(JsValue thisObj, JsValue[] arguments)
  96. {
  97. return ToLocalTime(EnsureDateInstance(thisObj).ToDateTime()).ToString("ddd MMM dd yyyy", CultureInfo.InvariantCulture);
  98. }
  99. private JsValue ToTimeString(JsValue thisObj, JsValue[] arguments)
  100. {
  101. return ToLocalTime(EnsureDateInstance(thisObj).ToDateTime()).ToString("HH:mm:ss 'GMT'K", CultureInfo.InvariantCulture);
  102. }
  103. private JsValue ToLocaleString(JsValue thisObj, JsValue[] arguments)
  104. {
  105. return ToLocalTime(EnsureDateInstance(thisObj).ToDateTime()).ToString("F", Engine.Options._Culture);
  106. }
  107. private JsValue ToLocaleDateString(JsValue thisObj, JsValue[] arguments)
  108. {
  109. return ToLocalTime(EnsureDateInstance(thisObj).ToDateTime()).ToString("D", Engine.Options._Culture);
  110. }
  111. private JsValue ToLocaleTimeString(JsValue thisObj, JsValue[] arguments)
  112. {
  113. return ToLocalTime(EnsureDateInstance(thisObj).ToDateTime()).ToString("T", Engine.Options._Culture);
  114. }
  115. private JsValue GetTime(JsValue thisObj, JsValue[] arguments)
  116. {
  117. if (double.IsNaN(EnsureDateInstance(thisObj).PrimitiveValue))
  118. {
  119. return JsNumber.DoubleNaN;
  120. }
  121. return EnsureDateInstance(thisObj).PrimitiveValue;
  122. }
  123. private JsValue GetFullYear(JsValue thisObj, JsValue[] arguments)
  124. {
  125. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  126. if (double.IsNaN(t))
  127. {
  128. return JsNumber.DoubleNaN;
  129. }
  130. return YearFromTime(LocalTime(t));
  131. }
  132. private JsValue GetYear(JsValue thisObj, JsValue[] arguments)
  133. {
  134. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  135. if (double.IsNaN(t))
  136. {
  137. return JsNumber.DoubleNaN;
  138. }
  139. return YearFromTime(LocalTime(t)) - 1900;
  140. }
  141. private JsValue GetUTCFullYear(JsValue thisObj, JsValue[] arguments)
  142. {
  143. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  144. if (double.IsNaN(t))
  145. {
  146. return JsNumber.DoubleNaN;
  147. }
  148. return YearFromTime(t);
  149. }
  150. private JsValue GetMonth(JsValue thisObj, JsValue[] arguments)
  151. {
  152. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  153. if (double.IsNaN(t))
  154. {
  155. return JsNumber.DoubleNaN;
  156. }
  157. return MonthFromTime(LocalTime(t));
  158. }
  159. private JsValue GetUTCMonth(JsValue thisObj, JsValue[] arguments)
  160. {
  161. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  162. if (double.IsNaN(t))
  163. {
  164. return JsNumber.DoubleNaN;
  165. }
  166. return MonthFromTime(t);
  167. }
  168. private JsValue GetDate(JsValue thisObj, JsValue[] arguments)
  169. {
  170. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  171. if (double.IsNaN(t))
  172. {
  173. return JsNumber.DoubleNaN;
  174. }
  175. return DateFromTime(LocalTime(t));
  176. }
  177. private JsValue GetUTCDate(JsValue thisObj, JsValue[] arguments)
  178. {
  179. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  180. if (double.IsNaN(t))
  181. {
  182. return JsNumber.DoubleNaN;
  183. }
  184. return DateFromTime(t);
  185. }
  186. private JsValue GetDay(JsValue thisObj, JsValue[] arguments)
  187. {
  188. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  189. if (double.IsNaN(t))
  190. {
  191. return JsNumber.DoubleNaN;
  192. }
  193. return WeekDay(LocalTime(t));
  194. }
  195. private JsValue GetUTCDay(JsValue thisObj, JsValue[] arguments)
  196. {
  197. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  198. if (double.IsNaN(t))
  199. {
  200. return JsNumber.DoubleNaN;
  201. }
  202. return WeekDay(t);
  203. }
  204. private JsValue GetHours(JsValue thisObj, JsValue[] arguments)
  205. {
  206. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  207. if (double.IsNaN(t))
  208. {
  209. return JsNumber.DoubleNaN;
  210. }
  211. return HourFromTime(LocalTime(t));
  212. }
  213. private JsValue GetUTCHours(JsValue thisObj, JsValue[] arguments)
  214. {
  215. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  216. if (double.IsNaN(t))
  217. {
  218. return JsNumber.DoubleNaN;
  219. }
  220. return HourFromTime(t);
  221. }
  222. private JsValue GetMinutes(JsValue thisObj, JsValue[] arguments)
  223. {
  224. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  225. if (double.IsNaN(t))
  226. {
  227. return JsNumber.DoubleNaN;
  228. }
  229. return MinFromTime(LocalTime(t));
  230. }
  231. private JsValue GetUTCMinutes(JsValue thisObj, JsValue[] arguments)
  232. {
  233. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  234. if (double.IsNaN(t))
  235. {
  236. return JsNumber.DoubleNaN;
  237. }
  238. return MinFromTime(t);
  239. }
  240. private JsValue GetSeconds(JsValue thisObj, JsValue[] arguments)
  241. {
  242. var t = thisObj.TryCast<DateInstance>().PrimitiveValue;
  243. if (double.IsNaN(t))
  244. {
  245. return JsNumber.DoubleNaN;
  246. }
  247. return SecFromTime(LocalTime(t));
  248. }
  249. private JsValue GetUTCSeconds(JsValue thisObj, JsValue[] arguments)
  250. {
  251. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  252. if (double.IsNaN(t))
  253. {
  254. return JsNumber.DoubleNaN;
  255. }
  256. return SecFromTime(t);
  257. }
  258. private JsValue GetMilliseconds(JsValue thisObj, JsValue[] arguments)
  259. {
  260. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  261. if (double.IsNaN(t))
  262. {
  263. return JsNumber.DoubleNaN;
  264. }
  265. return MsFromTime(LocalTime(t));
  266. }
  267. private JsValue GetUTCMilliseconds(JsValue thisObj, JsValue[] arguments)
  268. {
  269. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  270. if (double.IsNaN(t))
  271. {
  272. return JsNumber.DoubleNaN;
  273. }
  274. return MsFromTime(t);
  275. }
  276. private JsValue GetTimezoneOffset(JsValue thisObj, JsValue[] arguments)
  277. {
  278. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  279. if (double.IsNaN(t))
  280. {
  281. return JsNumber.DoubleNaN;
  282. }
  283. return (t - LocalTime(t))/MsPerMinute;
  284. }
  285. private JsValue SetTime(JsValue thisObj, JsValue[] arguments)
  286. {
  287. return EnsureDateInstance(thisObj).PrimitiveValue = TimeClip(TypeConverter.ToNumber(arguments.At(0)));
  288. }
  289. private JsValue SetMilliseconds(JsValue thisObj, JsValue[] arguments)
  290. {
  291. var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
  292. var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), TypeConverter.ToNumber(arguments.At(0)));
  293. var u = TimeClip(Utc(MakeDate(Day(t), time)));
  294. thisObj.As<DateInstance>().PrimitiveValue = u;
  295. return u;
  296. }
  297. private JsValue SetUTCMilliseconds(JsValue thisObj, JsValue[] arguments)
  298. {
  299. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  300. var time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), TypeConverter.ToNumber(arguments.At(0)));
  301. var u = TimeClip(MakeDate(Day(t), time));
  302. thisObj.As<DateInstance>().PrimitiveValue = u;
  303. return u;
  304. }
  305. private JsValue SetSeconds(JsValue thisObj, JsValue[] arguments)
  306. {
  307. var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
  308. var s = TypeConverter.ToNumber(arguments.At(0));
  309. var milli = arguments.Length <= 1 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  310. var date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
  311. var u = TimeClip(Utc(date));
  312. thisObj.As<DateInstance>().PrimitiveValue = u;
  313. return u;
  314. }
  315. private JsValue SetUTCSeconds(JsValue thisObj, JsValue[] arguments)
  316. {
  317. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  318. var s = TypeConverter.ToNumber(arguments.At(0));
  319. var milli = arguments.Length <= 1 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  320. var date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
  321. var u = TimeClip(date);
  322. thisObj.As<DateInstance>().PrimitiveValue = u;
  323. return u;
  324. }
  325. private JsValue SetMinutes(JsValue thisObj, JsValue[] arguments)
  326. {
  327. var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
  328. var m = TypeConverter.ToNumber(arguments.At(0));
  329. var s = arguments.Length <= 1 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  330. var milli = arguments.Length <= 2 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
  331. var date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
  332. var u = TimeClip(Utc(date));
  333. thisObj.As<DateInstance>().PrimitiveValue = u;
  334. return u;
  335. }
  336. private JsValue SetUTCMinutes(JsValue thisObj, JsValue[] arguments)
  337. {
  338. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  339. var m = TypeConverter.ToNumber(arguments.At(0));
  340. var s = arguments.Length <= 1 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  341. var milli = arguments.Length <= 2 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
  342. var date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
  343. var u = TimeClip(date);
  344. thisObj.As<DateInstance>().PrimitiveValue = u;
  345. return u;
  346. }
  347. private JsValue SetHours(JsValue thisObj, JsValue[] arguments)
  348. {
  349. var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
  350. var h = TypeConverter.ToNumber(arguments.At(0));
  351. var m = arguments.Length <= 1 ? MinFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  352. var s = arguments.Length <= 2 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
  353. var milli = arguments.Length <= 3 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(3));
  354. var date = MakeDate(Day(t), MakeTime(h, m, s, milli));
  355. var u = TimeClip(Utc(date));
  356. thisObj.As<DateInstance>().PrimitiveValue = u;
  357. return u;
  358. }
  359. private JsValue SetUTCHours(JsValue thisObj, JsValue[] arguments)
  360. {
  361. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  362. var h = TypeConverter.ToNumber(arguments.At(0));
  363. var m = arguments.Length <= 1 ? MinFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  364. var s = arguments.Length <= 2 ? SecFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
  365. var milli = arguments.Length <= 3 ? MsFromTime(t) : TypeConverter.ToNumber(arguments.At(3));
  366. var date = MakeDate(Day(t), MakeTime(h, m, s, milli));
  367. var u = TimeClip(date);
  368. thisObj.As<DateInstance>().PrimitiveValue = u;
  369. return u;
  370. }
  371. private JsValue SetDate(JsValue thisObj, JsValue[] arguments)
  372. {
  373. var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
  374. var dt = TypeConverter.ToNumber(arguments.At(0));
  375. var newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
  376. var u = TimeClip(Utc(newDate));
  377. thisObj.As<DateInstance>().PrimitiveValue = u;
  378. return u;
  379. }
  380. private JsValue SetUTCDate(JsValue thisObj, JsValue[] arguments)
  381. {
  382. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  383. var dt = TypeConverter.ToNumber(arguments.At(0));
  384. var newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), dt), TimeWithinDay(t));
  385. var u = TimeClip(newDate);
  386. thisObj.As<DateInstance>().PrimitiveValue = u;
  387. return u;
  388. }
  389. private JsValue SetMonth(JsValue thisObj, JsValue[] arguments)
  390. {
  391. var t = LocalTime(EnsureDateInstance(thisObj).PrimitiveValue);
  392. var m = TypeConverter.ToNumber(arguments.At(0));
  393. var dt = arguments.Length <= 1 ? DateFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  394. var newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
  395. var u = TimeClip(Utc(newDate));
  396. thisObj.As<DateInstance>().PrimitiveValue = u;
  397. return u;
  398. }
  399. private JsValue SetUTCMonth(JsValue thisObj, JsValue[] arguments)
  400. {
  401. var t = EnsureDateInstance(thisObj).PrimitiveValue;
  402. var m = TypeConverter.ToNumber(arguments.At(0));
  403. var dt = arguments.Length <= 1 ? DateFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  404. var newDate = MakeDate(MakeDay(YearFromTime(t), m, dt), TimeWithinDay(t));
  405. var u = TimeClip(newDate);
  406. thisObj.As<DateInstance>().PrimitiveValue = u;
  407. return u;
  408. }
  409. private JsValue SetFullYear(JsValue thisObj, JsValue[] arguments)
  410. {
  411. var thisTime = EnsureDateInstance(thisObj).PrimitiveValue;
  412. var t = double.IsNaN(thisTime) ? +0 : LocalTime(thisTime);
  413. var y = TypeConverter.ToNumber(arguments.At(0));
  414. var m = arguments.Length <= 1 ? MonthFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  415. var dt = arguments.Length <= 2 ? DateFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
  416. var newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t));
  417. var u = TimeClip(Utc(newDate));
  418. thisObj.As<DateInstance>().PrimitiveValue = u;
  419. return u;
  420. }
  421. private JsValue SetYear(JsValue thisObj, JsValue[] arguments)
  422. {
  423. var thisTime = EnsureDateInstance(thisObj).PrimitiveValue;
  424. var t = double.IsNaN(thisTime) ? +0 : LocalTime(thisTime);
  425. var y = TypeConverter.ToNumber(arguments.At(0));
  426. if (double.IsNaN(y))
  427. {
  428. EnsureDateInstance(thisObj).PrimitiveValue = double.NaN;
  429. return JsNumber.DoubleNaN;
  430. }
  431. var fy = TypeConverter.ToInteger(y);
  432. if (y >= 0 && y <= 99)
  433. {
  434. fy = fy + 1900;
  435. }
  436. var newDate = MakeDay(fy, MonthFromTime(t), DateFromTime(t));
  437. var u = Utc(MakeDate(newDate, TimeWithinDay(t)));
  438. EnsureDateInstance(thisObj).PrimitiveValue = TimeClip(u);
  439. return u;
  440. }
  441. private JsValue SetUTCFullYear(JsValue thisObj, JsValue[] arguments)
  442. {
  443. var thisTime = EnsureDateInstance(thisObj).PrimitiveValue;
  444. var t = double.IsNaN(thisTime) ? +0 : thisTime;
  445. var y = TypeConverter.ToNumber(arguments.At(0));
  446. var m = arguments.Length <= 1 ? MonthFromTime(t) : TypeConverter.ToNumber(arguments.At(1));
  447. var dt = arguments.Length <= 2 ? DateFromTime(t) : TypeConverter.ToNumber(arguments.At(2));
  448. var newDate = MakeDate(MakeDay(y, m, dt), TimeWithinDay(t));
  449. var u = TimeClip(newDate);
  450. thisObj.As<DateInstance>().PrimitiveValue = u;
  451. return u;
  452. }
  453. private JsValue ToUtcString(JsValue thisObj, JsValue[] arguments)
  454. {
  455. return thisObj.TryCast<DateInstance>(x =>
  456. {
  457. ExceptionHelper.ThrowTypeError(_engine);
  458. } )
  459. .ToDateTime().ToUniversalTime().ToString("ddd MMM dd yyyy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture);
  460. }
  461. private JsValue ToISOString(JsValue thisObj, JsValue[] arguments)
  462. {
  463. var t = thisObj.TryCast<DateInstance>(x =>
  464. {
  465. ExceptionHelper.ThrowTypeError(_engine);
  466. }).PrimitiveValue;
  467. if (double.IsInfinity(t) || double.IsNaN(t))
  468. {
  469. ExceptionHelper.ThrowRangeError(_engine);
  470. }
  471. double h = HourFromTime(t);
  472. double m = MinFromTime(t);
  473. double s = SecFromTime(t);
  474. double ms = MsFromTime(t);
  475. if (h < 0) { h += HoursPerDay; }
  476. if (m < 0) { m += MinutesPerHour; }
  477. if (s < 0) { s += SecondsPerMinute; }
  478. if (ms < 0) { ms += MsPerSecond; }
  479. return $"{YearFromTime(t):0000}-{MonthFromTime(t) + 1:00}-{DateFromTime(t):00}T{h:00}:{m:00}:{s:00}.{ms:000}Z";
  480. }
  481. private JsValue ToJSON(JsValue thisObj, JsValue[] arguments)
  482. {
  483. var o = TypeConverter.ToObject(Engine, thisObj);
  484. var tv = TypeConverter.ToPrimitive(o, Types.Number);
  485. if (tv.IsNumber() && double.IsInfinity(((JsNumber) tv)._value))
  486. {
  487. return Null;
  488. }
  489. var toIso = o.Get("toISOString");
  490. if (!toIso.Is<ICallable>())
  491. {
  492. ExceptionHelper.ThrowTypeError(Engine);
  493. }
  494. return toIso.TryCast<ICallable>().Call(o, Arguments.Empty);
  495. }
  496. public const double HoursPerDay = 24;
  497. public const double MinutesPerHour = 60;
  498. public const double SecondsPerMinute = 60;
  499. public const double MsPerSecond = 1000;
  500. public const double MsPerMinute = 60000;
  501. public const double MsPerHour = 3600000;
  502. public const double MsPerDay = 86400000;
  503. /// <summary>
  504. /// 15.9.1.2
  505. /// </summary>
  506. public static double Day(double t)
  507. {
  508. return System.Math.Floor(t / MsPerDay);
  509. }
  510. /// <summary>
  511. /// 15.9.1.2
  512. /// </summary>
  513. public static double TimeWithinDay(double t)
  514. {
  515. var result = t % MsPerDay;
  516. if (result < 0)
  517. {
  518. result += MsPerDay;
  519. }
  520. return result;
  521. }
  522. /// <summary>
  523. /// The number of days in a year
  524. /// </summary>
  525. public static double DaysInYear(double y)
  526. {
  527. if (!(y%4).Equals(0))
  528. {
  529. return 365;
  530. }
  531. if ((y%4).Equals(0) && !(y%100).Equals(0))
  532. {
  533. return 366;
  534. }
  535. if ((y%100).Equals(0) && !(y%400).Equals(0))
  536. {
  537. return 365;
  538. }
  539. if ((y%400).Equals(0))
  540. {
  541. return 366;
  542. }
  543. return 365;
  544. }
  545. /// <summary>
  546. /// The day number of the first day of the year.
  547. /// </summary>
  548. public static double DayFromYear(double y)
  549. {
  550. return 365*(y - 1970)
  551. + System.Math.Floor((y - 1969)/4)
  552. - System.Math.Floor((y - 1901)/100)
  553. + System.Math.Floor((y - 1601)/400);
  554. }
  555. /// <summary>
  556. /// The time value of the start of the year
  557. /// </summary>
  558. public static double TimeFromYear(double y)
  559. {
  560. return MsPerDay*DayFromYear(y);
  561. }
  562. /// <summary>
  563. /// The year of a time value.
  564. /// </summary>
  565. public static double YearFromTime(double t)
  566. {
  567. if (!AreFinite(t))
  568. {
  569. return double.NaN;
  570. }
  571. var sign = (t < 0) ? -1 : 1;
  572. var year = (sign < 0) ? 1969 : 1970;
  573. for (var timeToTimeZero = t; ;)
  574. {
  575. // Subtract the current year's time from the time that's left.
  576. var timeInYear = DaysInYear(year) * MsPerDay;
  577. timeToTimeZero -= sign * timeInYear;
  578. // If there's less than the current year's worth of time left, then break.
  579. if (sign < 0)
  580. {
  581. if (sign * timeToTimeZero <= 0)
  582. {
  583. break;
  584. }
  585. else
  586. {
  587. year += sign;
  588. }
  589. }
  590. else
  591. {
  592. if (sign * timeToTimeZero < 0)
  593. {
  594. break;
  595. }
  596. else
  597. {
  598. year += sign;
  599. }
  600. }
  601. }
  602. return year;
  603. }
  604. /// <summary>
  605. /// <value>true</value> if the time is within a leap year, <value>false</value> otherwise
  606. /// </summary>
  607. public static double InLeapYear(double t)
  608. {
  609. var daysInYear = DaysInYear(YearFromTime(t));
  610. if (daysInYear.Equals(365))
  611. {
  612. return 0;
  613. }
  614. if (daysInYear.Equals(366))
  615. {
  616. return 1;
  617. }
  618. ExceptionHelper.ThrowArgumentException();
  619. return 0;
  620. }
  621. /// <summary>
  622. /// The month number of a time value.
  623. /// </summary>
  624. public static double MonthFromTime(double t)
  625. {
  626. var dayWithinYear = DayWithinYear(t);
  627. var inLeapYear = InLeapYear(t);
  628. if (dayWithinYear < 31)
  629. {
  630. return 0;
  631. }
  632. if (dayWithinYear < 59 + inLeapYear)
  633. {
  634. return 1;
  635. }
  636. if (dayWithinYear < 90 + inLeapYear)
  637. {
  638. return 2;
  639. }
  640. if (dayWithinYear < 120 + inLeapYear)
  641. {
  642. return 3;
  643. }
  644. if (dayWithinYear < 151 + inLeapYear)
  645. {
  646. return 4;
  647. }
  648. if (dayWithinYear < 181 + inLeapYear)
  649. {
  650. return 5;
  651. }
  652. if (dayWithinYear < 212 + inLeapYear)
  653. {
  654. return 6;
  655. }
  656. if (dayWithinYear < 243 + inLeapYear)
  657. {
  658. return 7;
  659. }
  660. if (dayWithinYear < 273 + inLeapYear)
  661. {
  662. return 8;
  663. }
  664. if (dayWithinYear < 304 + inLeapYear)
  665. {
  666. return 9;
  667. }
  668. if (dayWithinYear < 334 + inLeapYear)
  669. {
  670. return 10;
  671. }
  672. if (dayWithinYear < 365 + inLeapYear)
  673. {
  674. return 11;
  675. }
  676. ExceptionHelper.ThrowInvalidOperationException();
  677. return 0;
  678. }
  679. public static double DayWithinYear(double t)
  680. {
  681. return Day(t) - DayFromYear(YearFromTime(t));
  682. }
  683. public static double DateFromTime(double t)
  684. {
  685. var monthFromTime = MonthFromTime(t);
  686. var dayWithinYear = DayWithinYear(t);
  687. if (monthFromTime.Equals(0))
  688. {
  689. return dayWithinYear + 1;
  690. }
  691. if (monthFromTime.Equals(1))
  692. {
  693. return dayWithinYear - 30;
  694. }
  695. if (monthFromTime.Equals(2))
  696. {
  697. return dayWithinYear - 58 - InLeapYear(t);
  698. }
  699. if (monthFromTime.Equals(3))
  700. {
  701. return dayWithinYear - 89 - InLeapYear(t);
  702. }
  703. if (monthFromTime.Equals(4))
  704. {
  705. return dayWithinYear - 119 - InLeapYear(t);
  706. }
  707. if (monthFromTime.Equals(5))
  708. {
  709. return dayWithinYear - 150 - InLeapYear(t);
  710. }
  711. if (monthFromTime.Equals(6))
  712. {
  713. return dayWithinYear - 180 - InLeapYear(t);
  714. }
  715. if (monthFromTime.Equals(7))
  716. {
  717. return dayWithinYear - 211 - InLeapYear(t);
  718. }
  719. if (monthFromTime.Equals(8))
  720. {
  721. return dayWithinYear - 242 - InLeapYear(t);
  722. }
  723. if (monthFromTime.Equals(9))
  724. {
  725. return dayWithinYear - 272 - InLeapYear(t);
  726. }
  727. if (monthFromTime.Equals(10))
  728. {
  729. return dayWithinYear - 303 - InLeapYear(t);
  730. }
  731. if (monthFromTime.Equals(11))
  732. {
  733. return dayWithinYear - 333 - InLeapYear(t);
  734. }
  735. ExceptionHelper.ThrowInvalidOperationException();
  736. return 0;
  737. }
  738. /// <summary>
  739. /// The weekday for a particular time value.
  740. /// </summary>
  741. public static double WeekDay(double t)
  742. {
  743. return (Day(t) + 4)%7;
  744. }
  745. public double LocalTza => Engine.Options._LocalTimeZone.BaseUtcOffset.TotalMilliseconds;
  746. public double DaylightSavingTa(double t)
  747. {
  748. var timeInYear = t - TimeFromYear(YearFromTime(t));
  749. if (double.IsInfinity(timeInYear) || double.IsNaN(timeInYear))
  750. {
  751. return 0;
  752. }
  753. var year = YearFromTime(t);
  754. if (year < 9999 && year > -9999)
  755. {
  756. // in DateTimeOffset range so we can use it
  757. }
  758. else
  759. {
  760. // use similar leap-ed year
  761. var isLeapYear = InLeapYear(t).Equals(1);
  762. year = isLeapYear ? 2000 : 1999;
  763. }
  764. var dateTime = new DateTime((int)year, 1, 1).AddMilliseconds(timeInYear);
  765. return Engine.Options._LocalTimeZone.IsDaylightSavingTime(dateTime) ? MsPerHour : 0;
  766. }
  767. public DateTimeOffset ToLocalTime(DateTime t)
  768. {
  769. switch (t.Kind)
  770. {
  771. case DateTimeKind.Local:
  772. return new DateTimeOffset(TimeZoneInfo.ConvertTime(t.ToUniversalTime(), Engine.Options._LocalTimeZone), Engine.Options._LocalTimeZone.GetUtcOffset(t));
  773. case DateTimeKind.Utc:
  774. return new DateTimeOffset(TimeZoneInfo.ConvertTime(t, Engine.Options._LocalTimeZone), Engine.Options._LocalTimeZone.GetUtcOffset(t));
  775. default:
  776. return t;
  777. }
  778. }
  779. public double LocalTime(double t)
  780. {
  781. return t + LocalTza + DaylightSavingTa(t);
  782. }
  783. public double Utc(double t)
  784. {
  785. return t - LocalTza - DaylightSavingTa(t - LocalTza);
  786. }
  787. public static double HourFromTime(double t)
  788. {
  789. var hours = System.Math.Floor(t / MsPerHour) % HoursPerDay;
  790. if (hours < 0)
  791. {
  792. hours += HoursPerDay;
  793. }
  794. return hours;
  795. }
  796. public static double MinFromTime(double t)
  797. {
  798. var minutes = System.Math.Floor(t / MsPerMinute) % MinutesPerHour;
  799. if (minutes < 0)
  800. {
  801. minutes += MinutesPerHour;
  802. }
  803. return minutes;
  804. }
  805. public static double SecFromTime(double t)
  806. {
  807. var seconds = System.Math.Floor(t / MsPerSecond) % SecondsPerMinute;
  808. if (seconds < 0)
  809. {
  810. seconds += SecondsPerMinute;
  811. }
  812. return seconds;
  813. }
  814. public static double MsFromTime(double t)
  815. {
  816. var milli = t % MsPerSecond;
  817. if (milli < 0)
  818. {
  819. milli += MsPerSecond;
  820. }
  821. return milli;
  822. }
  823. public static double DayFromMonth(double year, double month)
  824. {
  825. double day = month * 30;
  826. if (month >= 7)
  827. {
  828. day += month/2 - 1;
  829. }
  830. else if (month >= 2)
  831. {
  832. day += (month - 1)/2 - 1;
  833. }
  834. else
  835. {
  836. day += month;
  837. }
  838. if (month >= 2 && InLeapYear(year).Equals(1))
  839. {
  840. day++;
  841. }
  842. return day;
  843. }
  844. public static double DaysInMonth(double month, double leap)
  845. {
  846. month = month%12;
  847. switch ((long) month)
  848. {
  849. case 0:
  850. case 2:
  851. case 4:
  852. case 6:
  853. case 7:
  854. case 9:
  855. case 11:
  856. return 31;
  857. case 3:
  858. case 5:
  859. case 8:
  860. case 10:
  861. return 30;
  862. case 1:
  863. return 28 + leap;
  864. default:
  865. ExceptionHelper.ThrowArgumentOutOfRangeException(nameof(month), "invalid month");
  866. return 0;
  867. }
  868. }
  869. public static double MakeTime(double hour, double min, double sec, double ms)
  870. {
  871. if (!AreFinite(hour, min, sec, ms))
  872. {
  873. return double.NaN;
  874. }
  875. var h = (long) hour;
  876. var m = (long) min;
  877. var s = (long) sec;
  878. var milli = (long) ms;
  879. var t = h*MsPerHour + m*MsPerMinute + s*MsPerSecond + milli;
  880. return t;
  881. }
  882. public static double MakeDay(double year, double month, double date)
  883. {
  884. if (!AreFinite(year, month, date))
  885. {
  886. return double.NaN;
  887. }
  888. year = TypeConverter.ToInteger(year);
  889. month = TypeConverter.ToInteger(month);
  890. date = TypeConverter.ToInteger(date);
  891. if (month < 0)
  892. {
  893. var m = (long) month;
  894. year += (m - 11) / 12;
  895. month = (12 + m % 12) % 12;
  896. }
  897. var sign = (year < 1970) ? -1 : 1;
  898. double t = (year < 1970) ? 1 : 0;
  899. int y;
  900. if (sign == -1)
  901. {
  902. for (y = 1969; y >= year; y += sign)
  903. {
  904. t += sign * DaysInYear(y) * MsPerDay;
  905. }
  906. }
  907. else
  908. {
  909. for (y = 1970; y < year; y += sign)
  910. {
  911. t += sign * DaysInYear(y) * MsPerDay;
  912. }
  913. }
  914. for (var m = 0; m < month; m++)
  915. {
  916. t += DaysInMonth(m, InLeapYear(t)) * MsPerDay;
  917. }
  918. return Day(t) + date - 1;
  919. }
  920. public static double MakeDate(double day, double time)
  921. {
  922. if (!AreFinite(day, time))
  923. {
  924. return double.NaN;
  925. }
  926. return day * MsPerDay + time;
  927. }
  928. public static double TimeClip(double time)
  929. {
  930. if (!AreFinite(time))
  931. {
  932. return double.NaN;
  933. }
  934. if (System.Math.Abs(time) > 8640000000000000)
  935. {
  936. return double.NaN;
  937. }
  938. return (long) time + 0;
  939. }
  940. private static bool AreFinite(params double[] values)
  941. {
  942. for (int index = 0; index < values.Length; index++)
  943. {
  944. var value = values[index];
  945. if (double.IsNaN(value) || double.IsInfinity(value))
  946. {
  947. return false;
  948. }
  949. }
  950. return true;
  951. }
  952. }
  953. }