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 
Now(void)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 
LocalTZA(void)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 
DaylightSavingTA(double t)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 
pmod(double x,double y)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 
Day(double t)71 static int Day(double t)
72 {
73 	return floor(t / msPerDay);
74 }
75 
TimeWithinDay(double t)76 static double TimeWithinDay(double t)
77 {
78 	return pmod(t, msPerDay);
79 }
80 
DaysInYear(int y)81 static int DaysInYear(int y)
82 {
83 	return y % 4 == 0 && (y % 100 || (y % 400 == 0)) ? 366 : 365;
84 }
85 
DayFromYear(int y)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 
TimeFromYear(int y)94 static double TimeFromYear(int y)
95 {
96 	return DayFromYear(y) * msPerDay;
97 }
98 
YearFromTime(double t)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 
InLeapYear(double t)110 static int InLeapYear(double t)
111 {
112 	return DaysInYear(YearFromTime(t)) == 366;
113 }
114 
DayWithinYear(double t)115 static int DayWithinYear(double t)
116 {
117 	return Day(t) - DayFromYear(YearFromTime(t));
118 }
119 
MonthFromTime(double t)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 
DateFromTime(double t)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 
WeekDay(double t)158 static int WeekDay(double t)
159 {
160 	return pmod(Day(t) + 4, 7);
161 }
162 
LocalTime(double utc)163 static double LocalTime(double utc)
164 {
165 	return utc + LocalTZA() + DaylightSavingTA(utc);
166 }
167 
UTC(double loc)168 static double UTC(double loc)
169 {
170 	return loc - LocalTZA() - DaylightSavingTA(loc - LocalTZA());
171 }
172 
HourFromTime(double t)173 static int HourFromTime(double t)
174 {
175 	return pmod(floor(t / msPerHour), HoursPerDay);
176 }
177 
MinFromTime(double t)178 static int MinFromTime(double t)
179 {
180 	return pmod(floor(t / msPerMinute), MinutesPerHour);
181 }
182 
SecFromTime(double t)183 static int SecFromTime(double t)
184 {
185 	return pmod(floor(t / msPerSecond), SecondsPerMinute);
186 }
187 
msFromTime(double t)188 static int msFromTime(double t)
189 {
190 	return pmod(t, msPerSecond);
191 }
192 
MakeTime(double hour,double min,double sec,double ms)193 static double MakeTime(double hour, double min, double sec, double ms)
194 {
195 	return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms;
196 }
197 
MakeDay(double y,double m,double date)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[DaysInYear(y) == 366][im];
221 
222 	return yd + md + date - 1;
223 }
224 
MakeDate(double day,double time)225 static double MakeDate(double day, double time)
226 {
227 	return day * msPerDay + time;
228 }
229 
TimeClip(double t)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 
toint(const char ** sp,int w,int * v)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 
parseDateTime(const char * s)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 
fmtdate(char * buf,double t)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 
fmttime(char * buf,double t,double tza)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 
fmtdatetime(char * buf,double t,double tza)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 
js_todate(js_State * J,int idx)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 
js_setdate(js_State * J,int idx,double t)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 
D_parse(js_State * J)381 static void D_parse(js_State *J)
382 {
383 	double t = parseDateTime(js_tostring(J, 1));
384 	js_pushnumber(J, t);
385 }
386 
D_UTC(js_State * J)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 
D_now(js_State * J)403 static void D_now(js_State *J)
404 {
405 	js_pushnumber(J, Now());
406 }
407 
jsB_Date(js_State * J)408 static void jsB_Date(js_State *J)
409 {
410 	char buf[64];
411 	js_pushstring(J, fmtdatetime(buf, LocalTime(Now()), LocalTZA()));
412 }
413 
jsB_new_Date(js_State * J)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 
Dp_valueOf(js_State * J)448 static void Dp_valueOf(js_State *J)
449 {
450 	double t = js_todate(J, 0);
451 	js_pushnumber(J, t);
452 }
453 
Dp_toString(js_State * J)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 
Dp_toDateString(js_State * J)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 
Dp_toTimeString(js_State * J)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 
Dp_toUTCString(js_State * J)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 
Dp_toISOString(js_State * J)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 
Dp_getFullYear(js_State * J)491 static void Dp_getFullYear(js_State *J)
492 {
493 	double t = js_todate(J, 0);
494 	if (isnan(t))
495 		js_pushnumber(J, NAN);
496 	else
497 		js_pushnumber(J, YearFromTime(LocalTime(t)));
498 }
499 
Dp_getMonth(js_State * J)500 static void Dp_getMonth(js_State *J)
501 {
502 	double t = js_todate(J, 0);
503 	if (isnan(t))
504 		js_pushnumber(J, NAN);
505 	else
506 		js_pushnumber(J, MonthFromTime(LocalTime(t)));
507 }
508 
Dp_getDate(js_State * J)509 static void Dp_getDate(js_State *J)
510 {
511 	double t = js_todate(J, 0);
512 	if (isnan(t))
513 		js_pushnumber(J, NAN);
514 	else
515 		js_pushnumber(J, DateFromTime(LocalTime(t)));
516 }
517 
Dp_getDay(js_State * J)518 static void Dp_getDay(js_State *J)
519 {
520 	double t = js_todate(J, 0);
521 	if (isnan(t))
522 		js_pushnumber(J, NAN);
523 	else
524 		js_pushnumber(J, WeekDay(LocalTime(t)));
525 }
526 
Dp_getHours(js_State * J)527 static void Dp_getHours(js_State *J)
528 {
529 	double t = js_todate(J, 0);
530 	if (isnan(t))
531 		js_pushnumber(J, NAN);
532 	else
533 		js_pushnumber(J, HourFromTime(LocalTime(t)));
534 }
535 
Dp_getMinutes(js_State * J)536 static void Dp_getMinutes(js_State *J)
537 {
538 	double t = js_todate(J, 0);
539 	if (isnan(t))
540 		js_pushnumber(J, NAN);
541 	else
542 		js_pushnumber(J, MinFromTime(LocalTime(t)));
543 }
544 
Dp_getSeconds(js_State * J)545 static void Dp_getSeconds(js_State *J)
546 {
547 	double t = js_todate(J, 0);
548 	if (isnan(t))
549 		js_pushnumber(J, NAN);
550 	else
551 		js_pushnumber(J, SecFromTime(LocalTime(t)));
552 }
553 
Dp_getMilliseconds(js_State * J)554 static void Dp_getMilliseconds(js_State *J)
555 {
556 	double t = js_todate(J, 0);
557 	if (isnan(t))
558 		js_pushnumber(J, NAN);
559 	else
560 		js_pushnumber(J, msFromTime(LocalTime(t)));
561 }
562 
Dp_getUTCFullYear(js_State * J)563 static void Dp_getUTCFullYear(js_State *J)
564 {
565 	double t = js_todate(J, 0);
566 	if (isnan(t))
567 		js_pushnumber(J, NAN);
568 	else
569 		js_pushnumber(J, YearFromTime(t));
570 }
571 
Dp_getUTCMonth(js_State * J)572 static void Dp_getUTCMonth(js_State *J)
573 {
574 	double t = js_todate(J, 0);
575 	if (isnan(t))
576 		js_pushnumber(J, NAN);
577 	else
578 		js_pushnumber(J, MonthFromTime(t));
579 }
580 
Dp_getUTCDate(js_State * J)581 static void Dp_getUTCDate(js_State *J)
582 {
583 	double t = js_todate(J, 0);
584 	if (isnan(t))
585 		js_pushnumber(J, NAN);
586 	else
587 		js_pushnumber(J, DateFromTime(t));
588 }
589 
Dp_getUTCDay(js_State * J)590 static void Dp_getUTCDay(js_State *J)
591 {
592 	double t = js_todate(J, 0);
593 	if (isnan(t))
594 		js_pushnumber(J, NAN);
595 	else
596 		js_pushnumber(J, WeekDay(t));
597 }
598 
Dp_getUTCHours(js_State * J)599 static void Dp_getUTCHours(js_State *J)
600 {
601 	double t = js_todate(J, 0);
602 	if (isnan(t))
603 		js_pushnumber(J, NAN);
604 	else
605 		js_pushnumber(J, HourFromTime(t));
606 }
607 
Dp_getUTCMinutes(js_State * J)608 static void Dp_getUTCMinutes(js_State *J)
609 {
610 	double t = js_todate(J, 0);
611 	if (isnan(t))
612 		js_pushnumber(J, NAN);
613 	else
614 		js_pushnumber(J, MinFromTime(t));
615 }
616 
Dp_getUTCSeconds(js_State * J)617 static void Dp_getUTCSeconds(js_State *J)
618 {
619 	double t = js_todate(J, 0);
620 	if (isnan(t))
621 		js_pushnumber(J, NAN);
622 	else
623 		js_pushnumber(J, SecFromTime(t));
624 }
625 
Dp_getUTCMilliseconds(js_State * J)626 static void Dp_getUTCMilliseconds(js_State *J)
627 {
628 	double t = js_todate(J, 0);
629 	if (isnan(t))
630 		js_pushnumber(J, NAN);
631 	else
632 		js_pushnumber(J, msFromTime(t));
633 }
634 
Dp_getTimezoneOffset(js_State * J)635 static void Dp_getTimezoneOffset(js_State *J)
636 {
637 	double t = js_todate(J, 0);
638 	if (isnan(t))
639 		js_pushnumber(J, NAN);
640 	else
641 		js_pushnumber(J, (t - LocalTime(t)) / msPerMinute);
642 }
643 
Dp_setTime(js_State * J)644 static void Dp_setTime(js_State *J)
645 {
646 	js_setdate(J, 0, js_tonumber(J, 1));
647 }
648 
Dp_setMilliseconds(js_State * J)649 static void Dp_setMilliseconds(js_State *J)
650 {
651 	double t = LocalTime(js_todate(J, 0));
652 	double h = HourFromTime(t);
653 	double m = MinFromTime(t);
654 	double s = SecFromTime(t);
655 	double ms = js_tonumber(J, 1);
656 	js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms))));
657 }
658 
Dp_setSeconds(js_State * J)659 static void Dp_setSeconds(js_State *J)
660 {
661 	double t = LocalTime(js_todate(J, 0));
662 	double h = HourFromTime(t);
663 	double m = MinFromTime(t);
664 	double s = js_tonumber(J, 1);
665 	double ms = js_optnumber(J, 2, msFromTime(t));
666 	js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms))));
667 }
668 
Dp_setMinutes(js_State * J)669 static void Dp_setMinutes(js_State *J)
670 {
671 	double t = LocalTime(js_todate(J, 0));
672 	double h = HourFromTime(t);
673 	double m = js_tonumber(J, 1);
674 	double s = js_optnumber(J, 2, SecFromTime(t));
675 	double ms = js_optnumber(J, 3, msFromTime(t));
676 	js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms))));
677 }
678 
Dp_setHours(js_State * J)679 static void Dp_setHours(js_State *J)
680 {
681 	double t = LocalTime(js_todate(J, 0));
682 	double h = js_tonumber(J, 1);
683 	double m = js_optnumber(J, 2, MinFromTime(t));
684 	double s = js_optnumber(J, 3, SecFromTime(t));
685 	double ms = js_optnumber(J, 4, msFromTime(t));
686 	js_setdate(J, 0, UTC(MakeDate(Day(t), MakeTime(h, m, s, ms))));
687 }
688 
Dp_setDate(js_State * J)689 static void Dp_setDate(js_State *J)
690 {
691 	double t = LocalTime(js_todate(J, 0));
692 	double y = YearFromTime(t);
693 	double m = MonthFromTime(t);
694 	double d = js_tonumber(J, 1);
695 	js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t))));
696 }
697 
Dp_setMonth(js_State * J)698 static void Dp_setMonth(js_State *J)
699 {
700 	double t = LocalTime(js_todate(J, 0));
701 	double y = YearFromTime(t);
702 	double m = js_tonumber(J, 1);
703 	double d = js_optnumber(J, 2, DateFromTime(t));
704 	js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t))));
705 }
706 
Dp_setFullYear(js_State * J)707 static void Dp_setFullYear(js_State *J)
708 {
709 	double t = LocalTime(js_todate(J, 0));
710 	double y = js_tonumber(J, 1);
711 	double m = js_optnumber(J, 2, MonthFromTime(t));
712 	double d = js_optnumber(J, 3, DateFromTime(t));
713 	js_setdate(J, 0, UTC(MakeDate(MakeDay(y, m, d), TimeWithinDay(t))));
714 }
715 
Dp_setUTCMilliseconds(js_State * J)716 static void Dp_setUTCMilliseconds(js_State *J)
717 {
718 	double t = js_todate(J, 0);
719 	double h = HourFromTime(t);
720 	double m = MinFromTime(t);
721 	double s = SecFromTime(t);
722 	double ms = js_tonumber(J, 1);
723 	js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms)));
724 }
725 
Dp_setUTCSeconds(js_State * J)726 static void Dp_setUTCSeconds(js_State *J)
727 {
728 	double t = js_todate(J, 0);
729 	double h = HourFromTime(t);
730 	double m = MinFromTime(t);
731 	double s = js_tonumber(J, 1);
732 	double ms = js_optnumber(J, 2, msFromTime(t));
733 	js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms)));
734 }
735 
Dp_setUTCMinutes(js_State * J)736 static void Dp_setUTCMinutes(js_State *J)
737 {
738 	double t = js_todate(J, 0);
739 	double h = HourFromTime(t);
740 	double m = js_tonumber(J, 1);
741 	double s = js_optnumber(J, 2, SecFromTime(t));
742 	double ms = js_optnumber(J, 3, msFromTime(t));
743 	js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms)));
744 }
745 
Dp_setUTCHours(js_State * J)746 static void Dp_setUTCHours(js_State *J)
747 {
748 	double t = js_todate(J, 0);
749 	double h = js_tonumber(J, 1);
750 	double m = js_optnumber(J, 2, HourFromTime(t));
751 	double s = js_optnumber(J, 3, SecFromTime(t));
752 	double ms = js_optnumber(J, 4, msFromTime(t));
753 	js_setdate(J, 0, MakeDate(Day(t), MakeTime(h, m, s, ms)));
754 }
755 
Dp_setUTCDate(js_State * J)756 static void Dp_setUTCDate(js_State *J)
757 {
758 	double t = js_todate(J, 0);
759 	double y = YearFromTime(t);
760 	double m = MonthFromTime(t);
761 	double d = js_tonumber(J, 1);
762 	js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t)));
763 }
764 
Dp_setUTCMonth(js_State * J)765 static void Dp_setUTCMonth(js_State *J)
766 {
767 	double t = js_todate(J, 0);
768 	double y = YearFromTime(t);
769 	double m = js_tonumber(J, 1);
770 	double d = js_optnumber(J, 2, DateFromTime(t));
771 	js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t)));
772 }
773 
Dp_setUTCFullYear(js_State * J)774 static void Dp_setUTCFullYear(js_State *J)
775 {
776 	double t = js_todate(J, 0);
777 	double y = js_tonumber(J, 1);
778 	double m = js_optnumber(J, 2, MonthFromTime(t));
779 	double d = js_optnumber(J, 3, DateFromTime(t));
780 	js_setdate(J, 0, MakeDate(MakeDay(y, m, d), TimeWithinDay(t)));
781 }
782 
Dp_toJSON(js_State * J)783 static void Dp_toJSON(js_State *J)
784 {
785 	js_copy(J, 0);
786 	js_toprimitive(J, -1, JS_HNUMBER);
787 	if (js_isnumber(J, -1) && !isfinite(js_tonumber(J, -1))) {
788 		js_pushnull(J);
789 		return;
790 	}
791 	js_pop(J, 1);
792 
793 	js_getproperty(J, 0, "toISOString");
794 	if (!js_iscallable(J, -1))
795 		js_typeerror(J, "this.toISOString is not a function");
796 	js_copy(J, 0);
797 	js_call(J, 0);
798 }
799 
jsB_initdate(js_State * J)800 void jsB_initdate(js_State *J)
801 {
802 	J->Date_prototype->u.number = 0;
803 
804 	js_pushobject(J, J->Date_prototype);
805 	{
806 		jsB_propf(J, "Date.prototype.valueOf", Dp_valueOf, 0);
807 		jsB_propf(J, "Date.prototype.toString", Dp_toString, 0);
808 		jsB_propf(J, "Date.prototype.toDateString", Dp_toDateString, 0);
809 		jsB_propf(J, "Date.prototype.toTimeString", Dp_toTimeString, 0);
810 		jsB_propf(J, "Date.prototype.toLocaleString", Dp_toString, 0);
811 		jsB_propf(J, "Date.prototype.toLocaleDateString", Dp_toDateString, 0);
812 		jsB_propf(J, "Date.prototype.toLocaleTimeString", Dp_toTimeString, 0);
813 		jsB_propf(J, "Date.prototype.toUTCString", Dp_toUTCString, 0);
814 
815 		jsB_propf(J, "Date.prototype.getTime", Dp_valueOf, 0);
816 		jsB_propf(J, "Date.prototype.getFullYear", Dp_getFullYear, 0);
817 		jsB_propf(J, "Date.prototype.getUTCFullYear", Dp_getUTCFullYear, 0);
818 		jsB_propf(J, "Date.prototype.getMonth", Dp_getMonth, 0);
819 		jsB_propf(J, "Date.prototype.getUTCMonth", Dp_getUTCMonth, 0);
820 		jsB_propf(J, "Date.prototype.getDate", Dp_getDate, 0);
821 		jsB_propf(J, "Date.prototype.getUTCDate", Dp_getUTCDate, 0);
822 		jsB_propf(J, "Date.prototype.getDay", Dp_getDay, 0);
823 		jsB_propf(J, "Date.prototype.getUTCDay", Dp_getUTCDay, 0);
824 		jsB_propf(J, "Date.prototype.getHours", Dp_getHours, 0);
825 		jsB_propf(J, "Date.prototype.getUTCHours", Dp_getUTCHours, 0);
826 		jsB_propf(J, "Date.prototype.getMinutes", Dp_getMinutes, 0);
827 		jsB_propf(J, "Date.prototype.getUTCMinutes", Dp_getUTCMinutes, 0);
828 		jsB_propf(J, "Date.prototype.getSeconds", Dp_getSeconds, 0);
829 		jsB_propf(J, "Date.prototype.getUTCSeconds", Dp_getUTCSeconds, 0);
830 		jsB_propf(J, "Date.prototype.getMilliseconds", Dp_getMilliseconds, 0);
831 		jsB_propf(J, "Date.prototype.getUTCMilliseconds", Dp_getUTCMilliseconds, 0);
832 		jsB_propf(J, "Date.prototype.getTimezoneOffset", Dp_getTimezoneOffset, 0);
833 
834 		jsB_propf(J, "Date.prototype.setTime", Dp_setTime, 1);
835 		jsB_propf(J, "Date.prototype.setMilliseconds", Dp_setMilliseconds, 1);
836 		jsB_propf(J, "Date.prototype.setUTCMilliseconds", Dp_setUTCMilliseconds, 1);
837 		jsB_propf(J, "Date.prototype.setSeconds", Dp_setSeconds, 2);
838 		jsB_propf(J, "Date.prototype.setUTCSeconds", Dp_setUTCSeconds, 2);
839 		jsB_propf(J, "Date.prototype.setMinutes", Dp_setMinutes, 3);
840 		jsB_propf(J, "Date.prototype.setUTCMinutes", Dp_setUTCMinutes, 3);
841 		jsB_propf(J, "Date.prototype.setHours", Dp_setHours, 4);
842 		jsB_propf(J, "Date.prototype.setUTCHours", Dp_setUTCHours, 4);
843 		jsB_propf(J, "Date.prototype.setDate", Dp_setDate, 1);
844 		jsB_propf(J, "Date.prototype.setUTCDate", Dp_setUTCDate, 1);
845 		jsB_propf(J, "Date.prototype.setMonth", Dp_setMonth, 2);
846 		jsB_propf(J, "Date.prototype.setUTCMonth", Dp_setUTCMonth, 2);
847 		jsB_propf(J, "Date.prototype.setFullYear", Dp_setFullYear, 3);
848 		jsB_propf(J, "Date.prototype.setUTCFullYear", Dp_setUTCFullYear, 3);
849 
850 		/* ES5 */
851 		jsB_propf(J, "Date.prototype.toISOString", Dp_toISOString, 0);
852 		jsB_propf(J, "Date.prototype.toJSON", Dp_toJSON, 1);
853 	}
854 	js_newcconstructor(J, jsB_Date, jsB_new_Date, "Date", 0); /* 1 */
855 	{
856 		jsB_propf(J, "Date.parse", D_parse, 1);
857 		jsB_propf(J, "Date.UTC", D_UTC, 7);
858 
859 		/* ES5 */
860 		jsB_propf(J, "Date.now", D_now, 0);
861 	}
862 	js_defglobal(J, "Date", JS_DONTENUM);
863 }
864