1 | #include "jsi.h" |
2 | #include "jsvalue.h" |
3 | #include "jsbuiltin.h" |
4 | |
5 | #include <time.h> |
6 | |
7 | #if defined(__unix__) || defined(__APPLE__) |
8 | #include <sys/time.h> |
9 | #elif defined(_WIN32) |
10 | #include <sys/timeb.h> |
11 | #endif |
12 | |
13 | #define js_optnumber(J,I,V) (js_isdefined(J,I) ? js_tonumber(J,I) : V) |
14 | |
15 | static double Now(void) |
16 | { |
17 | #if defined(__unix__) || defined(__APPLE__) |
18 | struct timeval tv; |
19 | gettimeofday(&tv, NULL); |
20 | return floor(tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0); |
21 | #elif defined(_WIN32) |
22 | struct _timeb tv; |
23 | _ftime(&tv); |
24 | return tv.time * 1000.0 + tv.millitm; |
25 | #else |
26 | return time(NULL) * 1000.0; |
27 | #endif |
28 | } |
29 | |
30 | static double LocalTZA(void) |
31 | { |
32 | static int once = 1; |
33 | static double tza = 0; |
34 | if (once) { |
35 | time_t now = time(NULL); |
36 | time_t utc = mktime(gmtime(&now)); |
37 | time_t loc = mktime(localtime(&now)); |
38 | tza = (loc - utc) * 1000; |
39 | once = 0; |
40 | } |
41 | return tza; |
42 | } |
43 | |
44 | static double DaylightSavingTA(double t) |
45 | { |
46 | return 0; /* TODO */ |
47 | } |
48 | |
49 | /* Helpers from the ECMA 262 specification */ |
50 | |
51 | #define HoursPerDay 24.0 |
52 | #define MinutesPerDay (HoursPerDay * MinutesPerHour) |
53 | #define MinutesPerHour 60.0 |
54 | #define SecondsPerDay (MinutesPerDay * SecondsPerMinute) |
55 | #define SecondsPerHour (MinutesPerHour * SecondsPerMinute) |
56 | #define SecondsPerMinute 60.0 |
57 | |
58 | #define msPerDay (SecondsPerDay * msPerSecond) |
59 | #define msPerHour (SecondsPerHour * msPerSecond) |
60 | #define msPerMinute (SecondsPerMinute * msPerSecond) |
61 | #define msPerSecond 1000.0 |
62 | |
63 | static double pmod(double x, double y) |
64 | { |
65 | x = fmod(x, y); |
66 | if (x < 0) |
67 | x += y; |
68 | return x; |
69 | } |
70 | |
71 | static int Day(double t) |
72 | { |
73 | return floor(t / msPerDay); |
74 | } |
75 | |
76 | static double TimeWithinDay(double t) |
77 | { |
78 | return pmod(t, msPerDay); |
79 | } |
80 | |
81 | static int DaysInYear(int y) |
82 | { |
83 | return y % 4 == 0 && (y % 100 || (y % 400 == 0)) ? 366 : 365; |
84 | } |
85 | |
86 | static int DayFromYear(int y) |
87 | { |
88 | return 365 * (y - 1970) + |
89 | floor((y - 1969) / 4.0) - |
90 | floor((y - 1901) / 100.0) + |
91 | floor((y - 1601) / 400.0); |
92 | } |
93 | |
94 | static double TimeFromYear(int y) |
95 | { |
96 | return DayFromYear(y) * msPerDay; |
97 | } |
98 | |
99 | static int YearFromTime(double t) |
100 | { |
101 | int y = floor(t / (msPerDay * 365.2425)) + 1970; |
102 | double t2 = TimeFromYear(y); |
103 | if (t2 > t) |
104 | --y; |
105 | else if (t2 + msPerDay * DaysInYear(y) <= t) |
106 | ++y; |
107 | return y; |
108 | } |
109 | |
110 | static int InLeapYear(int t) |
111 | { |
112 | return DaysInYear(YearFromTime(t)) == 366; |
113 | } |
114 | |
115 | static int DayWithinYear(double t) |
116 | { |
117 | return Day(t) - DayFromYear(YearFromTime(t)); |
118 | } |
119 | |
120 | static int MonthFromTime(double t) |
121 | { |
122 | int day = DayWithinYear(t); |
123 | int leap = InLeapYear(t); |
124 | if (day < 31) return 0; |
125 | if (day < 59 + leap) return 1; |
126 | if (day < 90 + leap) return 2; |
127 | if (day < 120 + leap) return 3; |
128 | if (day < 151 + leap) return 4; |
129 | if (day < 181 + leap) return 5; |
130 | if (day < 212 + leap) return 6; |
131 | if (day < 243 + leap) return 7; |
132 | if (day < 273 + leap) return 8; |
133 | if (day < 304 + leap) return 9; |
134 | if (day < 334 + leap) return 10; |
135 | return 11; |
136 | } |
137 | |
138 | static int DateFromTime(double t) |
139 | { |
140 | int day = DayWithinYear(t); |
141 | int leap = InLeapYear(t); |
142 | switch (MonthFromTime(t)) { |
143 | case 0: return day + 1; |
144 | case 1: return day - 30; |
145 | case 2: return day - 58 - leap; |
146 | case 3: return day - 89 - leap; |
147 | case 4: return day - 119 - leap; |
148 | case 5: return day - 150 - leap; |
149 | case 6: return day - 180 - leap; |
150 | case 7: return day - 211 - leap; |
151 | case 8: return day - 242 - leap; |
152 | case 9: return day - 272 - leap; |
153 | case 10: return day - 303 - leap; |
154 | default : return day - 333 - leap; |
155 | } |
156 | } |
157 | |
158 | static int WeekDay(double t) |
159 | { |
160 | return pmod(Day(t) + 4, 7); |
161 | } |
162 | |
163 | static double LocalTime(double utc) |
164 | { |
165 | return utc + LocalTZA() + DaylightSavingTA(utc); |
166 | } |
167 | |
168 | static double UTC(double loc) |
169 | { |
170 | return loc - LocalTZA() - DaylightSavingTA(loc - LocalTZA()); |
171 | } |
172 | |
173 | static int HourFromTime(double t) |
174 | { |
175 | return pmod(floor(t / msPerHour), HoursPerDay); |
176 | } |
177 | |
178 | static int MinFromTime(double t) |
179 | { |
180 | return pmod(floor(t / msPerMinute), MinutesPerHour); |
181 | } |
182 | |
183 | static int SecFromTime(double t) |
184 | { |
185 | return pmod(floor(t / msPerSecond), SecondsPerMinute); |
186 | } |
187 | |
188 | static int msFromTime(double t) |
189 | { |
190 | return pmod(t, msPerSecond); |
191 | } |
192 | |
193 | static double MakeTime(double hour, double min, double sec, double ms) |
194 | { |
195 | return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms; |
196 | } |
197 | |
198 | static double MakeDay(double y, double m, double date) |
199 | { |
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 const double firstDayOfMonth[2][12] = { |
205 | {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}, |
206 | {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335} |
207 | }; |
208 | |
209 | double yd, md; |
210 | int im; |
211 | |
212 | y += floor(m / 12); |
213 | m = pmod(m, 12); |
214 | |
215 | im = (int)m; |
216 | if (im < 0 || im >= 12) |
217 | return NAN; |
218 | |
219 | yd = floor(TimeFromYear(y) / msPerDay); |
220 | md = firstDayOfMonth[InLeapYear(y)][im]; |
221 | |
222 | return yd + md + date - 1; |
223 | } |
224 | |
225 | static double MakeDate(double day, double time) |
226 | { |
227 | return day * msPerDay + time; |
228 | } |
229 | |
230 | static double TimeClip(double t) |
231 | { |
232 | if (!isfinite(t)) |
233 | return NAN; |
234 | if (fabs(t) > 8.64e15) |
235 | return NAN; |
236 | return t < 0 ? -floor(-t) : floor(t); |
237 | } |
238 | |
239 | static int toint(const char **sp, int w, int *v) |
240 | { |
241 | const char *s = *sp; |
242 | *v = 0; |
243 | while (w--) { |
244 | if (*s < '0' || *s > '9') |
245 | return 0; |
246 | *v = *v * 10 + (*s++ - '0'); |
247 | } |
248 | *sp = s; |
249 | return 1; |
250 | } |
251 | |
252 | static double parseDateTime(const char *s) |
253 | { |
254 | int y = 1970, m = 1, d = 1, H = 0, M = 0, S = 0, ms = 0; |
255 | int tza = 0; |
256 | double t; |
257 | |
258 | /* Parse ISO 8601 formatted date and time: */ |
259 | /* YYYY("-"MM("-"DD)?)?("T"HH":"mm(":"ss("."sss)?)?("Z"|[+-]HH(":"mm)?)?)? */ |
260 | |
261 | if (!toint(&s, 4, &y)) return NAN; |
262 | if (*s == '-') { |
263 | s += 1; |
264 | if (!toint(&s, 2, &m)) return NAN; |
265 | if (*s == '-') { |
266 | s += 1; |
267 | if (!toint(&s, 2, &d)) return NAN; |
268 | } |
269 | } |
270 | |
271 | if (*s == 'T') { |
272 | s += 1; |
273 | if (!toint(&s, 2, &H)) return NAN; |
274 | if (*s != ':') return NAN; |
275 | s += 1; |
276 | if (!toint(&s, 2, &M)) return NAN; |
277 | if (*s == ':') { |
278 | s += 1; |
279 | if (!toint(&s, 2, &S)) return NAN; |
280 | if (*s == '.') { |
281 | s += 1; |
282 | if (!toint(&s, 3, &ms)) return NAN; |
283 | } |
284 | } |
285 | if (*s == 'Z') { |
286 | s += 1; |
287 | tza = 0; |
288 | } else if (*s == '+' || *s == '-') { |
289 | int tzh = 0, tzm = 0; |
290 | int tzs = *s == '+' ? 1 : -1; |
291 | s += 1; |
292 | if (!toint(&s, 2, &tzh)) return NAN; |
293 | if (*s == ':') { |
294 | s += 1; |
295 | if (!toint(&s, 2, &tzm)) return NAN; |
296 | } |
297 | if (tzh > 23 || tzm > 59) return NAN; |
298 | tza = tzs * (tzh * msPerHour + tzm * msPerMinute); |
299 | } else { |
300 | tza = LocalTZA(); |
301 | } |
302 | } |
303 | |
304 | if (*s) return NAN; |
305 | |
306 | if (m < 1 || m > 12) return NAN; |
307 | if (d < 1 || d > 31) return NAN; |
308 | if (H < 0 || H > 24) return NAN; |
309 | if (M < 0 || M > 59) return NAN; |
310 | if (S < 0 || S > 59) return NAN; |
311 | if (ms < 0 || ms > 999) return NAN; |
312 | if (H == 24 && (M != 0 || S != 0 || ms != 0)) return NAN; |
313 | |
314 | /* TODO: DaylightSavingTA on local times */ |
315 | t = MakeDate(MakeDay(y, m-1, d), MakeTime(H, M, S, ms)); |
316 | return t - tza; |
317 | } |
318 | |
319 | /* date formatting */ |
320 | |
321 | static char *fmtdate(char *buf, double t) |
322 | { |
323 | int y = YearFromTime(t); |
324 | int m = MonthFromTime(t); |
325 | int d = DateFromTime(t); |
326 | if (!isfinite(t)) |
327 | return "Invalid Date" ; |
328 | sprintf(buf, "%04d-%02d-%02d" , y, m+1, d); |
329 | return buf; |
330 | } |
331 | |
332 | static char *fmttime(char *buf, double t, double tza) |
333 | { |
334 | int H = HourFromTime(t); |
335 | int M = MinFromTime(t); |
336 | int S = SecFromTime(t); |
337 | int ms = msFromTime(t); |
338 | int tzh = HourFromTime(fabs(tza)); |
339 | int tzm = MinFromTime(fabs(tza)); |
340 | if (!isfinite(t)) |
341 | return "Invalid Date" ; |
342 | if (tza == 0) |
343 | sprintf(buf, "%02d:%02d:%02d.%03dZ" , H, M, S, ms); |
344 | else if (tza < 0) |
345 | sprintf(buf, "%02d:%02d:%02d.%03d-%02d:%02d" , H, M, S, ms, tzh, tzm); |
346 | else |
347 | sprintf(buf, "%02d:%02d:%02d.%03d+%02d:%02d" , H, M, S, ms, tzh, tzm); |
348 | return buf; |
349 | } |
350 | |
351 | static char *fmtdatetime(char *buf, double t, double tza) |
352 | { |
353 | char dbuf[20], tbuf[20]; |
354 | if (!isfinite(t)) |
355 | return "Invalid Date" ; |
356 | fmtdate(dbuf, t); |
357 | fmttime(tbuf, t, tza); |
358 | sprintf(buf, "%sT%s" , dbuf, tbuf); |
359 | return buf; |
360 | } |
361 | |
362 | /* Date functions */ |
363 | |
364 | static double js_todate(js_State *J, int idx) |
365 | { |
366 | js_Object *self = js_toobject(J, idx); |
367 | if (self->type != JS_CDATE) |
368 | js_typeerror(J, "not a date" ); |
369 | return self->u.number; |
370 | } |
371 | |
372 | static void js_setdate(js_State *J, int idx, double t) |
373 | { |
374 | js_Object *self = js_toobject(J, idx); |
375 | if (self->type != JS_CDATE) |
376 | js_typeerror(J, "not a date" ); |
377 | self->u.number = TimeClip(t); |
378 | js_pushnumber(J, self->u.number); |
379 | } |
380 | |
381 | static void D_parse(js_State *J) |
382 | { |
383 | double t = parseDateTime(js_tostring(J, 1)); |
384 | js_pushnumber(J, t); |
385 | } |
386 | |
387 | static void D_UTC(js_State *J) |
388 | { |
389 | double y, m, d, H, M, S, ms, t; |
390 | y = js_tonumber(J, 1); |
391 | if (y < 100) y += 1900; |
392 | m = js_tonumber(J, 2); |
393 | d = js_optnumber(J, 3, 1); |
394 | H = js_optnumber(J, 4, 0); |
395 | M = js_optnumber(J, 5, 0); |
396 | S = js_optnumber(J, 6, 0); |
397 | ms = js_optnumber(J, 7, 0); |
398 | t = MakeDate(MakeDay(y, m, d), MakeTime(H, M, S, ms)); |
399 | t = TimeClip(t); |
400 | js_pushnumber(J, t); |
401 | } |
402 | |
403 | static void D_now(js_State *J) |
404 | { |
405 | js_pushnumber(J, Now()); |
406 | } |
407 | |
408 | static void jsB_Date(js_State *J) |
409 | { |
410 | char buf[64]; |
411 | js_pushstring(J, fmtdatetime(buf, LocalTime(Now()), LocalTZA())); |
412 | } |
413 | |
414 | static void jsB_new_Date(js_State *J) |
415 | { |
416 | int top = js_gettop(J); |
417 | js_Object *obj; |
418 | double t; |
419 | |
420 | if (top == 1) |
421 | t = Now(); |
422 | else if (top == 2) { |
423 | js_toprimitive(J, 1, JS_HNONE); |
424 | if (js_isstring(J, 1)) |
425 | t = parseDateTime(js_tostring(J, 1)); |
426 | else |
427 | t = TimeClip(js_tonumber(J, 1)); |
428 | } else { |
429 | double y, m, d, H, M, S, ms; |
430 | y = js_tonumber(J, 1); |
431 | if (y < 100) y += 1900; |
432 | m = js_tonumber(J, 2); |
433 | d = js_optnumber(J, 3, 1); |
434 | H = js_optnumber(J, 4, 0); |
435 | M = js_optnumber(J, 5, 0); |
436 | S = js_optnumber(J, 6, 0); |
437 | ms = js_optnumber(J, 7, 0); |
438 | t = MakeDate(MakeDay(y, m, d), MakeTime(H, M, S, ms)); |
439 | t = TimeClip(UTC(t)); |
440 | } |
441 | |
442 | obj = jsV_newobject(J, JS_CDATE, J->Date_prototype); |
443 | obj->u.number = t; |
444 | |
445 | js_pushobject(J, obj); |
446 | } |
447 | |
448 | static void Dp_valueOf(js_State *J) |
449 | { |
450 | double t = js_todate(J, 0); |
451 | js_pushnumber(J, t); |
452 | } |
453 | |
454 | static void Dp_toString(js_State *J) |
455 | { |
456 | char buf[64]; |
457 | double t = js_todate(J, 0); |
458 | js_pushstring(J, fmtdatetime(buf, LocalTime(t), LocalTZA())); |
459 | } |
460 | |
461 | static void Dp_toDateString(js_State *J) |
462 | { |
463 | char buf[64]; |
464 | double t = js_todate(J, 0); |
465 | js_pushstring(J, fmtdate(buf, LocalTime(t))); |
466 | } |
467 | |
468 | static void Dp_toTimeString(js_State *J) |
469 | { |
470 | char buf[64]; |
471 | double t = js_todate(J, 0); |
472 | js_pushstring(J, fmttime(buf, LocalTime(t), LocalTZA())); |
473 | } |
474 | |
475 | static void Dp_toUTCString(js_State *J) |
476 | { |
477 | char buf[64]; |
478 | double t = js_todate(J, 0); |
479 | js_pushstring(J, fmtdatetime(buf, t, 0)); |
480 | } |
481 | |
482 | static void Dp_toISOString(js_State *J) |
483 | { |
484 | char buf[64]; |
485 | double t = js_todate(J, 0); |
486 | if (!isfinite(t)) |
487 | js_rangeerror(J, "invalid date" ); |
488 | js_pushstring(J, fmtdatetime(buf, t, 0)); |
489 | } |
490 | |
491 | static void Dp_getFullYear(js_State *J) |
492 | { |
493 | double t = js_todate(J, 0); |
494 | js_pushnumber(J, YearFromTime(LocalTime(t))); |
495 | } |
496 | |
497 | static void Dp_getMonth(js_State *J) |
498 | { |
499 | double t = js_todate(J, 0); |
500 | js_pushnumber(J, MonthFromTime(LocalTime(t))); |
501 | } |
502 | |
503 | static void Dp_getDate(js_State *J) |
504 | { |
505 | double t = js_todate(J, 0); |
506 | js_pushnumber(J, DateFromTime(LocalTime(t))); |
507 | } |
508 | |
509 | static void Dp_getDay(js_State *J) |
510 | { |
511 | double t = js_todate(J, 0); |
512 | js_pushnumber(J, WeekDay(LocalTime(t))); |
513 | } |
514 | |
515 | static void Dp_getHours(js_State *J) |
516 | { |
517 | double t = js_todate(J, 0); |
518 | js_pushnumber(J, HourFromTime(LocalTime(t))); |
519 | } |
520 | |
521 | static void Dp_getMinutes(js_State *J) |
522 | { |
523 | double t = js_todate(J, 0); |
524 | js_pushnumber(J, MinFromTime(LocalTime(t))); |
525 | } |
526 | |
527 | static void Dp_getSeconds(js_State *J) |
528 | { |
529 | double t = js_todate(J, 0); |
530 | js_pushnumber(J, SecFromTime(LocalTime(t))); |
531 | } |
532 | |
533 | static void Dp_getMilliseconds(js_State *J) |
534 | { |
535 | double t = js_todate(J, 0); |
536 | js_pushnumber(J, msFromTime(LocalTime(t))); |
537 | } |
538 | |
539 | static void Dp_getUTCFullYear(js_State *J) |
540 | { |
541 | double t = js_todate(J, 0); |
542 | js_pushnumber(J, YearFromTime(t)); |
543 | } |
544 | |
545 | static void Dp_getUTCMonth(js_State *J) |
546 | { |
547 | double t = js_todate(J, 0); |
548 | js_pushnumber(J, MonthFromTime(t)); |
549 | } |
550 | |
551 | static void Dp_getUTCDate(js_State *J) |
552 | { |
553 | double t = js_todate(J, 0); |
554 | js_pushnumber(J, DateFromTime(t)); |
555 | } |
556 | |
557 | static void Dp_getUTCDay(js_State *J) |
558 | { |
559 | double t = js_todate(J, 0); |
560 | js_pushnumber(J, WeekDay(t)); |
561 | } |
562 | |
563 | static void Dp_getUTCHours(js_State *J) |
564 | { |
565 | double t = js_todate(J, 0); |
566 | js_pushnumber(J, HourFromTime(t)); |
567 | } |
568 | |
569 | static void Dp_getUTCMinutes(js_State *J) |
570 | { |
571 | double t = js_todate(J, 0); |
572 | js_pushnumber(J, MinFromTime(t)); |
573 | } |
574 | |
575 | static void Dp_getUTCSeconds(js_State *J) |
576 | { |
577 | double t = js_todate(J, 0); |
578 | js_pushnumber(J, SecFromTime(t)); |
579 | } |
580 | |
581 | static void Dp_getUTCMilliseconds(js_State *J) |
582 | { |
583 | double t = js_todate(J, 0); |
584 | js_pushnumber(J, msFromTime(t)); |
585 | } |
586 | |
587 | static void Dp_getTimezoneOffset(js_State *J) |
588 | { |
589 | double t = js_todate(J, 0); |
590 | js_pushnumber(J, (t - LocalTime(t)) / msPerMinute); |
591 | } |
592 | |
593 | static void Dp_setTime(js_State *J) |
594 | { |
595 | js_setdate(J, 0, js_tonumber(J, 1)); |
596 | } |
597 | |
598 | static void Dp_setMilliseconds(js_State *J) |
599 | { |
600 | double t = LocalTime(js_todate(J, 0)); |
601 | double h = HourFromTime(t); |
602 | double m = MinFromTime(t); |
603 | double s = SecFromTime(t); |
604 | double ms = js_tonumber(J, 1); |
605 | js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); |
606 | } |
607 | |
608 | static void Dp_setSeconds(js_State *J) |
609 | { |
610 | double t = LocalTime(js_todate(J, 0)); |
611 | double h = HourFromTime(t); |
612 | double m = MinFromTime(t); |
613 | double s = js_tonumber(J, 1); |
614 | double ms = js_optnumber(J, 2, msFromTime(t)); |
615 | js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); |
616 | } |
617 | |
618 | static void Dp_setMinutes(js_State *J) |
619 | { |
620 | double t = LocalTime(js_todate(J, 0)); |
621 | double h = HourFromTime(t); |
622 | double m = js_tonumber(J, 1); |
623 | double s = js_optnumber(J, 2, SecFromTime(t)); |
624 | double ms = js_optnumber(J, 3, msFromTime(t)); |
625 | js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); |
626 | } |
627 | |
628 | static void Dp_setHours(js_State *J) |
629 | { |
630 | double t = LocalTime(js_todate(J, 0)); |
631 | double h = js_tonumber(J, 1); |
632 | double m = js_optnumber(J, 2, MinFromTime(t)); |
633 | double s = js_optnumber(J, 3, SecFromTime(t)); |
634 | double ms = js_optnumber(J, 4, msFromTime(t)); |
635 | js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms)))); |
636 | } |
637 | |
638 | static void Dp_setDate(js_State *J) |
639 | { |
640 | double t = LocalTime(js_todate(J, 0)); |
641 | double y = YearFromTime(t); |
642 | double m = MonthFromTime(t); |
643 | double d = js_tonumber(J, 1); |
644 | js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); |
645 | } |
646 | |
647 | static void Dp_setMonth(js_State *J) |
648 | { |
649 | double t = LocalTime(js_todate(J, 0)); |
650 | double y = YearFromTime(t); |
651 | double m = js_tonumber(J, 1); |
652 | double d = js_optnumber(J, 3, DateFromTime(t)); |
653 | js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); |
654 | } |
655 | |
656 | static void Dp_setFullYear(js_State *J) |
657 | { |
658 | double t = LocalTime(js_todate(J, 0)); |
659 | double y = js_tonumber(J, 1); |
660 | double m = js_optnumber(J, 2, MonthFromTime(t)); |
661 | double d = js_optnumber(J, 3, DateFromTime(t)); |
662 | js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t)))); |
663 | } |
664 | |
665 | static void Dp_setUTCMilliseconds(js_State *J) |
666 | { |
667 | double t = js_todate(J, 0); |
668 | double h = HourFromTime(t); |
669 | double m = MinFromTime(t); |
670 | double s = SecFromTime(t); |
671 | double ms = js_tonumber(J, 1); |
672 | js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); |
673 | } |
674 | |
675 | static void Dp_setUTCSeconds(js_State *J) |
676 | { |
677 | double t = js_todate(J, 0); |
678 | double h = HourFromTime(t); |
679 | double m = MinFromTime(t); |
680 | double s = js_tonumber(J, 1); |
681 | double ms = js_optnumber(J, 2, msFromTime(t)); |
682 | js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); |
683 | } |
684 | |
685 | static void Dp_setUTCMinutes(js_State *J) |
686 | { |
687 | double t = js_todate(J, 0); |
688 | double h = HourFromTime(t); |
689 | double m = js_tonumber(J, 1); |
690 | double s = js_optnumber(J, 2, SecFromTime(t)); |
691 | double ms = js_optnumber(J, 3, msFromTime(t)); |
692 | js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); |
693 | } |
694 | |
695 | static void Dp_setUTCHours(js_State *J) |
696 | { |
697 | double t = js_todate(J, 0); |
698 | double h = js_tonumber(J, 1); |
699 | double m = js_optnumber(J, 2, HourFromTime(t)); |
700 | double s = js_optnumber(J, 3, SecFromTime(t)); |
701 | double ms = js_optnumber(J, 4, msFromTime(t)); |
702 | js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms))); |
703 | } |
704 | |
705 | static void Dp_setUTCDate(js_State *J) |
706 | { |
707 | double t = js_todate(J, 0); |
708 | double y = YearFromTime(t); |
709 | double m = MonthFromTime(t); |
710 | double d = js_tonumber(J, 1); |
711 | js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); |
712 | } |
713 | |
714 | static void Dp_setUTCMonth(js_State *J) |
715 | { |
716 | double t = js_todate(J, 0); |
717 | double y = YearFromTime(t); |
718 | double m = js_tonumber(J, 1); |
719 | double d = js_optnumber(J, 3, DateFromTime(t)); |
720 | js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); |
721 | } |
722 | |
723 | static void Dp_setUTCFullYear(js_State *J) |
724 | { |
725 | double t = js_todate(J, 0); |
726 | double y = js_tonumber(J, 1); |
727 | double m = js_optnumber(J, 2, MonthFromTime(t)); |
728 | double d = js_optnumber(J, 3, DateFromTime(t)); |
729 | js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t))); |
730 | } |
731 | |
732 | static void Dp_toJSON(js_State *J) |
733 | { |
734 | js_copy(J, 0); |
735 | js_toprimitive(J, -1, JS_HNUMBER); |
736 | if (js_isnumber(J, -1) && !isfinite(js_tonumber(J, -1))) { |
737 | js_pushnull(J); |
738 | return; |
739 | } |
740 | js_pop(J, 1); |
741 | |
742 | js_getproperty(J, 0, "toISOString" ); |
743 | if (!js_iscallable(J, -1)) |
744 | js_typeerror(J, "this.toISOString is not a function" ); |
745 | js_copy(J, 0); |
746 | js_call(J, 0); |
747 | } |
748 | |
749 | void jsB_initdate(js_State *J) |
750 | { |
751 | J->Date_prototype->u.number = 0; |
752 | |
753 | js_pushobject(J, J->Date_prototype); |
754 | { |
755 | jsB_propf(J, "Date.prototype.valueOf" , Dp_valueOf, 0); |
756 | jsB_propf(J, "Date.prototype.toString" , Dp_toString, 0); |
757 | jsB_propf(J, "Date.prototype.toDateString" , Dp_toDateString, 0); |
758 | jsB_propf(J, "Date.prototype.toTimeString" , Dp_toTimeString, 0); |
759 | jsB_propf(J, "Date.prototype.toLocaleString" , Dp_toString, 0); |
760 | jsB_propf(J, "Date.prototype.toLocaleDateString" , Dp_toDateString, 0); |
761 | jsB_propf(J, "Date.prototype.toLocaleTimeString" , Dp_toTimeString, 0); |
762 | jsB_propf(J, "Date.prototype.toUTCString" , Dp_toUTCString, 0); |
763 | |
764 | jsB_propf(J, "Date.prototype.getTime" , Dp_valueOf, 0); |
765 | jsB_propf(J, "Date.prototype.getFullYear" , Dp_getFullYear, 0); |
766 | jsB_propf(J, "Date.prototype.getUTCFullYear" , Dp_getUTCFullYear, 0); |
767 | jsB_propf(J, "Date.prototype.getMonth" , Dp_getMonth, 0); |
768 | jsB_propf(J, "Date.prototype.getUTCMonth" , Dp_getUTCMonth, 0); |
769 | jsB_propf(J, "Date.prototype.getDate" , Dp_getDate, 0); |
770 | jsB_propf(J, "Date.prototype.getUTCDate" , Dp_getUTCDate, 0); |
771 | jsB_propf(J, "Date.prototype.getDay" , Dp_getDay, 0); |
772 | jsB_propf(J, "Date.prototype.getUTCDay" , Dp_getUTCDay, 0); |
773 | jsB_propf(J, "Date.prototype.getHours" , Dp_getHours, 0); |
774 | jsB_propf(J, "Date.prototype.getUTCHours" , Dp_getUTCHours, 0); |
775 | jsB_propf(J, "Date.prototype.getMinutes" , Dp_getMinutes, 0); |
776 | jsB_propf(J, "Date.prototype.getUTCMinutes" , Dp_getUTCMinutes, 0); |
777 | jsB_propf(J, "Date.prototype.getSeconds" , Dp_getSeconds, 0); |
778 | jsB_propf(J, "Date.prototype.getUTCSeconds" , Dp_getUTCSeconds, 0); |
779 | jsB_propf(J, "Date.prototype.getMilliseconds" , Dp_getMilliseconds, 0); |
780 | jsB_propf(J, "Date.prototype.getUTCMilliseconds" , Dp_getUTCMilliseconds, 0); |
781 | jsB_propf(J, "Date.prototype.getTimezoneOffset" , Dp_getTimezoneOffset, 0); |
782 | |
783 | jsB_propf(J, "Date.prototype.setTime" , Dp_setTime, 1); |
784 | jsB_propf(J, "Date.prototype.setMilliseconds" , Dp_setMilliseconds, 1); |
785 | jsB_propf(J, "Date.prototype.setUTCMilliseconds" , Dp_setUTCMilliseconds, 1); |
786 | jsB_propf(J, "Date.prototype.setSeconds" , Dp_setSeconds, 2); |
787 | jsB_propf(J, "Date.prototype.setUTCSeconds" , Dp_setUTCSeconds, 2); |
788 | jsB_propf(J, "Date.prototype.setMinutes" , Dp_setMinutes, 3); |
789 | jsB_propf(J, "Date.prototype.setUTCMinutes" , Dp_setUTCMinutes, 3); |
790 | jsB_propf(J, "Date.prototype.setHours" , Dp_setHours, 4); |
791 | jsB_propf(J, "Date.prototype.setUTCHours" , Dp_setUTCHours, 4); |
792 | jsB_propf(J, "Date.prototype.setDate" , Dp_setDate, 1); |
793 | jsB_propf(J, "Date.prototype.setUTCDate" , Dp_setUTCDate, 1); |
794 | jsB_propf(J, "Date.prototype.setMonth" , Dp_setMonth, 2); |
795 | jsB_propf(J, "Date.prototype.setUTCMonth" , Dp_setUTCMonth, 2); |
796 | jsB_propf(J, "Date.prototype.setFullYear" , Dp_setFullYear, 3); |
797 | jsB_propf(J, "Date.prototype.setUTCFullYear" , Dp_setUTCFullYear, 3); |
798 | |
799 | /* ES5 */ |
800 | jsB_propf(J, "Date.prototype.toISOString" , Dp_toISOString, 0); |
801 | jsB_propf(J, "Date.prototype.toJSON" , Dp_toJSON, 1); |
802 | } |
803 | js_newcconstructor(J, jsB_Date, jsB_new_Date, "Date" , 0); /* 1 */ |
804 | { |
805 | jsB_propf(J, "Date.parse" , D_parse, 1); |
806 | jsB_propf(J, "Date.UTC" , D_UTC, 7); |
807 | |
808 | /* ES5 */ |
809 | jsB_propf(J, "Date.now" , D_now, 0); |
810 | } |
811 | js_defglobal(J, "Date" , JS_DONTENUM); |
812 | } |
813 | |