PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/js/jsdate.cpp

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C++ | 2301 lines | 1637 code | 332 blank | 332 comment | 426 complexity | 18b9835e785a8d289b95cccd244e81bf MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sw=4 et tw=78:
  3. *
  4. * ***** BEGIN LICENSE BLOCK *****
  5. * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  6. *
  7. * The contents of this file are subject to the Mozilla Public License Version
  8. * 1.1 (the "License"); you may not use this file except in compliance with
  9. * the License. You may obtain a copy of the License at
  10. * http://www.mozilla.org/MPL/
  11. *
  12. * Software distributed under the License is distributed on an "AS IS" basis,
  13. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  14. * for the specific language governing rights and limitations under the
  15. * License.
  16. *
  17. * The Original Code is Mozilla Communicator client code, released
  18. * March 31, 1998.
  19. *
  20. * The Initial Developer of the Original Code is
  21. * Netscape Communications Corporation.
  22. * Portions created by the Initial Developer are Copyright (C) 1998
  23. * the Initial Developer. All Rights Reserved.
  24. *
  25. * Contributor(s):
  26. *
  27. * Alternatively, the contents of this file may be used under the terms of
  28. * either of the GNU General Public License Version 2 or later (the "GPL"),
  29. * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  30. * in which case the provisions of the GPL or the LGPL are applicable instead
  31. * of those above. If you wish to allow use of your version of this file only
  32. * under the terms of either the GPL or the LGPL, and not to allow others to
  33. * use your version of this file under the terms of the MPL, indicate your
  34. * decision by deleting the provisions above and replace them with the notice
  35. * and other provisions required by the GPL or the LGPL. If you do not delete
  36. * the provisions above, a recipient may use your version of this file under
  37. * the terms of any one of the MPL, the GPL or the LGPL.
  38. *
  39. * ***** END LICENSE BLOCK ***** */
  40. /*
  41. * JS date methods.
  42. */
  43. /*
  44. * "For example, OS/360 devotes 26 bytes of the permanently
  45. * resident date-turnover routine to the proper handling of
  46. * December 31 on leap years (when it is Day 366). That
  47. * might have been left to the operator."
  48. *
  49. * Frederick Brooks, 'The Second-System Effect'.
  50. */
  51. #include "jsstddef.h"
  52. #include <ctype.h>
  53. #include <locale.h>
  54. #include <math.h>
  55. #include <stdlib.h>
  56. #include <string.h>
  57. #include "jstypes.h"
  58. #include "jsprf.h"
  59. #include "prmjtime.h"
  60. #include "jsutil.h" /* Added by JSIFY */
  61. #include "jsapi.h"
  62. #include "jsversion.h"
  63. #include "jsbuiltins.h"
  64. #include "jscntxt.h"
  65. #include "jsdate.h"
  66. #include "jsinterp.h"
  67. #include "jsnum.h"
  68. #include "jsobj.h"
  69. #include "jsstr.h"
  70. /*
  71. * The JS 'Date' object is patterned after the Java 'Date' object.
  72. * Here is an script:
  73. *
  74. * today = new Date();
  75. *
  76. * print(today.toLocaleString());
  77. *
  78. * weekDay = today.getDay();
  79. *
  80. *
  81. * These Java (and ECMA-262) methods are supported:
  82. *
  83. * UTC
  84. * getDate (getUTCDate)
  85. * getDay (getUTCDay)
  86. * getHours (getUTCHours)
  87. * getMinutes (getUTCMinutes)
  88. * getMonth (getUTCMonth)
  89. * getSeconds (getUTCSeconds)
  90. * getMilliseconds (getUTCMilliseconds)
  91. * getTime
  92. * getTimezoneOffset
  93. * getYear
  94. * getFullYear (getUTCFullYear)
  95. * parse
  96. * setDate (setUTCDate)
  97. * setHours (setUTCHours)
  98. * setMinutes (setUTCMinutes)
  99. * setMonth (setUTCMonth)
  100. * setSeconds (setUTCSeconds)
  101. * setMilliseconds (setUTCMilliseconds)
  102. * setTime
  103. * setYear (setFullYear, setUTCFullYear)
  104. * toGMTString (toUTCString)
  105. * toLocaleString
  106. * toString
  107. *
  108. *
  109. * These Java methods are not supported
  110. *
  111. * setDay
  112. * before
  113. * after
  114. * equals
  115. * hashCode
  116. */
  117. /*
  118. * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
  119. * definition and reduce dependence on NSPR. NSPR is used to get the current
  120. * time in milliseconds, the time zone offset, and the daylight savings time
  121. * offset for a given time. NSPR is also used for Date.toLocaleString(), for
  122. * locale-specific formatting, and to get a string representing the timezone.
  123. * (Which turns out to be platform-dependent.)
  124. *
  125. * To do:
  126. * (I did some performance tests by timing how long it took to run what
  127. * I had of the js ECMA conformance tests.)
  128. *
  129. * - look at saving results across multiple calls to supporting
  130. * functions; the toString functions compute some of the same values
  131. * multiple times. Although - I took a quick stab at this, and I lost
  132. * rather than gained. (Fractionally.) Hard to tell what compilers/processors
  133. * are doing these days.
  134. *
  135. * - look at tweaking function return types to return double instead
  136. * of int; this seems to make things run slightly faster sometimes.
  137. * (though it could be architecture-dependent.) It'd be good to see
  138. * how this does on win32. (Tried it on irix.) Types could use a
  139. * general going-over.
  140. */
  141. /*
  142. * Supporting functions - ECMA 15.9.1.*
  143. */
  144. #define HalfTimeDomain 8.64e15
  145. #define HoursPerDay 24.0
  146. #define MinutesPerDay (HoursPerDay * MinutesPerHour)
  147. #define MinutesPerHour 60.0
  148. #define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
  149. #define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
  150. #define SecondsPerMinute 60.0
  151. #if defined(XP_WIN) || defined(XP_OS2)
  152. /* Work around msvc double optimization bug by making these runtime values; if
  153. * they're available at compile time, msvc optimizes division by them by
  154. * computing the reciprocal and multiplying instead of dividing - this loses
  155. * when the reciprocal isn't representable in a double.
  156. */
  157. static jsdouble msPerSecond = 1000.0;
  158. static jsdouble msPerDay = SecondsPerDay * 1000.0;
  159. static jsdouble msPerHour = SecondsPerHour * 1000.0;
  160. static jsdouble msPerMinute = SecondsPerMinute * 1000.0;
  161. #else
  162. #define msPerDay (SecondsPerDay * msPerSecond)
  163. #define msPerHour (SecondsPerHour * msPerSecond)
  164. #define msPerMinute (SecondsPerMinute * msPerSecond)
  165. #define msPerSecond 1000.0
  166. #endif
  167. #define Day(t) floor((t) / msPerDay)
  168. static jsdouble
  169. TimeWithinDay(jsdouble t)
  170. {
  171. jsdouble result;
  172. result = fmod(t, msPerDay);
  173. if (result < 0)
  174. result += msPerDay;
  175. return result;
  176. }
  177. #define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
  178. ? 366 : 365)
  179. /* math here has to be f.p, because we need
  180. * floor((1968 - 1969) / 4) == -1
  181. */
  182. #define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
  183. - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
  184. #define TimeFromYear(y) (DayFromYear(y) * msPerDay)
  185. static jsint
  186. YearFromTime(jsdouble t)
  187. {
  188. jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
  189. jsdouble t2 = (jsdouble) TimeFromYear(y);
  190. if (t2 > t) {
  191. y--;
  192. } else {
  193. if (t2 + msPerDay * DaysInYear(y) <= t)
  194. y++;
  195. }
  196. return y;
  197. }
  198. #define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
  199. #define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
  200. /*
  201. * The following array contains the day of year for the first day of
  202. * each month, where index 0 is January, and day 0 is January 1.
  203. */
  204. static jsdouble firstDayOfMonth[2][12] = {
  205. {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
  206. {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
  207. };
  208. #define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
  209. static intN
  210. MonthFromTime(jsdouble t)
  211. {
  212. intN d, step;
  213. jsint year = YearFromTime(t);
  214. d = DayWithinYear(t, year);
  215. if (d < (step = 31))
  216. return 0;
  217. step += (InLeapYear(t) ? 29 : 28);
  218. if (d < step)
  219. return 1;
  220. if (d < (step += 31))
  221. return 2;
  222. if (d < (step += 30))
  223. return 3;
  224. if (d < (step += 31))
  225. return 4;
  226. if (d < (step += 30))
  227. return 5;
  228. if (d < (step += 31))
  229. return 6;
  230. if (d < (step += 31))
  231. return 7;
  232. if (d < (step += 30))
  233. return 8;
  234. if (d < (step += 31))
  235. return 9;
  236. if (d < (step += 30))
  237. return 10;
  238. return 11;
  239. }
  240. static intN
  241. DateFromTime(jsdouble t)
  242. {
  243. intN d, step, next;
  244. jsint year = YearFromTime(t);
  245. d = DayWithinYear(t, year);
  246. if (d <= (next = 30))
  247. return d + 1;
  248. step = next;
  249. next += (InLeapYear(t) ? 29 : 28);
  250. if (d <= next)
  251. return d - step;
  252. step = next;
  253. if (d <= (next += 31))
  254. return d - step;
  255. step = next;
  256. if (d <= (next += 30))
  257. return d - step;
  258. step = next;
  259. if (d <= (next += 31))
  260. return d - step;
  261. step = next;
  262. if (d <= (next += 30))
  263. return d - step;
  264. step = next;
  265. if (d <= (next += 31))
  266. return d - step;
  267. step = next;
  268. if (d <= (next += 31))
  269. return d - step;
  270. step = next;
  271. if (d <= (next += 30))
  272. return d - step;
  273. step = next;
  274. if (d <= (next += 31))
  275. return d - step;
  276. step = next;
  277. if (d <= (next += 30))
  278. return d - step;
  279. step = next;
  280. return d - step;
  281. }
  282. static intN
  283. WeekDay(jsdouble t)
  284. {
  285. jsint result;
  286. result = (jsint) Day(t) + 4;
  287. result = result % 7;
  288. if (result < 0)
  289. result += 7;
  290. return (intN) result;
  291. }
  292. #define MakeTime(hour, min, sec, ms) \
  293. ((((hour) * MinutesPerHour + (min)) * SecondsPerMinute + (sec)) * msPerSecond + (ms))
  294. static jsdouble
  295. MakeDay(jsdouble year, jsdouble month, jsdouble date)
  296. {
  297. JSBool leap;
  298. jsdouble yearday;
  299. jsdouble monthday;
  300. year += floor(month / 12);
  301. month = fmod(month, 12.0);
  302. if (month < 0)
  303. month += 12;
  304. leap = (DaysInYear((jsint) year) == 366);
  305. yearday = floor(TimeFromYear(year) / msPerDay);
  306. monthday = DayFromMonth(month, leap);
  307. return yearday + monthday + date - 1;
  308. }
  309. #define MakeDate(day, time) ((day) * msPerDay + (time))
  310. /*
  311. * Years and leap years on which Jan 1 is a Sunday, Monday, etc.
  312. *
  313. * yearStartingWith[0][i] is an example non-leap year where
  314. * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
  315. *
  316. * yearStartingWith[1][i] is an example leap year where
  317. * Jan 1 appears on Sunday (i == 0), Monday (i == 1), etc.
  318. */
  319. static jsint yearStartingWith[2][7] = {
  320. {1978, 1973, 1974, 1975, 1981, 1971, 1977},
  321. {1984, 1996, 1980, 1992, 1976, 1988, 1972}
  322. };
  323. /*
  324. * Find a year for which any given date will fall on the same weekday.
  325. *
  326. * This function should be used with caution when used other than
  327. * for determining DST; it hasn't been proven not to produce an
  328. * incorrect year for times near year boundaries.
  329. */
  330. static jsint
  331. EquivalentYearForDST(jsint year)
  332. {
  333. jsint day;
  334. JSBool isLeapYear;
  335. day = (jsint) DayFromYear(year) + 4;
  336. day = day % 7;
  337. if (day < 0)
  338. day += 7;
  339. isLeapYear = (DaysInYear(year) == 366);
  340. return yearStartingWith[isLeapYear][day];
  341. }
  342. /* LocalTZA gets set by js_InitDateClass() */
  343. static jsdouble LocalTZA;
  344. static jsdouble
  345. DaylightSavingTA(jsdouble t)
  346. {
  347. volatile int64 PR_t;
  348. int64 ms2us;
  349. int64 offset;
  350. jsdouble result;
  351. /* abort if NaN */
  352. if (JSDOUBLE_IS_NaN(t))
  353. return t;
  354. /*
  355. * If earlier than 1970 or after 2038, potentially beyond the ken of
  356. * many OSes, map it to an equivalent year before asking.
  357. */
  358. if (t < 0.0 || t > 2145916800000.0) {
  359. jsint year;
  360. jsdouble day;
  361. year = EquivalentYearForDST(YearFromTime(t));
  362. day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
  363. t = MakeDate(day, TimeWithinDay(t));
  364. }
  365. /* put our t in an LL, and map it to usec for prtime */
  366. JSLL_D2L(PR_t, t);
  367. JSLL_I2L(ms2us, PRMJ_USEC_PER_MSEC);
  368. JSLL_MUL(PR_t, PR_t, ms2us);
  369. offset = PRMJ_DSTOffset(PR_t);
  370. JSLL_DIV(offset, offset, ms2us);
  371. JSLL_L2D(result, offset);
  372. return result;
  373. }
  374. #define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay)
  375. #define LocalTime(t) ((t) + AdjustTime(t))
  376. static jsdouble
  377. UTC(jsdouble t)
  378. {
  379. return t - AdjustTime(t - LocalTZA);
  380. }
  381. static intN
  382. HourFromTime(jsdouble t)
  383. {
  384. intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
  385. if (result < 0)
  386. result += (intN)HoursPerDay;
  387. return result;
  388. }
  389. static intN
  390. MinFromTime(jsdouble t)
  391. {
  392. intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
  393. if (result < 0)
  394. result += (intN)MinutesPerHour;
  395. return result;
  396. }
  397. static intN
  398. SecFromTime(jsdouble t)
  399. {
  400. intN result = (intN) fmod(floor(t / msPerSecond), SecondsPerMinute);
  401. if (result < 0)
  402. result += (intN)SecondsPerMinute;
  403. return result;
  404. }
  405. static intN
  406. msFromTime(jsdouble t)
  407. {
  408. intN result = (intN) fmod(t, msPerSecond);
  409. if (result < 0)
  410. result += (intN)msPerSecond;
  411. return result;
  412. }
  413. #define TIMECLIP(d) ((JSDOUBLE_IS_FINITE(d) \
  414. && !((d < 0 ? -d : d) > HalfTimeDomain)) \
  415. ? js_DoubleToInteger(d + (+0.)) : *cx->runtime->jsNaN)
  416. /**
  417. * end of ECMA 'support' functions
  418. */
  419. /*
  420. * Other Support routines and definitions
  421. */
  422. /*
  423. * We use the first reseved slot to store UTC time, and the second for caching
  424. * the local time. The initial value of the cache entry is NaN.
  425. */
  426. const uint32 JSSLOT_UTC_TIME = JSSLOT_PRIVATE;
  427. const uint32 JSSLOT_LOCAL_TIME = JSSLOT_PRIVATE + 1;
  428. const uint32 DATE_RESERVED_SLOTS = 2;
  429. JSClass js_DateClass = {
  430. js_Date_str,
  431. JSCLASS_HAS_RESERVED_SLOTS(DATE_RESERVED_SLOTS) |
  432. JSCLASS_HAS_CACHED_PROTO(JSProto_Date),
  433. JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
  434. JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
  435. JSCLASS_NO_OPTIONAL_MEMBERS
  436. };
  437. /* for use by date_parse */
  438. static const char* wtb[] = {
  439. "am", "pm",
  440. "monday", "tuesday", "wednesday", "thursday", "friday",
  441. "saturday", "sunday",
  442. "january", "february", "march", "april", "may", "june",
  443. "july", "august", "september", "october", "november", "december",
  444. "gmt", "ut", "utc",
  445. "est", "edt",
  446. "cst", "cdt",
  447. "mst", "mdt",
  448. "pst", "pdt"
  449. /* time zone table needs to be expanded */
  450. };
  451. static int ttb[] = {
  452. -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */
  453. 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
  454. 10000 + 0, 10000 + 0, 10000 + 0, /* GMT/UT/UTC */
  455. 10000 + 5 * 60, 10000 + 4 * 60, /* EST/EDT */
  456. 10000 + 6 * 60, 10000 + 5 * 60, /* CST/CDT */
  457. 10000 + 7 * 60, 10000 + 6 * 60, /* MST/MDT */
  458. 10000 + 8 * 60, 10000 + 7 * 60 /* PST/PDT */
  459. };
  460. /* helper for date_parse */
  461. static JSBool
  462. date_regionMatches(const char* s1, int s1off, const jschar* s2, int s2off,
  463. int count, int ignoreCase)
  464. {
  465. JSBool result = JS_FALSE;
  466. /* return true if matches, otherwise, false */
  467. while (count > 0 && s1[s1off] && s2[s2off]) {
  468. if (ignoreCase) {
  469. if (JS_TOLOWER((jschar)s1[s1off]) != JS_TOLOWER(s2[s2off])) {
  470. break;
  471. }
  472. } else {
  473. if ((jschar)s1[s1off] != s2[s2off]) {
  474. break;
  475. }
  476. }
  477. s1off++;
  478. s2off++;
  479. count--;
  480. }
  481. if (count == 0) {
  482. result = JS_TRUE;
  483. }
  484. return result;
  485. }
  486. /* find UTC time from given date... no 1900 correction! */
  487. static jsdouble
  488. date_msecFromDate(jsdouble year, jsdouble mon, jsdouble mday, jsdouble hour,
  489. jsdouble min, jsdouble sec, jsdouble msec)
  490. {
  491. jsdouble day;
  492. jsdouble msec_time;
  493. jsdouble result;
  494. day = MakeDay(year, mon, mday);
  495. msec_time = MakeTime(hour, min, sec, msec);
  496. result = MakeDate(day, msec_time);
  497. return result;
  498. }
  499. /* compute the time in msec (unclipped) from the given args */
  500. #define MAXARGS 7
  501. static JSBool
  502. date_msecFromArgs(JSContext *cx, uintN argc, jsval *argv, jsdouble *rval)
  503. {
  504. uintN loop;
  505. jsdouble array[MAXARGS];
  506. jsdouble d;
  507. jsdouble msec_time;
  508. for (loop = 0; loop < MAXARGS; loop++) {
  509. if (loop < argc) {
  510. d = js_ValueToNumber(cx, &argv[loop]);
  511. if (JSVAL_IS_NULL(argv[loop]))
  512. return JS_FALSE;
  513. /* return NaN if any arg is not finite */
  514. if (!JSDOUBLE_IS_FINITE(d)) {
  515. *rval = *cx->runtime->jsNaN;
  516. return JS_TRUE;
  517. }
  518. array[loop] = js_DoubleToInteger(d);
  519. } else {
  520. if (loop == 2) {
  521. array[loop] = 1; /* Default the date argument to 1. */
  522. } else {
  523. array[loop] = 0;
  524. }
  525. }
  526. }
  527. /* adjust 2-digit years into the 20th century */
  528. if (array[0] >= 0 && array[0] <= 99)
  529. array[0] += 1900;
  530. msec_time = date_msecFromDate(array[0], array[1], array[2],
  531. array[3], array[4], array[5], array[6]);
  532. *rval = msec_time;
  533. return JS_TRUE;
  534. }
  535. /*
  536. * See ECMA 15.9.4.[3-10];
  537. */
  538. static JSBool
  539. date_UTC(JSContext *cx, uintN argc, jsval *vp)
  540. {
  541. jsdouble msec_time;
  542. if (!date_msecFromArgs(cx, argc, vp + 2, &msec_time))
  543. return JS_FALSE;
  544. msec_time = TIMECLIP(msec_time);
  545. return js_NewNumberInRootedValue(cx, msec_time, vp);
  546. }
  547. static JSBool
  548. date_parseString(JSString *str, jsdouble *result)
  549. {
  550. jsdouble msec;
  551. const jschar *s;
  552. size_t limit;
  553. size_t i = 0;
  554. int year = -1;
  555. int mon = -1;
  556. int mday = -1;
  557. int hour = -1;
  558. int min = -1;
  559. int sec = -1;
  560. int c = -1;
  561. int n = -1;
  562. int tzoffset = -1;
  563. int prevc = 0;
  564. JSBool seenplusminus = JS_FALSE;
  565. int temp;
  566. JSBool seenmonthname = JS_FALSE;
  567. JSSTRING_CHARS_AND_LENGTH(str, s, limit);
  568. if (limit == 0)
  569. goto syntax;
  570. while (i < limit) {
  571. c = s[i];
  572. i++;
  573. if (c <= ' ' || c == ',' || c == '-') {
  574. if (c == '-' && '0' <= s[i] && s[i] <= '9') {
  575. prevc = c;
  576. }
  577. continue;
  578. }
  579. if (c == '(') { /* comments) */
  580. int depth = 1;
  581. while (i < limit) {
  582. c = s[i];
  583. i++;
  584. if (c == '(') depth++;
  585. else if (c == ')')
  586. if (--depth <= 0)
  587. break;
  588. }
  589. continue;
  590. }
  591. if ('0' <= c && c <= '9') {
  592. n = c - '0';
  593. while (i < limit && '0' <= (c = s[i]) && c <= '9') {
  594. n = n * 10 + c - '0';
  595. i++;
  596. }
  597. /* allow TZA before the year, so
  598. * 'Wed Nov 05 21:49:11 GMT-0800 1997'
  599. * works */
  600. /* uses of seenplusminus allow : in TZA, so Java
  601. * no-timezone style of GMT+4:30 works
  602. */
  603. if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
  604. /* make ':' case below change tzoffset */
  605. seenplusminus = JS_TRUE;
  606. /* offset */
  607. if (n < 24)
  608. n = n * 60; /* EG. "GMT-3" */
  609. else
  610. n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
  611. if (prevc == '+') /* plus means east of GMT */
  612. n = -n;
  613. if (tzoffset != 0 && tzoffset != -1)
  614. goto syntax;
  615. tzoffset = n;
  616. } else if (prevc == '/' && mon >= 0 && mday >= 0 && year < 0) {
  617. if (c <= ' ' || c == ',' || c == '/' || i >= limit)
  618. year = n;
  619. else
  620. goto syntax;
  621. } else if (c == ':') {
  622. if (hour < 0)
  623. hour = /*byte*/ n;
  624. else if (min < 0)
  625. min = /*byte*/ n;
  626. else
  627. goto syntax;
  628. } else if (c == '/') {
  629. /* until it is determined that mon is the actual
  630. month, keep it as 1-based rather than 0-based */
  631. if (mon < 0)
  632. mon = /*byte*/ n;
  633. else if (mday < 0)
  634. mday = /*byte*/ n;
  635. else
  636. goto syntax;
  637. } else if (i < limit && c != ',' && c > ' ' && c != '-' && c != '(') {
  638. goto syntax;
  639. } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
  640. if (tzoffset < 0)
  641. tzoffset -= n;
  642. else
  643. tzoffset += n;
  644. } else if (hour >= 0 && min < 0) {
  645. min = /*byte*/ n;
  646. } else if (prevc == ':' && min >= 0 && sec < 0) {
  647. sec = /*byte*/ n;
  648. } else if (mon < 0) {
  649. mon = /*byte*/n;
  650. } else if (mon >= 0 && mday < 0) {
  651. mday = /*byte*/ n;
  652. } else if (mon >= 0 && mday >= 0 && year < 0) {
  653. year = n;
  654. } else {
  655. goto syntax;
  656. }
  657. prevc = 0;
  658. } else if (c == '/' || c == ':' || c == '+' || c == '-') {
  659. prevc = c;
  660. } else {
  661. size_t st = i - 1;
  662. int k;
  663. while (i < limit) {
  664. c = s[i];
  665. if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
  666. break;
  667. i++;
  668. }
  669. if (i <= st + 1)
  670. goto syntax;
  671. for (k = JS_ARRAY_LENGTH(wtb); --k >= 0;)
  672. if (date_regionMatches(wtb[k], 0, s, st, i-st, 1)) {
  673. int action = ttb[k];
  674. if (action != 0) {
  675. if (action < 0) {
  676. /*
  677. * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
  678. * 12:30, instead of blindly adding 12 if PM.
  679. */
  680. JS_ASSERT(action == -1 || action == -2);
  681. if (hour > 12 || hour < 0) {
  682. goto syntax;
  683. } else {
  684. if (action == -1 && hour == 12) { /* am */
  685. hour = 0;
  686. } else if (action == -2 && hour != 12) { /* pm */
  687. hour += 12;
  688. }
  689. }
  690. } else if (action <= 13) { /* month! */
  691. /* Adjust mon to be 1-based until the final values
  692. for mon, mday and year are adjusted below */
  693. if (seenmonthname) {
  694. goto syntax;
  695. }
  696. seenmonthname = JS_TRUE;
  697. temp = /*byte*/ (action - 2) + 1;
  698. if (mon < 0) {
  699. mon = temp;
  700. } else if (mday < 0) {
  701. mday = mon;
  702. mon = temp;
  703. } else if (year < 0) {
  704. year = mon;
  705. mon = temp;
  706. } else {
  707. goto syntax;
  708. }
  709. } else {
  710. tzoffset = action - 10000;
  711. }
  712. }
  713. break;
  714. }
  715. if (k < 0)
  716. goto syntax;
  717. prevc = 0;
  718. }
  719. }
  720. if (year < 0 || mon < 0 || mday < 0)
  721. goto syntax;
  722. /*
  723. Case 1. The input string contains an English month name.
  724. The form of the string can be month f l, or f month l, or
  725. f l month which each evaluate to the same date.
  726. If f and l are both greater than or equal to 70, or
  727. both less than 70, the date is invalid.
  728. The year is taken to be the greater of the values f, l.
  729. If the year is greater than or equal to 70 and less than 100,
  730. it is considered to be the number of years after 1900.
  731. Case 2. The input string is of the form "f/m/l" where f, m and l are
  732. integers, e.g. 7/16/45.
  733. Adjust the mon, mday and year values to achieve 100% MSIE
  734. compatibility.
  735. a. If 0 <= f < 70, f/m/l is interpreted as month/day/year.
  736. i. If year < 100, it is the number of years after 1900
  737. ii. If year >= 100, it is the number of years after 0.
  738. b. If 70 <= f < 100
  739. i. If m < 70, f/m/l is interpreted as
  740. year/month/day where year is the number of years after
  741. 1900.
  742. ii. If m >= 70, the date is invalid.
  743. c. If f >= 100
  744. i. If m < 70, f/m/l is interpreted as
  745. year/month/day where year is the number of years after 0.
  746. ii. If m >= 70, the date is invalid.
  747. */
  748. if (seenmonthname) {
  749. if ((mday >= 70 && year >= 70) || (mday < 70 && year < 70)) {
  750. goto syntax;
  751. }
  752. if (mday > year) {
  753. temp = year;
  754. year = mday;
  755. mday = temp;
  756. }
  757. if (year >= 70 && year < 100) {
  758. year += 1900;
  759. }
  760. } else if (mon < 70) { /* (a) month/day/year */
  761. if (year < 100) {
  762. year += 1900;
  763. }
  764. } else if (mon < 100) { /* (b) year/month/day */
  765. if (mday < 70) {
  766. temp = year;
  767. year = mon + 1900;
  768. mon = mday;
  769. mday = temp;
  770. } else {
  771. goto syntax;
  772. }
  773. } else { /* (c) year/month/day */
  774. if (mday < 70) {
  775. temp = year;
  776. year = mon;
  777. mon = mday;
  778. mday = temp;
  779. } else {
  780. goto syntax;
  781. }
  782. }
  783. mon -= 1; /* convert month to 0-based */
  784. if (sec < 0)
  785. sec = 0;
  786. if (min < 0)
  787. min = 0;
  788. if (hour < 0)
  789. hour = 0;
  790. if (tzoffset == -1) { /* no time zone specified, have to use local */
  791. jsdouble msec_time;
  792. msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
  793. *result = UTC(msec_time);
  794. return JS_TRUE;
  795. }
  796. msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
  797. msec += tzoffset * msPerMinute;
  798. *result = msec;
  799. return JS_TRUE;
  800. syntax:
  801. /* syntax error */
  802. *result = 0;
  803. return JS_FALSE;
  804. }
  805. static JSBool
  806. date_parse(JSContext *cx, uintN argc, jsval *vp)
  807. {
  808. JSString *str;
  809. jsdouble result;
  810. if (argc == 0) {
  811. *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  812. return JS_TRUE;
  813. }
  814. str = js_ValueToString(cx, vp[2]);
  815. if (!str)
  816. return JS_FALSE;
  817. vp[2] = STRING_TO_JSVAL(str);
  818. if (!date_parseString(str, &result)) {
  819. *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  820. return JS_TRUE;
  821. }
  822. result = TIMECLIP(result);
  823. return js_NewNumberInRootedValue(cx, result, vp);
  824. }
  825. static JSBool
  826. date_now(JSContext *cx, uintN argc, jsval *vp)
  827. {
  828. return js_NewDoubleInRootedValue(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC, vp);
  829. }
  830. #ifdef JS_TRACER
  831. static jsdouble FASTCALL
  832. date_now_tn(JSContext*)
  833. {
  834. return PRMJ_Now() / PRMJ_USEC_PER_MSEC;
  835. }
  836. #endif
  837. /*
  838. * Get UTC time from the date object. Returns false if the object is not
  839. * Date type.
  840. */
  841. static JSBool
  842. GetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
  843. {
  844. if (!JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
  845. return JS_FALSE;
  846. *dp = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]);
  847. return JS_TRUE;
  848. }
  849. /*
  850. * Set UTC time slot with a pointer pointing to a jsdouble. This function is
  851. * used only for setting UTC time to some predefined values, such as NaN.
  852. *
  853. * It also invalidates cached local time.
  854. */
  855. static JSBool
  856. SetUTCTimePtr(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
  857. {
  858. if (vp && !JS_InstanceOf(cx, obj, &js_DateClass, vp + 2))
  859. return JS_FALSE;
  860. JS_ASSERT_IF(!vp, STOBJ_GET_CLASS(obj) == &js_DateClass);
  861. /* Invalidate local time cache. */
  862. obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  863. obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(dp);
  864. return JS_TRUE;
  865. }
  866. /*
  867. * Set UTC time to a given time.
  868. */
  869. static JSBool
  870. SetUTCTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble t)
  871. {
  872. jsdouble *dp = js_NewWeaklyRootedDouble(cx, t);
  873. if (!dp)
  874. return JS_FALSE;
  875. return SetUTCTimePtr(cx, obj, vp, dp);
  876. }
  877. /*
  878. * Get the local time, cache it if necessary. If UTC time is not finite
  879. * (e.g., NaN), the local time slot is set to the UTC time without conversion.
  880. */
  881. static JSBool
  882. GetAndCacheLocalTime(JSContext *cx, JSObject *obj, jsval *vp, jsdouble *dp)
  883. {
  884. jsval v;
  885. jsdouble result;
  886. jsdouble *cached;
  887. if (!obj || !JS_InstanceOf(cx, obj, &js_DateClass, vp ? vp + 2 : NULL))
  888. return JS_FALSE;
  889. v = obj->fslots[JSSLOT_LOCAL_TIME];
  890. result = *JSVAL_TO_DOUBLE(v);
  891. if (JSDOUBLE_IS_NaN(result)) {
  892. if (!GetUTCTime(cx, obj, vp, &result))
  893. return JS_FALSE;
  894. /* if result is NaN, it couldn't be finite. */
  895. if (JSDOUBLE_IS_FINITE(result))
  896. result = LocalTime(result);
  897. cached = js_NewWeaklyRootedDouble(cx, result);
  898. if (!cached)
  899. return JS_FALSE;
  900. obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cached);
  901. }
  902. *dp = result;
  903. return JS_TRUE;
  904. }
  905. /*
  906. * See ECMA 15.9.5.4 thru 15.9.5.23
  907. */
  908. static JSBool
  909. date_getTime(JSContext *cx, uintN argc, jsval *vp)
  910. {
  911. jsdouble result;
  912. return GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result) &&
  913. js_NewNumberInRootedValue(cx, result, vp);
  914. }
  915. static JSBool
  916. GetYear(JSContext *cx, JSBool fullyear, jsval *vp)
  917. {
  918. jsdouble result;
  919. if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  920. return JS_FALSE;
  921. if (JSDOUBLE_IS_FINITE(result)) {
  922. result = YearFromTime(result);
  923. /* Follow ECMA-262 to the letter, contrary to IE JScript. */
  924. if (!fullyear)
  925. result -= 1900;
  926. }
  927. return js_NewNumberInRootedValue(cx, result, vp);
  928. }
  929. static JSBool
  930. date_getYear(JSContext *cx, uintN argc, jsval *vp)
  931. {
  932. return GetYear(cx, JS_FALSE, vp);
  933. }
  934. static JSBool
  935. date_getFullYear(JSContext *cx, uintN argc, jsval *vp)
  936. {
  937. return GetYear(cx, JS_TRUE, vp);
  938. }
  939. static JSBool
  940. date_getUTCFullYear(JSContext *cx, uintN argc, jsval *vp)
  941. {
  942. jsdouble result;
  943. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  944. return JS_FALSE;
  945. if (JSDOUBLE_IS_FINITE(result))
  946. result = YearFromTime(result);
  947. return js_NewNumberInRootedValue(cx, result, vp);
  948. }
  949. static JSBool
  950. date_getMonth(JSContext *cx, uintN argc, jsval *vp)
  951. {
  952. jsdouble result;
  953. if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  954. return JS_FALSE;
  955. if (JSDOUBLE_IS_FINITE(result))
  956. result = MonthFromTime(result);
  957. return js_NewNumberInRootedValue(cx, result, vp);
  958. }
  959. static JSBool
  960. date_getUTCMonth(JSContext *cx, uintN argc, jsval *vp)
  961. {
  962. jsdouble result;
  963. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  964. return JS_FALSE;
  965. if (JSDOUBLE_IS_FINITE(result))
  966. result = MonthFromTime(result);
  967. return js_NewNumberInRootedValue(cx, result, vp);
  968. }
  969. static JSBool
  970. date_getDate(JSContext *cx, uintN argc, jsval *vp)
  971. {
  972. jsdouble result;
  973. if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  974. return JS_FALSE;
  975. if (JSDOUBLE_IS_FINITE(result))
  976. result = DateFromTime(result);
  977. return js_NewNumberInRootedValue(cx, result, vp);
  978. }
  979. static JSBool
  980. date_getUTCDate(JSContext *cx, uintN argc, jsval *vp)
  981. {
  982. jsdouble result;
  983. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  984. return JS_FALSE;
  985. if (JSDOUBLE_IS_FINITE(result))
  986. result = DateFromTime(result);
  987. return js_NewNumberInRootedValue(cx, result, vp);
  988. }
  989. static JSBool
  990. date_getDay(JSContext *cx, uintN argc, jsval *vp)
  991. {
  992. jsdouble result;
  993. if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  994. return JS_FALSE;
  995. if (JSDOUBLE_IS_FINITE(result))
  996. result = WeekDay(result);
  997. return js_NewNumberInRootedValue(cx, result, vp);
  998. }
  999. static JSBool
  1000. date_getUTCDay(JSContext *cx, uintN argc, jsval *vp)
  1001. {
  1002. jsdouble result;
  1003. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1004. return JS_FALSE;
  1005. if (JSDOUBLE_IS_FINITE(result))
  1006. result = WeekDay(result);
  1007. return js_NewNumberInRootedValue(cx, result, vp);
  1008. }
  1009. static JSBool
  1010. date_getHours(JSContext *cx, uintN argc, jsval *vp)
  1011. {
  1012. jsdouble result;
  1013. if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1014. return JS_FALSE;
  1015. if (JSDOUBLE_IS_FINITE(result))
  1016. result = HourFromTime(result);
  1017. return js_NewNumberInRootedValue(cx, result, vp);
  1018. }
  1019. static JSBool
  1020. date_getUTCHours(JSContext *cx, uintN argc, jsval *vp)
  1021. {
  1022. jsdouble result;
  1023. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1024. return JS_FALSE;
  1025. if (JSDOUBLE_IS_FINITE(result))
  1026. result = HourFromTime(result);
  1027. return js_NewNumberInRootedValue(cx, result, vp);
  1028. }
  1029. static JSBool
  1030. date_getMinutes(JSContext *cx, uintN argc, jsval *vp)
  1031. {
  1032. jsdouble result;
  1033. if (!GetAndCacheLocalTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1034. return JS_FALSE;
  1035. if (JSDOUBLE_IS_FINITE(result))
  1036. result = MinFromTime(result);
  1037. return js_NewNumberInRootedValue(cx, result, vp);
  1038. }
  1039. static JSBool
  1040. date_getUTCMinutes(JSContext *cx, uintN argc, jsval *vp)
  1041. {
  1042. jsdouble result;
  1043. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1044. return JS_FALSE;
  1045. if (JSDOUBLE_IS_FINITE(result))
  1046. result = MinFromTime(result);
  1047. return js_NewNumberInRootedValue(cx, result, vp);
  1048. }
  1049. /* Date.getSeconds is mapped to getUTCSeconds */
  1050. static JSBool
  1051. date_getUTCSeconds(JSContext *cx, uintN argc, jsval *vp)
  1052. {
  1053. jsdouble result;
  1054. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1055. return JS_FALSE;
  1056. if (JSDOUBLE_IS_FINITE(result))
  1057. result = SecFromTime(result);
  1058. return js_NewNumberInRootedValue(cx, result, vp);
  1059. }
  1060. /* Date.getMilliseconds is mapped to getUTCMilliseconds */
  1061. static JSBool
  1062. date_getUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp)
  1063. {
  1064. jsdouble result;
  1065. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &result))
  1066. return JS_FALSE;
  1067. if (JSDOUBLE_IS_FINITE(result))
  1068. result = msFromTime(result);
  1069. return js_NewNumberInRootedValue(cx, result, vp);
  1070. }
  1071. static JSBool
  1072. date_getTimezoneOffset(JSContext *cx, uintN argc, jsval *vp)
  1073. {
  1074. JSObject *obj;
  1075. jsdouble utctime, localtime, result;
  1076. obj = JS_THIS_OBJECT(cx, vp);
  1077. if (!GetUTCTime(cx, obj, vp, &utctime))
  1078. return JS_FALSE;
  1079. if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime))
  1080. return JS_FALSE;
  1081. /*
  1082. * Return the time zone offset in minutes for the current locale that is
  1083. * appropriate for this time. This value would be a constant except for
  1084. * daylight savings time.
  1085. */
  1086. result = (utctime - localtime) / msPerMinute;
  1087. return js_NewNumberInRootedValue(cx, result, vp);
  1088. }
  1089. static JSBool
  1090. SetDateToNaN(JSContext *cx, jsval *vp)
  1091. {
  1092. JSObject *obj;
  1093. obj = JS_THIS_OBJECT(cx, vp);
  1094. if (!SetUTCTimePtr(cx, obj, NULL, cx->runtime->jsNaN))
  1095. return JS_FALSE;
  1096. *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  1097. return JS_TRUE;
  1098. }
  1099. static JSBool
  1100. date_setTime(JSContext *cx, uintN argc, jsval *vp)
  1101. {
  1102. jsdouble result;
  1103. if (argc == 0)
  1104. return SetDateToNaN(cx, vp);
  1105. result = js_ValueToNumber(cx, &vp[2]);
  1106. if (JSVAL_IS_NULL(vp[2]))
  1107. return JS_FALSE;
  1108. result = TIMECLIP(result);
  1109. if (!SetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, result))
  1110. return JS_FALSE;
  1111. return js_NewNumberInRootedValue(cx, result, vp);
  1112. }
  1113. static JSBool
  1114. date_makeTime(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
  1115. {
  1116. JSObject *obj;
  1117. jsval *argv;
  1118. uintN i;
  1119. jsdouble args[4], *argp, *stop;
  1120. jsdouble hour, min, sec, msec;
  1121. jsdouble lorutime; /* Local or UTC version of *date */
  1122. jsdouble msec_time;
  1123. jsdouble result;
  1124. obj = JS_THIS_OBJECT(cx, vp);
  1125. if (!GetUTCTime(cx, obj, vp, &result))
  1126. return JS_FALSE;
  1127. /* just return NaN if the date is already NaN */
  1128. if (!JSDOUBLE_IS_FINITE(result))
  1129. return js_NewNumberInRootedValue(cx, result, vp);
  1130. /*
  1131. * Satisfy the ECMA rule that if a function is called with
  1132. * fewer arguments than the specified formal arguments, the
  1133. * remaining arguments are set to undefined. Seems like all
  1134. * the Date.setWhatever functions in ECMA are only varargs
  1135. * beyond the first argument; this should be set to undefined
  1136. * if it's not given. This means that "d = new Date();
  1137. * d.setMilliseconds()" returns NaN. Blech.
  1138. */
  1139. if (argc == 0)
  1140. return SetDateToNaN(cx, vp);
  1141. if (argc > maxargs)
  1142. argc = maxargs; /* clamp argc */
  1143. JS_ASSERT(argc <= 4);
  1144. argv = vp + 2;
  1145. for (i = 0; i < argc; i++) {
  1146. args[i] = js_ValueToNumber(cx, &argv[i]);
  1147. if (JSVAL_IS_NULL(argv[i]))
  1148. return JS_FALSE;
  1149. if (!JSDOUBLE_IS_FINITE(args[i]))
  1150. return SetDateToNaN(cx, vp);
  1151. args[i] = js_DoubleToInteger(args[i]);
  1152. }
  1153. if (local)
  1154. lorutime = LocalTime(result);
  1155. else
  1156. lorutime = result;
  1157. argp = args;
  1158. stop = argp + argc;
  1159. if (maxargs >= 4 && argp < stop)
  1160. hour = *argp++;
  1161. else
  1162. hour = HourFromTime(lorutime);
  1163. if (maxargs >= 3 && argp < stop)
  1164. min = *argp++;
  1165. else
  1166. min = MinFromTime(lorutime);
  1167. if (maxargs >= 2 && argp < stop)
  1168. sec = *argp++;
  1169. else
  1170. sec = SecFromTime(lorutime);
  1171. if (maxargs >= 1 && argp < stop)
  1172. msec = *argp;
  1173. else
  1174. msec = msFromTime(lorutime);
  1175. msec_time = MakeTime(hour, min, sec, msec);
  1176. result = MakeDate(Day(lorutime), msec_time);
  1177. /* fprintf(stderr, "%f\n", result); */
  1178. if (local)
  1179. result = UTC(result);
  1180. /* fprintf(stderr, "%f\n", result); */
  1181. result = TIMECLIP(result);
  1182. if (!SetUTCTime(cx, obj, NULL, result))
  1183. return JS_FALSE;
  1184. return js_NewNumberInRootedValue(cx, result, vp);
  1185. }
  1186. static JSBool
  1187. date_setMilliseconds(JSContext *cx, uintN argc, jsval *vp)
  1188. {
  1189. return date_makeTime(cx, 1, JS_TRUE, argc, vp);
  1190. }
  1191. static JSBool
  1192. date_setUTCMilliseconds(JSContext *cx, uintN argc, jsval *vp)
  1193. {
  1194. return date_makeTime(cx, 1, JS_FALSE, argc, vp);
  1195. }
  1196. static JSBool
  1197. date_setSeconds(JSContext *cx, uintN argc, jsval *vp)
  1198. {
  1199. return date_makeTime(cx, 2, JS_TRUE, argc, vp);
  1200. }
  1201. static JSBool
  1202. date_setUTCSeconds(JSContext *cx, uintN argc, jsval *vp)
  1203. {
  1204. return date_makeTime(cx, 2, JS_FALSE, argc, vp);
  1205. }
  1206. static JSBool
  1207. date_setMinutes(JSContext *cx, uintN argc, jsval *vp)
  1208. {
  1209. return date_makeTime(cx, 3, JS_TRUE, argc, vp);
  1210. }
  1211. static JSBool
  1212. date_setUTCMinutes(JSContext *cx, uintN argc, jsval *vp)
  1213. {
  1214. return date_makeTime(cx, 3, JS_FALSE, argc, vp);
  1215. }
  1216. static JSBool
  1217. date_setHours(JSContext *cx, uintN argc, jsval *vp)
  1218. {
  1219. return date_makeTime(cx, 4, JS_TRUE, argc, vp);
  1220. }
  1221. static JSBool
  1222. date_setUTCHours(JSContext *cx, uintN argc, jsval *vp)
  1223. {
  1224. return date_makeTime(cx, 4, JS_FALSE, argc, vp);
  1225. }
  1226. static JSBool
  1227. date_makeDate(JSContext *cx, uintN maxargs, JSBool local, uintN argc, jsval *vp)
  1228. {
  1229. JSObject *obj;
  1230. jsval *argv;
  1231. uintN i;
  1232. jsdouble lorutime; /* local or UTC version of *date */
  1233. jsdouble args[3], *argp, *stop;
  1234. jsdouble year, month, day;
  1235. jsdouble result;
  1236. obj = JS_THIS_OBJECT(cx, vp);
  1237. if (!GetUTCTime(cx, obj, vp, &result))
  1238. return JS_FALSE;
  1239. /* see complaint about ECMA in date_MakeTime */
  1240. if (argc == 0)
  1241. return SetDateToNaN(cx, vp);
  1242. if (argc > maxargs)
  1243. argc = maxargs; /* clamp argc */
  1244. JS_ASSERT(1 <= argc && argc <= 3);
  1245. argv = vp + 2;
  1246. for (i = 0; i < argc; i++) {
  1247. args[i] = js_ValueToNumber(cx, &argv[i]);
  1248. if (JSVAL_IS_NULL(argv[i]))
  1249. return JS_FALSE;
  1250. if (!JSDOUBLE_IS_FINITE(args[i]))
  1251. return SetDateToNaN(cx, vp);
  1252. args[i] = js_DoubleToInteger(args[i]);
  1253. }
  1254. /* return NaN if date is NaN and we're not setting the year,
  1255. * If we are, use 0 as the time. */
  1256. if (!(JSDOUBLE_IS_FINITE(result))) {
  1257. if (maxargs < 3)
  1258. return js_NewNumberInRootedValue(cx, result, vp);
  1259. lorutime = +0.;
  1260. } else {
  1261. lorutime = local ? LocalTime(result) : result;
  1262. }
  1263. argp = args;
  1264. stop = argp + argc;
  1265. if (maxargs >= 3 && argp < stop)
  1266. year = *argp++;
  1267. else
  1268. year = YearFromTime(lorutime);
  1269. if (maxargs >= 2 && argp < stop)
  1270. month = *argp++;
  1271. else
  1272. month = MonthFromTime(lorutime);
  1273. if (maxargs >= 1 && argp < stop)
  1274. day = *argp++;
  1275. else
  1276. day = DateFromTime(lorutime);
  1277. day = MakeDay(year, month, day); /* day within year */
  1278. result = MakeDate(day, TimeWithinDay(lorutime));
  1279. if (local)
  1280. result = UTC(result);
  1281. result = TIMECLIP(result);
  1282. if (!SetUTCTime(cx, obj, NULL, result))
  1283. return JS_FALSE;
  1284. return js_NewNumberInRootedValue(cx, result, vp);
  1285. }
  1286. static JSBool
  1287. date_setDate(JSContext *cx, uintN argc, jsval *vp)
  1288. {
  1289. return date_makeDate(cx, 1, JS_TRUE, argc, vp);
  1290. }
  1291. static JSBool
  1292. date_setUTCDate(JSContext *cx, uintN argc, jsval *vp)
  1293. {
  1294. return date_makeDate(cx, 1, JS_FALSE, argc, vp);
  1295. }
  1296. static JSBool
  1297. date_setMonth(JSContext *cx, uintN argc, jsval *vp)
  1298. {
  1299. return date_makeDate(cx, 2, JS_TRUE, argc, vp);
  1300. }
  1301. static JSBool
  1302. date_setUTCMonth(JSContext *cx, uintN argc, jsval *vp)
  1303. {
  1304. return date_makeDate(cx, 2, JS_FALSE, argc, vp);
  1305. }
  1306. static JSBool
  1307. date_setFullYear(JSContext *cx, uintN argc, jsval *vp)
  1308. {
  1309. return date_makeDate(cx, 3, JS_TRUE, argc, vp);
  1310. }
  1311. static JSBool
  1312. date_setUTCFullYear(JSContext *cx, uintN argc, jsval *vp)
  1313. {
  1314. return date_makeDate(cx, 3, JS_FALSE, argc, vp);
  1315. }
  1316. static JSBool
  1317. date_setYear(JSContext *cx, uintN argc, jsval *vp)
  1318. {
  1319. JSObject *obj;
  1320. jsdouble t;
  1321. jsdouble year;
  1322. jsdouble day;
  1323. jsdouble result;
  1324. obj = JS_THIS_OBJECT(cx, vp);
  1325. if (!GetUTCTime(cx, obj, vp, &result))
  1326. return JS_FALSE;
  1327. if (argc == 0)
  1328. return SetDateToNaN(cx, vp);
  1329. year = js_ValueToNumber(cx, &vp[2]);
  1330. if (JSVAL_IS_NULL(vp[2]))
  1331. return JS_FALSE;
  1332. if (!JSDOUBLE_IS_FINITE(year))
  1333. return SetDateToNaN(cx, vp);
  1334. year = js_DoubleToInteger(year);
  1335. if (!JSDOUBLE_IS_FINITE(result)) {
  1336. t = +0.0;
  1337. } else {
  1338. t = LocalTime(result);
  1339. }
  1340. if (year >= 0 && year <= 99)
  1341. year += 1900;
  1342. day = MakeDay(year, MonthFromTime(t), DateFromTime(t));
  1343. result = MakeDate(day, TimeWithinDay(t));
  1344. result = UTC(result);
  1345. result = TIMECLIP(result);
  1346. if (!SetUTCTime(cx, obj, NULL, result))
  1347. return JS_FALSE;
  1348. return js_NewNumberInRootedValue(cx, result, vp);
  1349. }
  1350. /* constants for toString, toUTCString */
  1351. static char js_NaN_date_str[] = "Invalid Date";
  1352. static const char* days[] =
  1353. {
  1354. "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
  1355. };
  1356. static const char* months[] =
  1357. {
  1358. "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  1359. };
  1360. // Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
  1361. // requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
  1362. static void
  1363. print_gmt_string(char* buf, size_t size, jsdouble utctime)
  1364. {
  1365. JS_snprintf(buf, size, "%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
  1366. days[WeekDay(utctime)],
  1367. DateFromTime(utctime),
  1368. months[MonthFromTime(utctime)],
  1369. YearFromTime(utctime),
  1370. HourFromTime(utctime),
  1371. MinFromTime(utctime),
  1372. SecFromTime(utctime));
  1373. }
  1374. static void
  1375. print_iso_string(char* buf, size_t size, jsdouble utctime)
  1376. {
  1377. JS_snprintf(buf, size, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2d.%.3dZ",
  1378. YearFromTime(utctime),
  1379. MonthFromTime(utctime) + 1,
  1380. DateFromTime(utctime),
  1381. HourFromTime(utctime),
  1382. MinFromTime(utctime),
  1383. SecFromTime(utctime),
  1384. msFromTime(utctime));
  1385. }
  1386. static JSBool
  1387. date_utc_format(JSContext *cx, jsval *vp,
  1388. void (*printFunc)(char*, size_t, jsdouble))
  1389. {
  1390. char buf[100];
  1391. JSString *str;
  1392. jsdouble utctime;
  1393. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
  1394. return JS_FALSE;
  1395. if (!JSDOUBLE_IS_FINITE(utctime)) {
  1396. JS_snprintf(buf, sizeof buf, js_NaN_date_str);
  1397. } else {
  1398. (*printFunc)(buf, sizeof buf, utctime);
  1399. }
  1400. str = JS_NewStringCopyZ(cx, buf);
  1401. if (!str)
  1402. return JS_FALSE;
  1403. *vp = STRING_TO_JSVAL(str);
  1404. return JS_TRUE;
  1405. }
  1406. static JSBool
  1407. date_toGMTString(JSContext *cx, uintN argc, jsval *vp)
  1408. {
  1409. return date_utc_format(cx, vp, print_gmt_string);
  1410. }
  1411. static JSBool
  1412. date_toISOString(JSContext *cx, uintN argc, jsval *vp)
  1413. {
  1414. return date_utc_format(cx, vp, print_iso_string);
  1415. }
  1416. /* for Date.toLocaleString; interface to PRMJTime date struct.
  1417. */
  1418. static void
  1419. new_explode(jsdouble timeval, PRMJTime *split)
  1420. {
  1421. jsint year = YearFromTime(timeval);
  1422. split->tm_usec = (int32) msFromTime(timeval) * 1000;
  1423. split->tm_sec = (int8) SecFromTime(timeval);
  1424. split->tm_min = (int8) MinFromTime(timeval);
  1425. split->tm_hour = (int8) HourFromTime(timeval);
  1426. split->tm_mday = (int8) DateFromTime(timeval);
  1427. split->tm_mon = (int8) MonthFromTime(timeval);
  1428. split->tm_wday = (int8) WeekDay(timeval);
  1429. split->tm_year = year;
  1430. split->tm_yday = (int16) DayWithinYear(timeval, year);
  1431. /* not sure how this affects things, but it doesn't seem
  1432. to matter. */
  1433. split->tm_isdst = (DaylightSavingTA(timeval) != 0);
  1434. }
  1435. typedef enum formatspec {
  1436. FORMATSPEC_FULL, FORMATSPEC_DATE, FORMATSPEC_TIME
  1437. } formatspec;
  1438. /* helper function */
  1439. static JSBool
  1440. date_format(JSContext *cx, jsdouble date, formatspec format, jsval *rval)
  1441. {
  1442. char buf[100];
  1443. JSString *str;
  1444. char tzbuf[100];
  1445. JSBool usetz;
  1446. size_t i, tzlen;
  1447. PRMJTime split;
  1448. if (!JSDOUBLE_IS_FINITE(date)) {
  1449. JS_snprintf(buf, sizeof buf, js_NaN_date_str);
  1450. } else {
  1451. jsdouble local = LocalTime(date);
  1452. /* offset from GMT in minutes. The offset includes daylight savings,
  1453. if it applies. */
  1454. jsint minutes = (jsint) floor(AdjustTime(date) / msPerMinute);
  1455. /* map 510 minutes to 0830 hours */
  1456. intN offset = (minutes / 60) * 100 + minutes % 60;
  1457. /* print as "Wed Nov 05 19:38:03 GMT-0800 (PST) 1997" The TZA is
  1458. * printed as 'GMT-0800' rather than as 'PST' to avoid
  1459. * operating-system dependence on strftime (which
  1460. * PRMJ_FormatTimeUSEnglish calls, for %Z only.) win32 prints
  1461. * PST as 'Pacific Standard Time.' This way we always know
  1462. * what we're getting, and can parse it if we produce it.
  1463. * The OS TZA string is included as a comment.
  1464. */
  1465. /* get a timezone string from the OS to include as a
  1466. comment. */
  1467. new_explode(date, &split);
  1468. if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
  1469. /* Decide whether to use the resulting timezone string.
  1470. *
  1471. * Reject it if it contains any non-ASCII, non-alphanumeric
  1472. * characters. It's then likely in some other character
  1473. * encoding, and we probably won't display it correctly.
  1474. */
  1475. usetz = JS_TRUE;
  1476. tzlen = strlen(tzbuf);
  1477. if (tzlen > 100) {
  1478. usetz = JS_FALSE;
  1479. } else {
  1480. for (i = 0; i < tzlen; i++) {
  1481. jschar c = tzbuf[i];
  1482. if (c > 127 ||
  1483. !(isalpha(c) || isdigit(c) ||
  1484. c == ' ' || c == '(' || c == ')')) {
  1485. usetz = JS_FALSE;
  1486. }
  1487. }
  1488. }
  1489. /* Also reject it if it's not parenthesized or if it's '()'. */
  1490. if (tzbuf[0] != '(' || tzbuf[1] == ')')
  1491. usetz = JS_FALSE;
  1492. } else
  1493. usetz = JS_FALSE;
  1494. switch (format) {
  1495. case FORMATSPEC_FULL:
  1496. /*
  1497. * Avoid dependence on PRMJ_FormatTimeUSEnglish, because it
  1498. * requires a PRMJTime... which only has 16-bit years. Sub-ECMA.
  1499. */
  1500. /* Tue Oct 31 2000 09:41:40 GMT-0800 (PST) */
  1501. JS_snprintf(buf, sizeof buf,
  1502. "%s %s %.2d %.4d %.2d:%.2d:%.2d GMT%+.4d%s%s",
  1503. days[WeekDay(local)],
  1504. months[MonthFromTime(local)],
  1505. DateFromTime(local),
  1506. YearFromTime(local),
  1507. HourFromTime(local),
  1508. MinFromTime(local),
  1509. SecFromTime(local),
  1510. offset,
  1511. usetz ? " " : "",
  1512. usetz ? tzbuf : "");
  1513. break;
  1514. case FORMATSPEC_DATE:
  1515. /* Tue Oct 31 2000 */
  1516. JS_snprintf(buf, sizeof buf,
  1517. "%s %s %.2d %.4d",
  1518. days[WeekDay(local)],
  1519. months[MonthFromTime(local)],
  1520. DateFromTime(local),
  1521. YearFromTime(local));
  1522. break;
  1523. case FORMATSPEC_TIME:
  1524. /* 09:41:40 GMT-0800 (PST) */
  1525. JS_snprintf(buf, sizeof buf,
  1526. "%.2d:%.2d:%.2d GMT%+.4d%s%s",
  1527. HourFromTime(local),
  1528. MinFromTime(local),
  1529. SecFromTime(local),
  1530. offset,
  1531. usetz ? " " : "",
  1532. usetz ? tzbuf : "");
  1533. break;
  1534. }
  1535. }
  1536. str = JS_NewStringCopyZ(cx, buf);
  1537. if (!str)
  1538. return JS_FALSE;
  1539. *rval = STRING_TO_JSVAL(str);
  1540. return JS_TRUE;
  1541. }
  1542. static JSBool
  1543. date_toLocaleHelper(JSContext *cx, const char *format, jsval *vp)
  1544. {
  1545. JSObject *obj;
  1546. char buf[100];
  1547. JSString *str;
  1548. PRMJTime split;
  1549. jsdouble utctime;
  1550. obj = JS_THIS_OBJECT(cx, vp);
  1551. if (!GetUTCTime(cx, obj, vp, &utctime))
  1552. return JS_FALSE;
  1553. if (!JSDOUBLE_IS_FINITE(utctime)) {
  1554. JS_snprintf(buf, sizeof buf, js_NaN_date_str);
  1555. } else {
  1556. intN result_len;
  1557. jsdouble local = LocalTime(utctime);
  1558. new_explode(local, &split);
  1559. /* let PRMJTime format it. */
  1560. result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
  1561. /* If it failed, default to toString. */
  1562. if (result_len == 0)
  1563. return date_format(cx, utctime, FORMATSPEC_FULL, vp);
  1564. /* Hacked check against undesired 2-digit year 00/00/00 form. */
  1565. if (strcmp(format, "%x") == 0 && result_len >= 6 &&
  1566. /* Format %x means use OS settings, which may have 2-digit yr, so
  1567. hack end of 3/11/22 or 11.03.22 or 11Mar22 to use 4-digit yr...*/
  1568. !isdigit(buf[result_len - 3]) &&
  1569. isdigit(buf[result_len - 2]) && isdigit(buf[result_len - 1]) &&
  1570. /* ...but not if starts with 4-digit year, like 2022/3/11. */
  1571. !(isdigit(buf[0]) && isdigit(buf[1]) &&
  1572. isdigit(buf[2]) && isdigit(buf[3]))) {
  1573. JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
  1574. "%d", js_DateGetYear(cx, obj));
  1575. }
  1576. }
  1577. if (cx->localeCallbacks && cx->localeCallbacks->localeToUnicode)
  1578. return cx->localeCallbacks->localeToUnicode(cx, buf, vp);
  1579. str = JS_NewStringCopyZ(cx, buf);
  1580. if (!str)
  1581. return JS_FALSE;
  1582. *vp = STRING_TO_JSVAL(str);
  1583. return JS_TRUE;
  1584. }
  1585. static JSBool
  1586. date_toLocaleString(JSContext *cx, uintN argc, jsval *vp)
  1587. {
  1588. /* Use '%#c' for windows, because '%c' is
  1589. * backward-compatible and non-y2k with msvc; '%#c' requests that a
  1590. * full year be used in the result string.
  1591. */
  1592. return date_toLocaleHelper(cx,
  1593. #if defined(_WIN32) && !defined(__MWERKS__)
  1594. "%#c"
  1595. #else
  1596. "%c"
  1597. #endif
  1598. , vp);
  1599. }
  1600. static JSBool
  1601. date_toLocaleDateString(JSContext *cx, uintN argc, jsval *vp)
  1602. {
  1603. /* Use '%#x' for windows, because '%x' is
  1604. * backward-compatible and non-y2k with msvc; '%#x' requests that a
  1605. * full year be used in the result string.
  1606. */
  1607. return date_toLocaleHelper(cx,
  1608. #if defined(_WIN32) && !defined(__MWERKS__)
  1609. "%#x"
  1610. #else
  1611. "%x"
  1612. #endif
  1613. , vp);
  1614. }
  1615. static JSBool
  1616. date_toLocaleTimeString(JSContext *cx, uintN argc, jsval *vp)
  1617. {
  1618. return date_toLocaleHelper(cx, "%X", vp);
  1619. }
  1620. static JSBool
  1621. date_toLocaleFormat(JSContext *cx, uintN argc, jsval *vp)
  1622. {
  1623. JSString *fmt;
  1624. const char *fmtbytes;
  1625. if (argc == 0)
  1626. return date_toLocaleString(cx, argc, vp);
  1627. fmt = js_ValueToString(cx, vp[2]);
  1628. if (!fmt)
  1629. return JS_FALSE;
  1630. vp[2] = STRING_TO_JSVAL(fmt);
  1631. fmtbytes = js_GetStringBytes(cx, fmt);
  1632. if (!fmtbytes)
  1633. return JS_FALSE;
  1634. return date_toLocaleHelper(cx, fmtbytes, vp);
  1635. }
  1636. static JSBool
  1637. date_toTimeString(JSContext *cx, uintN argc, jsval *vp)
  1638. {
  1639. jsdouble utctime;
  1640. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
  1641. return JS_FALSE;
  1642. return date_format(cx, utctime, FORMATSPEC_TIME, vp);
  1643. }
  1644. static JSBool
  1645. date_toDateString(JSContext *cx, uintN argc, jsval *vp)
  1646. {
  1647. jsdouble utctime;
  1648. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
  1649. return JS_FALSE;
  1650. return date_format(cx, utctime, FORMATSPEC_DATE, vp);
  1651. }
  1652. #if JS_HAS_TOSOURCE
  1653. #include <string.h>
  1654. #include "jsdtoa.h"
  1655. static JSBool
  1656. date_toSource(JSContext *cx, uintN argc, jsval *vp)
  1657. {
  1658. jsdouble utctime;
  1659. char buf[DTOSTR_STANDARD_BUFFER_SIZE], *numStr, *bytes;
  1660. JSString *str;
  1661. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
  1662. return JS_FALSE;
  1663. numStr = JS_dtostr(buf, sizeof buf, DTOSTR_STANDARD, 0, utctime);
  1664. if (!numStr) {
  1665. JS_ReportOutOfMemory(cx);
  1666. return JS_FALSE;
  1667. }
  1668. bytes = JS_smprintf("(new %s(%s))", js_Date_str, numStr);
  1669. if (!bytes) {
  1670. JS_ReportOutOfMemory(cx);
  1671. return JS_FALSE;
  1672. }
  1673. str = JS_NewString(cx, bytes, strlen(bytes));
  1674. if (!str) {
  1675. free(bytes);
  1676. return JS_FALSE;
  1677. }
  1678. *vp = STRING_TO_JSVAL(str);
  1679. return JS_TRUE;
  1680. }
  1681. #endif
  1682. static JSBool
  1683. date_toString(JSContext *cx, uintN argc, jsval *vp)
  1684. {
  1685. jsdouble utctime;
  1686. if (!GetUTCTime(cx, JS_THIS_OBJECT(cx, vp), vp, &utctime))
  1687. return JS_FALSE;
  1688. return date_format(cx, utctime, FORMATSPEC_FULL, vp);
  1689. }
  1690. #ifdef JS_TRACER
  1691. static jsval FASTCALL
  1692. date_valueOf_tn(JSContext* cx, JSObject* obj, JSString* str)
  1693. {
  1694. JS_ASSERT(JS_InstanceOf(cx, obj, &js_DateClass, NULL));
  1695. jsdouble t = *JSVAL_TO_DOUBLE(obj->fslots[JSSLOT_UTC_TIME]);
  1696. JSString* number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
  1697. jsval v;
  1698. if (js_EqualStrings(str, number_str)) {
  1699. if (!js_NewNumberInRootedValue(cx, t, &v))
  1700. return JSVAL_ERROR_COOKIE;
  1701. } else {
  1702. if (!date_format(cx, t, FORMATSPEC_FULL, &v))
  1703. return JSVAL_ERROR_COOKIE;
  1704. }
  1705. return v;
  1706. }
  1707. #endif
  1708. static JSBool
  1709. date_valueOf(JSContext *cx, uintN argc, jsval *vp)
  1710. {
  1711. JSString *str, *number_str;
  1712. /* It is an error to call date_valueOf on a non-date object, but we don't
  1713. * need to check for that explicitly here because every path calls
  1714. * GetUTCTime, which does the check.
  1715. */
  1716. /* If called directly with no arguments, convert to a time number. */
  1717. if (argc == 0)
  1718. return date_getTime(cx, argc, vp);
  1719. /* Convert to number only if the hint was given, otherwise favor string. */
  1720. str = js_ValueToString(cx, vp[2]);
  1721. if (!str)
  1722. return JS_FALSE;
  1723. number_str = ATOM_TO_STRING(cx->runtime->atomState.typeAtoms[JSTYPE_NUMBER]);
  1724. if (js_EqualStrings(str, number_str))
  1725. return date_getTime(cx, argc, vp);
  1726. return date_toString(cx, argc, vp);
  1727. }
  1728. JS_DEFINE_CALLINFO_2(extern, OBJECT, js_FastNewDate, CONTEXT, OBJECT, 0, 0)
  1729. // Don't really need an argument here, but we don't support arg-less builtins
  1730. JS_DEFINE_TRCINFO_1(date_now,
  1731. (1, (static, DOUBLE, date_now_tn, CONTEXT, 0, 0)))
  1732. static JSFunctionSpec date_static_methods[] = {
  1733. JS_FN("UTC", date_UTC, MAXARGS,0),
  1734. JS_FN("parse", date_parse, 1,0),
  1735. JS_TN("now", date_now, 0,0, date_now_trcinfo),
  1736. JS_FS_END
  1737. };
  1738. JS_DEFINE_TRCINFO_1(date_valueOf,
  1739. (3, (static, JSVAL_FAIL, date_valueOf_tn, CONTEXT, THIS, STRING, 0, 0)))
  1740. static JSFunctionSpec date_methods[] = {
  1741. JS_FN("getTime", date_getTime, 0,0),
  1742. JS_FN("getTimezoneOffset", date_getTimezoneOffset, 0,0),
  1743. JS_FN("getYear", date_getYear, 0,0),
  1744. JS_FN("getFullYear", date_getFullYear, 0,0),
  1745. JS_FN("getUTCFullYear", date_getUTCFullYear, 0,0),
  1746. JS_FN("getMonth", date_getMonth, 0,0),
  1747. JS_FN("getUTCMonth", date_getUTCMonth, 0,0),
  1748. JS_FN("getDate", date_getDate, 0,0),
  1749. JS_FN("getUTCDate", date_getUTCDate, 0,0),
  1750. JS_FN("getDay", date_getDay, 0,0),
  1751. JS_FN("getUTCDay", date_getUTCDay, 0,0),
  1752. JS_FN("getHours", date_getHours, 0,0),
  1753. JS_FN("getUTCHours", date_getUTCHours, 0,0),
  1754. JS_FN("getMinutes", date_getMinutes, 0,0),
  1755. JS_FN("getUTCMinutes", date_getUTCMinutes, 0,0),
  1756. JS_FN("getSeconds", date_getUTCSeconds, 0,0),
  1757. JS_FN("getUTCSeconds", date_getUTCSeconds, 0,0),
  1758. JS_FN("getMilliseconds", date_getUTCMilliseconds, 0,0),
  1759. JS_FN("getUTCMilliseconds", date_getUTCMilliseconds, 0,0),
  1760. JS_FN("setTime", date_setTime, 1,0),
  1761. JS_FN("setYear", date_setYear, 1,0),
  1762. JS_FN("setFullYear", date_setFullYear, 3,0),
  1763. JS_FN("setUTCFullYear", date_setUTCFullYear, 3,0),
  1764. JS_FN("setMonth", date_setMonth, 2,0),
  1765. JS_FN("setUTCMonth", date_setUTCMonth, 2,0),
  1766. JS_FN("setDate", date_setDate, 1,0),
  1767. JS_FN("setUTCDate", date_setUTCDate, 1,0),
  1768. JS_FN("setHours", date_setHours, 4,0),
  1769. JS_FN("setUTCHours", date_setUTCHours, 4,0),
  1770. JS_FN("setMinutes", date_setMinutes, 3,0),
  1771. JS_FN("setUTCMinutes", date_setUTCMinutes, 3,0),
  1772. JS_FN("setSeconds", date_setSeconds, 2,0),
  1773. JS_FN("setUTCSeconds", date_setUTCSeconds, 2,0),
  1774. JS_FN("setMilliseconds", date_setMilliseconds, 1,0),
  1775. JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0),
  1776. JS_FN("toUTCString", date_toGMTString, 0,0),
  1777. JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
  1778. JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
  1779. JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
  1780. JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0),
  1781. JS_FN("toDateString", date_toDateString, 0,0),
  1782. JS_FN("toTimeString", date_toTimeString, 0,0),
  1783. JS_FN("toISOString", date_toISOString, 0,0),
  1784. JS_FN(js_toJSON_str, date_toISOString, 0,0),
  1785. #if JS_HAS_TOSOURCE
  1786. JS_FN(js_toSource_str, date_toSource, 0,0),
  1787. #endif
  1788. JS_FN(js_toString_str, date_toString, 0,0),
  1789. JS_TN(js_valueOf_str, date_valueOf, 0,0, date_valueOf_trcinfo),
  1790. JS_FS_END
  1791. };
  1792. static jsdouble *
  1793. date_constructor(JSContext *cx, JSObject* obj)
  1794. {
  1795. jsdouble *date;
  1796. date = js_NewWeaklyRootedDouble(cx, 0.0);
  1797. if (!date)
  1798. return NULL;
  1799. obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date);
  1800. obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  1801. return date;
  1802. }
  1803. JSBool
  1804. js_Date(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
  1805. {
  1806. jsdouble *date;
  1807. JSString *str;
  1808. jsdouble d;
  1809. /* Date called as function. */
  1810. if (!(cx->fp->flags & JSFRAME_CONSTRUCTING)) {
  1811. return date_format(cx, PRMJ_Now() / PRMJ_USEC_PER_MSEC,
  1812. FORMATSPEC_FULL, rval);
  1813. }
  1814. /* Date called as constructor. */
  1815. if (argc == 0) {
  1816. date = date_constructor(cx, obj);
  1817. if (!date)
  1818. return JS_FALSE;
  1819. *date = PRMJ_Now() / PRMJ_USEC_PER_MSEC;
  1820. } else if (argc == 1) {
  1821. if (!JSVAL_IS_STRING(argv[0])) {
  1822. /* the argument is a millisecond number */
  1823. d = js_ValueToNumber(cx, &argv[0]);
  1824. if (JSVAL_IS_NULL(argv[0]))
  1825. return JS_FALSE;
  1826. date = date_constructor(cx, obj);
  1827. if (!date)
  1828. return JS_FALSE;
  1829. *date = TIMECLIP(d);
  1830. } else {
  1831. /* the argument is a string; parse it. */
  1832. date = date_constructor(cx, obj);
  1833. if (!date)
  1834. return JS_FALSE;
  1835. str = js_ValueToString(cx, argv[0]);
  1836. if (!str)
  1837. return JS_FALSE;
  1838. if (!date_parseString(str, date))
  1839. *date = *cx->runtime->jsNaN;
  1840. *date = TIMECLIP(*date);
  1841. }
  1842. } else {
  1843. jsdouble *date;
  1844. jsdouble msec_time;
  1845. if (!date_msecFromArgs(cx, argc, argv, &msec_time))
  1846. return JS_FALSE;
  1847. date = date_constructor(cx, obj);
  1848. if (!date)
  1849. return JS_FALSE;
  1850. if (JSDOUBLE_IS_FINITE(msec_time)) {
  1851. msec_time = UTC(msec_time);
  1852. msec_time = TIMECLIP(msec_time);
  1853. }
  1854. *date = msec_time;
  1855. }
  1856. return JS_TRUE;
  1857. }
  1858. JS_STATIC_ASSERT(JSSLOT_PRIVATE == JSSLOT_UTC_TIME);
  1859. JS_STATIC_ASSERT(JSSLOT_UTC_TIME + 1 == JSSLOT_LOCAL_TIME);
  1860. #ifdef JS_TRACER
  1861. JSObject* FASTCALL
  1862. js_FastNewDate(JSContext* cx, JSObject* proto)
  1863. {
  1864. JS_ASSERT(JS_ON_TRACE(cx));
  1865. JSObject* obj = (JSObject*) js_NewGCThing(cx, GCX_OBJECT, sizeof(JSObject));
  1866. if (!obj)
  1867. return NULL;
  1868. JSClass* clasp = &js_DateClass;
  1869. obj->classword = jsuword(clasp);
  1870. obj->fslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto);
  1871. obj->fslots[JSSLOT_PARENT] = proto->fslots[JSSLOT_PARENT];
  1872. jsdouble* date = js_NewWeaklyRootedDouble(cx, 0.0);
  1873. if (!date)
  1874. return NULL;
  1875. *date = date_now_tn(cx);
  1876. obj->fslots[JSSLOT_UTC_TIME] = DOUBLE_TO_JSVAL(date);
  1877. obj->fslots[JSSLOT_LOCAL_TIME] = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
  1878. for (unsigned i = JSSLOT_LOCAL_TIME + 1; i != JS_INITIAL_NSLOTS; ++i)
  1879. obj->fslots[i] = JSVAL_VOID;
  1880. JS_ASSERT(!clasp->getObjectOps);
  1881. JS_ASSERT(proto->map->ops == &js_ObjectOps);
  1882. obj->map = js_HoldObjectMap(cx, proto->map);
  1883. obj->dslots = NULL;
  1884. return obj;
  1885. }
  1886. #endif
  1887. JSObject *
  1888. js_InitDateClass(JSContext *cx, JSObject *obj)
  1889. {
  1890. JSObject *proto;
  1891. jsdouble *proto_date;
  1892. /* set static LocalTZA */
  1893. LocalTZA = -(PRMJ_LocalGMTDifference() * msPerSecond);
  1894. proto = JS_InitClass(cx, obj, NULL, &js_DateClass, js_Date, MAXARGS,
  1895. NULL, date_methods, NULL, date_static_methods);
  1896. if (!proto)
  1897. return NULL;
  1898. /* Alias toUTCString with toGMTString. (ECMA B.2.6) */
  1899. if (!JS_AliasProperty(cx, proto, "toUTCString", "toGMTString"))
  1900. return NULL;
  1901. /* Set the value of the Date.prototype date to NaN */
  1902. proto_date = date_constructor(cx, proto);
  1903. if (!proto_date)
  1904. return NULL;
  1905. *proto_date = *cx->runtime->jsNaN;
  1906. return proto;
  1907. }
  1908. JS_FRIEND_API(JSObject *)
  1909. js_NewDateObjectMsec(JSContext *cx, jsdouble msec_time)
  1910. {
  1911. JSObject *obj;
  1912. jsdouble *date;
  1913. obj = js_NewObject(cx, &js_DateClass, NULL, NULL, 0);
  1914. if (!obj)
  1915. return NULL;
  1916. date = date_constructor(cx, obj);
  1917. if (!date)
  1918. return NULL;
  1919. *date = msec_time;
  1920. return obj;
  1921. }
  1922. JS_FRIEND_API(JSObject *)
  1923. js_NewDateObject(JSContext* cx, int year, int mon, int mday,
  1924. int hour, int min, int sec)
  1925. {
  1926. JSObject *obj;
  1927. jsdouble msec_time;
  1928. JS_ASSERT(mon < 12);
  1929. msec_time = date_msecFromDate(year, mon, mday, hour, min, sec, 0);
  1930. obj = js_NewDateObjectMsec(cx, UTC(msec_time));
  1931. return obj;
  1932. }
  1933. JS_FRIEND_API(JSBool)
  1934. js_DateIsValid(JSContext *cx, JSObject* obj)
  1935. {
  1936. jsdouble utctime;
  1937. return GetUTCTime(cx, obj, NULL, &utctime) && !JSDOUBLE_IS_NaN(utctime);
  1938. }
  1939. JS_FRIEND_API(int)
  1940. js_DateGetYear(JSContext *cx, JSObject* obj)
  1941. {
  1942. jsdouble localtime;
  1943. /* Preserve legacy API behavior of returning 0 for invalid dates. */
  1944. if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
  1945. JSDOUBLE_IS_NaN(localtime)) {
  1946. return 0;
  1947. }
  1948. return (int) YearFromTime(localtime);
  1949. }
  1950. JS_FRIEND_API(int)
  1951. js_DateGetMonth(JSContext *cx, JSObject* obj)
  1952. {
  1953. jsdouble localtime;
  1954. if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
  1955. JSDOUBLE_IS_NaN(localtime)) {
  1956. return 0;
  1957. }
  1958. return (int) MonthFromTime(localtime);
  1959. }
  1960. JS_FRIEND_API(int)
  1961. js_DateGetDate(JSContext *cx, JSObject* obj)
  1962. {
  1963. jsdouble localtime;
  1964. if (!GetAndCacheLocalTime(cx, obj, NULL, &localtime) ||
  1965. JSDOUBLE_IS_NaN(localtime)) {
  1966. return 0;
  1967. }
  1968. return (int) DateFromTime(localtime);
  1969. }