ntdll: Conform to Windows 11 behavior in RtlIpv6StringToAddress().
[wine.git] / dlls / jscript / date.c
blobb1846fb3245b4231a099ad25971f85ba6af14736
1 /*
2 * Copyright 2008 Jacek Caban for CodeWeavers
3 * Copyright 2009 Piotr Caban
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <limits.h>
22 #include <math.h>
23 #include <assert.h>
25 #include "jscript.h"
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
31 typedef struct {
32 jsdisp_t dispex;
34 /* ECMA-262 3rd Edition 15.9.1.1 */
35 DOUBLE time;
37 LONG bias;
38 SYSTEMTIME standardDate;
39 LONG standardBias;
40 SYSTEMTIME daylightDate;
41 LONG daylightBias;
42 } DateInstance;
44 static inline DateInstance *date_from_jsdisp(jsdisp_t *jsdisp)
46 return CONTAINING_RECORD(jsdisp, DateInstance, dispex);
49 static inline DateInstance *date_this(jsval_t vthis)
51 jsdisp_t *jsdisp = is_object_instance(vthis) ? to_jsdisp(get_object(vthis)) : NULL;
52 return (jsdisp && is_class(jsdisp, JSCLASS_DATE)) ? date_from_jsdisp(jsdisp) : NULL;
55 static inline double file_time_to_date_time(const FILETIME *ftime)
57 /* 1601 to 1970 is 369 years plus 89 leap days */
58 const LONGLONG time_epoch = (LONGLONG)(369 * 365 + 89) * 86400 * 1000;
60 LONGLONG time = (((ULONGLONG)ftime->dwHighDateTime << 32) | ftime->dwLowDateTime) / 10000;
62 return time - time_epoch;
65 /*ECMA-262 3rd Edition 15.9.1.2 */
66 #define MS_PER_DAY 86400000
67 #define MS_PER_HOUR 3600000
68 #define MS_PER_MINUTE 60000
70 /* ECMA-262 3rd Edition 15.9.1.2 */
71 static inline DOUBLE day(DOUBLE time)
73 return floor(time / MS_PER_DAY);
76 /* ECMA-262 3rd Edition 15.9.1.2 */
77 static inline DOUBLE time_within_day(DOUBLE time)
79 DOUBLE ret;
81 ret = fmod(time, MS_PER_DAY);
82 if(ret < 0)
83 ret += MS_PER_DAY;
85 return ret;
88 /* ECMA-262 3rd Edition 15.9.1.3 */
89 static inline DOUBLE days_in_year(DOUBLE year)
91 int y;
93 if(year != (int)year)
94 return NAN;
96 y = year;
97 if(y%4 != 0) return 365;
98 if(y%100 != 0) return 366;
99 if(y%400 != 0) return 365;
100 return 366;
103 /* ECMA-262 3rd Edition 15.9.1.3 */
104 static inline DOUBLE day_from_year(DOUBLE year)
106 if(year != (int)year)
107 return NAN;
109 return floor(365.0*(year-1970) + floor((year-1969)/4)
110 - floor((year-1901)/100) + floor((year-1601)/400));
113 static inline int day_from_month(int month, int in_leap_year)
115 switch(month)
117 case 0:
118 return 0;
119 case 1:
120 return 31;
121 case 2:
122 return 59+in_leap_year;
123 case 3:
124 return 90+in_leap_year;
125 case 4:
126 return 120+in_leap_year;
127 case 5:
128 return 151+in_leap_year;
129 case 6:
130 return 181+in_leap_year;
131 case 7:
132 return 212+in_leap_year;
133 case 8:
134 return 243+in_leap_year;
135 case 9:
136 return 273+in_leap_year;
137 case 10:
138 return 304+in_leap_year;
139 default:
140 return 334+in_leap_year;
144 /* ECMA-262 3rd Edition 15.9.1.3 */
145 static inline DOUBLE time_from_year(DOUBLE year)
147 return MS_PER_DAY*day_from_year(year);
150 /* ECMA-262 3rd Edition 15.9.1.3 */
151 static inline DOUBLE year_from_time(DOUBLE time)
153 int y;
155 if(isnan(time))
156 return NAN;
158 y = 1970 + time/365.25/MS_PER_DAY;
160 if(time_from_year(y) > time)
161 while(time_from_year(y) > time) y--;
162 else
163 while(time_from_year(y+1)<=time) y++;
165 return y;
168 /* ECMA-262 3rd Edition 15.9.1.3 */
169 static inline int in_leap_year(DOUBLE time)
171 if(days_in_year(year_from_time(time))==366)
172 return 1;
173 return 0;
176 /* ECMA-262 3rd Edition 15.9.1.4 */
177 static inline int day_within_year(DOUBLE time)
179 return day(time) - day_from_year(year_from_time(time));
182 /* ECMA-262 3rd Edition 15.9.1.4 */
183 static inline DOUBLE month_from_time(DOUBLE time)
185 int ily = in_leap_year(time);
186 int dwy = day_within_year(time);
188 if(isnan(time))
189 return NAN;
191 if(0<=dwy && dwy<31) return 0;
192 if(dwy < 59+ily) return 1;
193 if(dwy < 90+ily) return 2;
194 if(dwy < 120+ily) return 3;
195 if(dwy < 151+ily) return 4;
196 if(dwy < 181+ily) return 5;
197 if(dwy < 212+ily) return 6;
198 if(dwy < 243+ily) return 7;
199 if(dwy < 273+ily) return 8;
200 if(dwy < 304+ily) return 9;
201 if(dwy < 334+ily) return 10;
202 return 11;
205 /* ECMA-262 3rd Edition 15.9.1.5 */
206 static inline DOUBLE date_from_time(DOUBLE time)
208 int dwy = day_within_year(time);
209 int ily = in_leap_year(time);
210 int mft = month_from_time(time);
212 if(isnan(time))
213 return NAN;
215 if(mft==0) return dwy+1;
216 if(mft==1) return dwy-30;
217 if(mft==2) return dwy-58-ily;
218 if(mft==3) return dwy-89-ily;
219 if(mft==4) return dwy-119-ily;
220 if(mft==5) return dwy-150-ily;
221 if(mft==6) return dwy-180-ily;
222 if(mft==7) return dwy-211-ily;
223 if(mft==8) return dwy-242-ily;
224 if(mft==9) return dwy-272-ily;
225 if(mft==10) return dwy-303-ily;
226 return dwy-333-ily;
229 /* ECMA-262 3rd Edition 15.9.1.6 */
230 static inline DOUBLE week_day(DOUBLE time)
232 DOUBLE ret;
234 if(isnan(time))
235 return NAN;
237 ret = fmod(day(time)+4, 7);
238 if(ret<0) ret += 7;
240 return ret;
243 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
245 DOUBLE time;
246 int set_week_day;
248 if(st.wMonth == 0)
249 return NAN;
251 if(st.wYear != 0)
252 year = st.wYear;
254 time = time_from_year(year);
255 time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
257 if(st.wYear == 0) {
258 set_week_day = st.wDayOfWeek-week_day(time);
259 if(set_week_day < 0)
260 set_week_day += 7;
261 time += set_week_day * MS_PER_DAY;
263 time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
264 if(month_from_time(time) != st.wMonth-1)
265 time -= 7 * MS_PER_DAY;
267 else
268 time += st.wDay * MS_PER_DAY;
270 time += st.wHour * MS_PER_HOUR;
271 time += st.wMinute * MS_PER_MINUTE;
273 return time;
276 /* ECMA-262 3rd Edition 15.9.1.9 */
277 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
279 int year = year_from_time(time);
280 DOUBLE standardTime, daylightTime;
282 if(isnan(time))
283 return 0;
285 standardTime = convert_time(year, date->standardDate);
286 daylightTime = convert_time(year, date->daylightDate);
288 if(isnan(standardTime) || isnan(daylightTime))
289 return 0;
290 else if(standardTime > daylightTime) {
291 if(daylightTime <= time && time < standardTime)
292 return date->daylightBias;
294 return date->standardBias;
296 else {
297 if(standardTime <= time && time < daylightTime)
298 return date->standardBias;
300 return date->daylightBias;
304 /* ECMA-262 3rd Edition 15.9.1.9 */
305 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
307 return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
310 /* ECMA-262 3rd Edition 15.9.1.9 */
311 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
313 time += date->bias * MS_PER_MINUTE;
314 return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
317 /* ECMA-262 3rd Edition 15.9.1.10 */
318 static inline DOUBLE hour_from_time(DOUBLE time)
320 DOUBLE ret;
322 if(isnan(time))
323 return NAN;
325 ret = fmod(floor(time/MS_PER_HOUR), 24);
326 if(ret<0) ret += 24;
328 return ret;
331 /* ECMA-262 3rd Edition 15.9.1.10 */
332 static inline DOUBLE min_from_time(DOUBLE time)
334 DOUBLE ret;
336 if(isnan(time))
337 return NAN;
339 ret = fmod(floor(time/MS_PER_MINUTE), 60);
340 if(ret<0) ret += 60;
342 return ret;
345 /* ECMA-262 3rd Edition 15.9.1.10 */
346 static inline DOUBLE sec_from_time(DOUBLE time)
348 DOUBLE ret;
350 if(isnan(time))
351 return NAN;
353 ret = fmod(floor(time/1000), 60);
354 if(ret<0) ret += 60;
356 return ret;
359 /* ECMA-262 3rd Edition 15.9.1.10 */
360 static inline DOUBLE ms_from_time(DOUBLE time)
362 DOUBLE ret;
364 if(isnan(time))
365 return NAN;
367 ret = fmod(time, 1000);
368 if(ret<0) ret += 1000;
370 return ret;
373 /* ECMA-262 3rd Edition 15.9.1.11 */
374 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
376 return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
379 /* ECMA-262 3rd Edition 15.9.1.12 */
380 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
382 DOUBLE time;
384 year += floor(month/12);
386 month = fmod(month, 12);
387 if(month<0) month += 12;
389 time = time_from_year(year);
391 day += floor(time / MS_PER_DAY);
392 day += day_from_month(month, in_leap_year(time));
394 return day-1;
397 /* ECMA-262 3rd Edition 15.9.1.13 */
398 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
400 return day*MS_PER_DAY + time;
403 /* ECMA-262 3rd Edition 15.9.1.14 */
404 static inline DOUBLE time_clip(DOUBLE time)
406 if(8.64e15 < time || time < -8.64e15) {
407 return NAN;
410 return floor(time);
413 static double date_now(void)
415 FILETIME ftime;
417 GetSystemTimeAsFileTime(&ftime);
418 return file_time_to_date_time(&ftime);
421 static SYSTEMTIME create_systemtime(DOUBLE time)
423 SYSTEMTIME st;
425 st.wYear = year_from_time(time);
426 st.wMonth = month_from_time(time) + 1;
427 st.wDayOfWeek = week_day(time);
428 st.wDay = date_from_time(time);
429 st.wHour = hour_from_time(time);
430 st.wMinute = min_from_time(time);
431 st.wSecond = sec_from_time(time);
432 st.wMilliseconds = ms_from_time(time);
434 return st;
437 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
439 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
440 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
441 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
442 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
443 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
444 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
445 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
446 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
447 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
449 const WCHAR *formatEra = L"";
450 WCHAR week[64], month[64];
451 WCHAR buf[192];
452 jsstr_t *date_jsstr;
453 int year, day;
454 DWORD lcid_en;
455 WCHAR sign = '-';
457 if(isnan(time)) {
458 if(r)
459 *r = jsval_string(jsstr_nan());
460 return S_OK;
463 if(r) {
464 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
466 week[0] = 0;
467 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
469 month[0] = 0;
470 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
472 year = year_from_time(time);
473 if(year<0) {
474 formatEra = L" B.C.";
475 year = -year+1;
478 day = date_from_time(time);
480 if(offset < 0) {
481 sign = '+';
482 offset = -offset;
485 if(!show_offset)
486 swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %02d:%02d:%02d %d%s", week, month, day,
487 (int)hour_from_time(time), (int)min_from_time(time),
488 (int)sec_from_time(time), year, formatEra);
489 else if(offset)
490 swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %02d:%02d:%02d UTC%c%02d%02d %d%s", week, month, day,
491 (int)hour_from_time(time), (int)min_from_time(time),
492 (int)sec_from_time(time), sign, offset/60, offset%60,
493 year, formatEra);
494 else
495 swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %02d:%02d:%02d UTC %d%s", week, month, day,
496 (int)hour_from_time(time), (int)min_from_time(time),
497 (int)sec_from_time(time), year, formatEra);
499 date_jsstr = jsstr_alloc(buf);
500 if(!date_jsstr)
501 return E_OUTOFMEMORY;
503 *r = jsval_string(date_jsstr);
505 return S_OK;
508 /* ECMA-262 3rd Edition 15.9.1.2 */
509 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
511 DOUBLE time;
512 int offset;
514 time = local_time(date->time, date);
515 offset = date->bias +
516 daylight_saving_ta(time, date);
518 return date_to_string(time, TRUE, offset, r);
521 static HRESULT Date_toString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
523 DateInstance *date;
525 TRACE("\n");
527 if(!(date = date_this(vthis)))
528 return JS_E_DATE_EXPECTED;
530 return dateobj_to_string(date, r);
533 /* ECMA-262 3rd Edition 15.9.1.5 */
534 static HRESULT Date_toLocaleString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
535 jsval_t *r)
537 SYSTEMTIME st;
538 DateInstance *date;
539 jsstr_t *date_str;
540 int date_len, time_len;
542 TRACE("\n");
544 if(!(date = date_this(vthis)))
545 return JS_E_DATE_EXPECTED;
547 if(isnan(date->time)) {
548 if(r)
549 *r = jsval_string(jsstr_nan());
550 return S_OK;
553 st = create_systemtime(local_time(date->time, date));
555 if(st.wYear<1601 || st.wYear>9999)
556 return dateobj_to_string(date, r);
558 if(r) {
559 WCHAR *ptr;
561 date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
562 time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
564 date_str = jsstr_alloc_buf(date_len+time_len-1, &ptr);
565 if(!date_str)
566 return E_OUTOFMEMORY;
568 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
569 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
570 ptr[date_len-1] = ' ';
572 *r = jsval_string(date_str);
574 return S_OK;
577 static HRESULT Date_toISOString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
578 jsval_t *r)
580 DateInstance *date;
581 WCHAR buf[64], *p = buf;
582 double year;
584 TRACE("\n");
586 if(!(date = date_this(vthis)))
587 return JS_E_DATE_EXPECTED;
589 year = year_from_time(date->time);
590 if(isnan(year) || year > 999999 || year < -999999) {
591 FIXME("year %lf should throw an exception\n", year);
592 return E_FAIL;
595 if(year < 0) {
596 *p++ = '-';
597 p += swprintf(p, ARRAY_SIZE(buf) - 1, L"%06d", -(int)year);
598 }else if(year > 9999) {
599 *p++ = '+';
600 p += swprintf(p, ARRAY_SIZE(buf) - 1, L"%06d", (int)year);
601 }else {
602 p += swprintf(p, ARRAY_SIZE(buf), L"%04d", (int)year);
605 swprintf(p, ARRAY_SIZE(buf) - (p - buf), L"-%02d-%02dT%02d:%02d:%02d.%03dZ",
606 (int)month_from_time(date->time) + 1, (int)date_from_time(date->time),
607 (int)hour_from_time(date->time), (int)min_from_time(date->time),
608 (int)sec_from_time(date->time), (int)ms_from_time(date->time));
610 if(r) {
611 jsstr_t *ret;
612 if(!(ret = jsstr_alloc(buf)))
613 return E_OUTOFMEMORY;
614 *r = jsval_string(ret);
616 return S_OK;
619 static HRESULT Date_valueOf(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
620 jsval_t *r)
622 DateInstance *date;
624 TRACE("\n");
626 if(!(date = date_this(vthis)))
627 return JS_E_DATE_EXPECTED;
629 if(r)
630 *r = jsval_number(date->time);
631 return S_OK;
634 static inline HRESULT create_utc_string(script_ctx_t *ctx, jsval_t vthis, jsval_t *r)
636 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
637 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
638 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
639 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
640 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
641 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
642 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
643 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
644 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
646 const WCHAR *formatEra = L"";
647 WCHAR week[64], month[64];
648 WCHAR buf[192];
649 DateInstance *date;
650 jsstr_t *date_str;
651 int year, day;
652 DWORD lcid_en;
654 if(!(date = date_this(vthis)))
655 return JS_E_DATE_EXPECTED;
657 if(isnan(date->time)) {
658 if(r)
659 *r = jsval_string(jsstr_nan());
660 return S_OK;
663 if(r) {
664 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
666 week[0] = 0;
667 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, ARRAY_SIZE(week));
669 month[0] = 0;
670 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, ARRAY_SIZE(month));
672 year = year_from_time(date->time);
673 if(year<0) {
674 formatEra = L" B.C.";
675 year = -year+1;
678 day = date_from_time(date->time);
680 swprintf(buf, ARRAY_SIZE(buf),
681 L"%s, %d %s %d%s %02d:%02d:%02d UTC", week, day, month, year, formatEra,
682 (int)hour_from_time(date->time), (int)min_from_time(date->time),
683 (int)sec_from_time(date->time));
685 date_str = jsstr_alloc(buf);
686 if(!date_str)
687 return E_OUTOFMEMORY;
689 *r = jsval_string(date_str);
691 return S_OK;
694 /* ECMA-262 3rd Edition 15.9.5.42 */
695 static HRESULT Date_toUTCString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
696 jsval_t *r)
698 TRACE("\n");
699 return create_utc_string(ctx, vthis, r);
702 static HRESULT Date_toGMTString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
703 jsval_t *r)
705 TRACE("\n");
706 return create_utc_string(ctx, vthis, r);
709 /* ECMA-262 3rd Edition 15.9.5.3 */
710 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
712 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
713 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
714 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
715 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
716 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
717 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
718 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
719 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
720 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
722 const WCHAR *formatEra = L"";
723 WCHAR week[64], month[64];
724 WCHAR buf[192];
725 jsstr_t *date_str;
726 DOUBLE time;
727 int year, day;
728 DWORD lcid_en;
730 if(isnan(date->time)) {
731 if(r)
732 *r = jsval_string(jsstr_nan());
733 return S_OK;
736 time = local_time(date->time, date);
738 if(r) {
739 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
741 week[0] = 0;
742 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, ARRAY_SIZE(week));
744 month[0] = 0;
745 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, ARRAY_SIZE(month));
747 year = year_from_time(time);
748 if(year<0) {
749 formatEra = L" B.C.";
750 year = -year+1;
753 day = date_from_time(time);
755 swprintf(buf, ARRAY_SIZE(buf), L"%s %s %d %d%s", week, month, day, year, formatEra);
757 date_str = jsstr_alloc(buf);
758 if(!date_str)
759 return E_OUTOFMEMORY;
761 *r = jsval_string(date_str);
763 return S_OK;
766 static HRESULT Date_toDateString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
767 jsval_t *r)
769 DateInstance *date;
771 if(!(date = date_this(vthis)))
772 return JS_E_DATE_EXPECTED;
774 return dateobj_to_date_string(date, r);
777 /* ECMA-262 3rd Edition 15.9.5.4 */
778 static HRESULT Date_toTimeString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
779 jsval_t *r)
781 DateInstance *date;
782 jsstr_t *date_str;
783 WCHAR buf[32];
784 DOUBLE time;
785 WCHAR sign;
786 int offset;
788 TRACE("\n");
790 if(!(date = date_this(vthis)))
791 return JS_E_DATE_EXPECTED;
793 if(isnan(date->time)) {
794 if(r)
795 *r = jsval_string(jsstr_nan());
796 return S_OK;
799 time = local_time(date->time, date);
801 if(r) {
802 offset = date->bias +
803 daylight_saving_ta(time, date);
805 if(offset < 0) {
806 sign = '+';
807 offset = -offset;
809 else sign = '-';
811 if(offset)
812 swprintf(buf, ARRAY_SIZE(buf), L"%02d:%02d:%02d UTC%c%02d%02d", (int)hour_from_time(time),
813 (int)min_from_time(time), (int)sec_from_time(time),
814 sign, offset/60, offset%60);
815 else
816 swprintf(buf, ARRAY_SIZE(buf), L"%02d:%02d:%02d UTC", (int)hour_from_time(time),
817 (int)min_from_time(time), (int)sec_from_time(time));
819 date_str = jsstr_alloc(buf);
820 if(!date_str)
821 return E_OUTOFMEMORY;
823 *r = jsval_string(date_str);
825 return S_OK;
828 /* ECMA-262 3rd Edition 15.9.5.6 */
829 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
830 jsval_t *r)
832 SYSTEMTIME st;
833 DateInstance *date;
834 jsstr_t *date_str;
835 int len;
837 TRACE("\n");
839 if(!(date = date_this(vthis)))
840 return JS_E_DATE_EXPECTED;
842 if(isnan(date->time)) {
843 if(r)
844 *r = jsval_string(jsstr_nan());
845 return S_OK;
848 st = create_systemtime(local_time(date->time, date));
850 if(st.wYear<1601 || st.wYear>9999)
851 return dateobj_to_date_string(date, r);
853 if(r) {
854 WCHAR *ptr;
856 len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
857 date_str = jsstr_alloc_buf(len-1, &ptr);
858 if(!date_str)
859 return E_OUTOFMEMORY;
860 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
862 *r = jsval_string(date_str);
864 return S_OK;
867 /* ECMA-262 3rd Edition 15.9.5.7 */
868 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
869 jsval_t *r)
871 SYSTEMTIME st;
872 DateInstance *date;
873 jsstr_t *date_str;
874 int len;
876 TRACE("\n");
878 if(!(date = date_this(vthis)))
879 return JS_E_DATE_EXPECTED;
881 if(isnan(date->time)) {
882 if(r)
883 *r = jsval_string(jsstr_nan());
884 return S_OK;
887 st = create_systemtime(local_time(date->time, date));
889 if(st.wYear<1601 || st.wYear>9999)
890 return Date_toTimeString(ctx, vthis, flags, argc, argv, r);
892 if(r) {
893 WCHAR *ptr;
895 len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
896 date_str = jsstr_alloc_buf(len-1, &ptr);
897 if(!date_str)
898 return E_OUTOFMEMORY;
899 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
901 *r = jsval_string(date_str);
903 return S_OK;
906 /* ECMA-262 3rd Edition 15.9.5.9 */
907 static HRESULT Date_getTime(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
908 jsval_t *r)
910 DateInstance *date;
912 TRACE("\n");
914 if(!(date = date_this(vthis)))
915 return JS_E_DATE_EXPECTED;
917 if(r)
918 *r = jsval_number(date->time);
919 return S_OK;
922 /* ECMA-262 3rd Edition 15.9.5.10 */
923 static HRESULT Date_getFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
924 jsval_t *r)
926 DateInstance *date;
928 TRACE("\n");
930 if(!(date = date_this(vthis)))
931 return JS_E_DATE_EXPECTED;
933 if(r) {
934 DOUBLE time = local_time(date->time, date);
936 *r = jsval_number(year_from_time(time));
938 return S_OK;
941 /* ECMA-262 3rd Edition 15.9.5.11 */
942 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
943 jsval_t *r)
945 DateInstance *date;
947 TRACE("\n");
949 if(!(date = date_this(vthis)))
950 return JS_E_DATE_EXPECTED;
952 if(r)
953 *r = jsval_number(year_from_time(date->time));
954 return S_OK;
957 /* ECMA-262 3rd Edition 15.9.5.12 */
958 static HRESULT Date_getMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
960 DateInstance *date;
962 TRACE("\n");
964 if(!(date = date_this(vthis)))
965 return JS_E_DATE_EXPECTED;
967 if(r)
968 *r = jsval_number(month_from_time(local_time(date->time, date)));
969 return S_OK;
972 /* ECMA-262 3rd Edition 15.9.5.13 */
973 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
974 jsval_t *r)
976 DateInstance *date;
978 TRACE("\n");
980 if(!(date = date_this(vthis)))
981 return JS_E_DATE_EXPECTED;
983 if(r)
984 *r = jsval_number(month_from_time(date->time));
985 return S_OK;
988 /* ECMA-262 3rd Edition 15.9.5.14 */
989 static HRESULT Date_getDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
991 DateInstance *date;
993 TRACE("\n");
995 if(!(date = date_this(vthis)))
996 return JS_E_DATE_EXPECTED;
998 if(r)
999 *r = jsval_number(date_from_time(local_time(date->time, date)));
1000 return S_OK;
1003 /* ECMA-262 3rd Edition 15.9.5.15 */
1004 static HRESULT Date_getUTCDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1005 jsval_t *r)
1007 DateInstance *date;
1009 TRACE("\n");
1011 if(!(date = date_this(vthis)))
1012 return JS_E_DATE_EXPECTED;
1014 if(r)
1015 *r = jsval_number(date_from_time(date->time));
1016 return S_OK;
1019 /* ECMA-262 3rd Edition 15.9.5.16 */
1020 static HRESULT Date_getDay(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1021 jsval_t *r)
1023 DateInstance *date;
1025 TRACE("\n");
1027 if(!(date = date_this(vthis)))
1028 return JS_E_DATE_EXPECTED;
1030 if(r)
1031 *r = jsval_number(week_day(local_time(date->time, date)));
1032 return S_OK;
1035 /* ECMA-262 3rd Edition 15.9.5.17 */
1036 static HRESULT Date_getUTCDay(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1037 jsval_t *r)
1039 DateInstance *date;
1041 TRACE("\n");
1043 if(!(date = date_this(vthis)))
1044 return JS_E_DATE_EXPECTED;
1046 if(r)
1047 *r = jsval_number(week_day(date->time));
1048 return S_OK;
1051 /* ECMA-262 3rd Edition 15.9.5.18 */
1052 static HRESULT Date_getHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1053 jsval_t *r)
1055 DateInstance *date;
1057 TRACE("\n");
1059 if(!(date = date_this(vthis)))
1060 return JS_E_DATE_EXPECTED;
1062 if(r)
1063 *r = jsval_number(hour_from_time(local_time(date->time, date)));
1064 return S_OK;
1067 /* ECMA-262 3rd Edition 15.9.5.19 */
1068 static HRESULT Date_getUTCHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1069 jsval_t *r)
1071 DateInstance *date;
1073 TRACE("\n");
1075 if(!(date = date_this(vthis)))
1076 return JS_E_DATE_EXPECTED;
1078 if(r)
1079 *r = jsval_number(hour_from_time(date->time));
1080 return S_OK;
1083 /* ECMA-262 3rd Edition 15.9.5.20 */
1084 static HRESULT Date_getMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1085 jsval_t *r)
1087 DateInstance *date;
1089 TRACE("\n");
1091 if(!(date = date_this(vthis)))
1092 return JS_E_DATE_EXPECTED;
1094 if(r)
1095 *r = jsval_number(min_from_time(local_time(date->time, date)));
1096 return S_OK;
1099 /* ECMA-262 3rd Edition 15.9.5.21 */
1100 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1101 jsval_t *r)
1103 DateInstance *date;
1105 TRACE("\n");
1107 if(!(date = date_this(vthis)))
1108 return JS_E_DATE_EXPECTED;
1110 if(r)
1111 *r = jsval_number(min_from_time(date->time));
1112 return S_OK;
1115 /* ECMA-262 3rd Edition 15.9.5.22 */
1116 static HRESULT Date_getSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1118 DateInstance *date;
1120 TRACE("\n");
1122 if(!(date = date_this(vthis)))
1123 return JS_E_DATE_EXPECTED;
1125 if(r)
1126 *r = jsval_number(sec_from_time(local_time(date->time, date)));
1127 return S_OK;
1130 /* ECMA-262 3rd Edition 15.9.5.23 */
1131 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1132 jsval_t *r)
1134 DateInstance *date;
1136 TRACE("\n");
1138 if(!(date = date_this(vthis)))
1139 return JS_E_DATE_EXPECTED;
1141 if(r)
1142 *r = jsval_number(sec_from_time(date->time));
1143 return S_OK;
1146 /* ECMA-262 3rd Edition 15.9.5.24 */
1147 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1148 jsval_t *r)
1150 DateInstance *date;
1152 TRACE("\n");
1154 if(!(date = date_this(vthis)))
1155 return JS_E_DATE_EXPECTED;
1157 if(r)
1158 *r = jsval_number(ms_from_time(local_time(date->time, date)));
1159 return S_OK;
1162 /* ECMA-262 3rd Edition 15.9.5.25 */
1163 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1164 jsval_t *r)
1166 DateInstance *date;
1168 TRACE("\n");
1170 if(!(date = date_this(vthis)))
1171 return JS_E_DATE_EXPECTED;
1173 if(r)
1174 *r = jsval_number(ms_from_time(date->time));
1175 return S_OK;
1178 /* ECMA-262 3rd Edition 15.9.5.26 */
1179 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1180 jsval_t *r)
1182 DateInstance *date;
1184 TRACE("\n");
1186 if(!(date = date_this(vthis)))
1187 return JS_E_DATE_EXPECTED;
1189 if(r)
1190 *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1191 return S_OK;
1194 /* ECMA-262 3rd Edition 15.9.5.27 */
1195 static HRESULT Date_setTime(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1196 jsval_t *r)
1198 double n;
1199 HRESULT hres;
1200 DateInstance *date;
1202 TRACE("\n");
1204 if(!(date = date_this(vthis)))
1205 return JS_E_DATE_EXPECTED;
1207 if(!argc)
1208 return JS_E_MISSING_ARG;
1210 hres = to_number(ctx, argv[0], &n);
1211 if(FAILED(hres))
1212 return hres;
1214 date->time = time_clip(n);
1216 if(r)
1217 *r = jsval_number(date->time);
1218 return S_OK;
1221 /* ECMA-262 3rd Edition 15.9.5.28 */
1222 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1223 jsval_t *r)
1225 DateInstance *date;
1226 double n, t;
1227 HRESULT hres;
1229 TRACE("\n");
1231 if(!(date = date_this(vthis)))
1232 return JS_E_DATE_EXPECTED;
1234 if(!argc)
1235 return JS_E_MISSING_ARG;
1237 hres = to_number(ctx, argv[0], &n);
1238 if(FAILED(hres))
1239 return hres;
1241 t = local_time(date->time, date);
1242 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1243 sec_from_time(t), n));
1244 date->time = time_clip(utc(t, date));
1246 if(r)
1247 *r = jsval_number(date->time);
1248 return S_OK;
1251 /* ECMA-262 3rd Edition 15.9.5.29 */
1252 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1253 jsval_t *r)
1255 DateInstance *date;
1256 double n, t;
1257 HRESULT hres;
1259 TRACE("\n");
1261 if(!(date = date_this(vthis)))
1262 return JS_E_DATE_EXPECTED;
1264 if(!argc)
1265 return JS_E_MISSING_ARG;
1267 hres = to_number(ctx, argv[0], &n);
1268 if(FAILED(hres))
1269 return hres;
1271 t = date->time;
1272 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1273 sec_from_time(t), n));
1274 date->time = time_clip(t);
1276 if(r)
1277 *r = jsval_number(date->time);
1278 return S_OK;
1281 /* ECMA-262 3rd Edition 15.9.5.30 */
1282 static HRESULT Date_setSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1283 jsval_t *r)
1285 DateInstance *date;
1286 double t, sec, ms;
1287 HRESULT hres;
1289 TRACE("\n");
1291 if(!(date = date_this(vthis)))
1292 return JS_E_DATE_EXPECTED;
1294 if(!argc)
1295 return JS_E_MISSING_ARG;
1297 t = local_time(date->time, date);
1299 hres = to_number(ctx, argv[0], &sec);
1300 if(FAILED(hres))
1301 return hres;
1303 if(argc > 1) {
1304 hres = to_number(ctx, argv[1], &ms);
1305 if(FAILED(hres))
1306 return hres;
1307 }else {
1308 ms = ms_from_time(t);
1311 t = make_date(day(t), make_time(hour_from_time(t),
1312 min_from_time(t), sec, ms));
1313 date->time = time_clip(utc(t, date));
1315 if(r)
1316 *r = jsval_number(date->time);
1317 return S_OK;
1320 /* ECMA-262 3rd Edition 15.9.5.31 */
1321 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1322 jsval_t *r)
1324 DateInstance *date;
1325 double t, sec, ms;
1326 HRESULT hres;
1328 TRACE("\n");
1330 if(!(date = date_this(vthis)))
1331 return JS_E_DATE_EXPECTED;
1333 if(!argc)
1334 return JS_E_MISSING_ARG;
1336 t = date->time;
1338 hres = to_number(ctx, argv[0], &sec);
1339 if(FAILED(hres))
1340 return hres;
1342 if(argc > 1) {
1343 hres = to_number(ctx, argv[1], &ms);
1344 if(FAILED(hres))
1345 return hres;
1346 }else {
1347 ms = ms_from_time(t);
1350 t = make_date(day(t), make_time(hour_from_time(t),
1351 min_from_time(t), sec, ms));
1352 date->time = time_clip(t);
1354 if(r)
1355 *r = jsval_number(date->time);
1356 return S_OK;
1359 /* ECMA-262 3rd Edition 15.9.5.33 */
1360 static HRESULT Date_setMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1361 jsval_t *r)
1363 DateInstance *date;
1364 double t, min, sec, ms;
1365 HRESULT hres;
1367 TRACE("\n");
1369 if(!(date = date_this(vthis)))
1370 return JS_E_DATE_EXPECTED;
1372 if(!argc)
1373 return JS_E_MISSING_ARG;
1375 t = local_time(date->time, date);
1377 hres = to_number(ctx, argv[0], &min);
1378 if(FAILED(hres))
1379 return hres;
1381 if(argc > 1) {
1382 hres = to_number(ctx, argv[1], &sec);
1383 if(FAILED(hres))
1384 return hres;
1385 }else {
1386 sec = sec_from_time(t);
1389 if(argc > 2) {
1390 hres = to_number(ctx, argv[2], &ms);
1391 if(FAILED(hres))
1392 return hres;
1393 }else {
1394 ms = ms_from_time(t);
1397 t = make_date(day(t), make_time(hour_from_time(t),
1398 min, sec, ms));
1399 date->time = time_clip(utc(t, date));
1401 if(r)
1402 *r = jsval_number(date->time);
1403 return S_OK;
1406 /* ECMA-262 3rd Edition 15.9.5.34 */
1407 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1408 jsval_t *r)
1410 DateInstance *date;
1411 double t, min, sec, ms;
1412 HRESULT hres;
1414 TRACE("\n");
1416 if(!(date = date_this(vthis)))
1417 return JS_E_DATE_EXPECTED;
1419 if(!argc)
1420 return JS_E_MISSING_ARG;
1422 t = date->time;
1424 hres = to_number(ctx, argv[0], &min);
1425 if(FAILED(hres))
1426 return hres;
1428 if(argc > 1) {
1429 hres = to_number(ctx, argv[1], &sec);
1430 if(FAILED(hres))
1431 return hres;
1432 }else {
1433 sec = sec_from_time(t);
1436 if(argc > 2) {
1437 hres = to_number(ctx, argv[2], &ms);
1438 if(FAILED(hres))
1439 return hres;
1440 }else {
1441 ms = ms_from_time(t);
1444 t = make_date(day(t), make_time(hour_from_time(t),
1445 min, sec, ms));
1446 date->time = time_clip(t);
1448 if(r)
1449 *r = jsval_number(date->time);
1450 return S_OK;
1453 /* ECMA-262 3rd Edition 15.9.5.35 */
1454 static HRESULT Date_setHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1455 jsval_t *r)
1457 DateInstance *date;
1458 double t, hour, min, sec, ms;
1459 HRESULT hres;
1461 TRACE("\n");
1463 if(!(date = date_this(vthis)))
1464 return JS_E_DATE_EXPECTED;
1466 if(!argc)
1467 return JS_E_MISSING_ARG;
1469 t = local_time(date->time, date);
1471 hres = to_number(ctx, argv[0], &hour);
1472 if(FAILED(hres))
1473 return hres;
1475 if(argc > 1) {
1476 hres = to_number(ctx, argv[1], &min);
1477 if(FAILED(hres))
1478 return hres;
1479 }else {
1480 min = min_from_time(t);
1483 if(argc > 2) {
1484 hres = to_number(ctx, argv[2], &sec);
1485 if(FAILED(hres))
1486 return hres;
1487 }else {
1488 sec = sec_from_time(t);
1491 if(argc > 3) {
1492 hres = to_number(ctx, argv[3], &ms);
1493 if(FAILED(hres))
1494 return hres;
1495 }else {
1496 ms = ms_from_time(t);
1499 t = make_date(day(t), make_time(hour, min, sec, ms));
1500 date->time = time_clip(utc(t, date));
1502 if(r)
1503 *r = jsval_number(date->time);
1504 return S_OK;
1507 /* ECMA-262 3rd Edition 15.9.5.36 */
1508 static HRESULT Date_setUTCHours(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1509 jsval_t *r)
1511 DateInstance *date;
1512 double t, hour, min, sec, ms;
1513 HRESULT hres;
1515 TRACE("\n");
1517 if(!(date = date_this(vthis)))
1518 return JS_E_DATE_EXPECTED;
1520 if(!argc)
1521 return JS_E_MISSING_ARG;
1523 t = date->time;
1525 hres = to_number(ctx, argv[0], &hour);
1526 if(FAILED(hres))
1527 return hres;
1529 if(argc > 1) {
1530 hres = to_number(ctx, argv[1], &min);
1531 if(FAILED(hres))
1532 return hres;
1533 }else {
1534 min = min_from_time(t);
1537 if(argc > 2) {
1538 hres = to_number(ctx, argv[2], &sec);
1539 if(FAILED(hres))
1540 return hres;
1541 }else {
1542 sec = sec_from_time(t);
1545 if(argc > 3) {
1546 hres = to_number(ctx, argv[3], &ms);
1547 if(FAILED(hres))
1548 return hres;
1549 }else {
1550 ms = ms_from_time(t);
1553 t = make_date(day(t), make_time(hour, min, sec, ms));
1554 date->time = time_clip(t);
1556 if(r)
1557 *r = jsval_number(date->time);
1558 return S_OK;
1561 /* ECMA-262 3rd Edition 15.9.5.36 */
1562 static HRESULT Date_setDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1563 jsval_t *r)
1565 DateInstance *date;
1566 double t, n;
1567 HRESULT hres;
1569 TRACE("\n");
1571 if(!(date = date_this(vthis)))
1572 return JS_E_DATE_EXPECTED;
1574 if(!argc)
1575 return JS_E_MISSING_ARG;
1577 hres = to_number(ctx, argv[0], &n);
1578 if(FAILED(hres))
1579 return hres;
1581 t = local_time(date->time, date);
1582 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1583 date->time = time_clip(utc(t, date));
1585 if(r)
1586 *r = jsval_number(date->time);
1587 return S_OK;
1590 /* ECMA-262 3rd Edition 15.9.5.37 */
1591 static HRESULT Date_setUTCDate(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1592 jsval_t *r)
1594 DateInstance *date;
1595 double t, n;
1596 HRESULT hres;
1598 TRACE("\n");
1600 if(!(date = date_this(vthis)))
1601 return JS_E_DATE_EXPECTED;
1603 if(!argc)
1604 return JS_E_MISSING_ARG;
1606 hres = to_number(ctx, argv[0], &n);
1607 if(FAILED(hres))
1608 return hres;
1610 t = date->time;
1611 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1612 date->time = time_clip(t);
1614 if(r)
1615 *r = jsval_number(date->time);
1616 return S_OK;
1619 /* ECMA-262 3rd Edition 15.9.5.38 */
1620 static HRESULT Date_setMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1621 jsval_t *r)
1623 DateInstance *date;
1624 DOUBLE t, month, ddate;
1625 HRESULT hres;
1627 TRACE("\n");
1629 if(!(date = date_this(vthis)))
1630 return JS_E_DATE_EXPECTED;
1632 if(!argc)
1633 return JS_E_MISSING_ARG;
1635 t = local_time(date->time, date);
1637 hres = to_number(ctx, argv[0], &month);
1638 if(FAILED(hres))
1639 return hres;
1641 if(argc > 1) {
1642 hres = to_number(ctx, argv[1], &ddate);
1643 if(FAILED(hres))
1644 return hres;
1645 }else {
1646 ddate = date_from_time(t);
1649 t = make_date(make_day(year_from_time(t), month, ddate),
1650 time_within_day(t));
1651 date->time = time_clip(utc(t, date));
1653 if(r)
1654 *r = jsval_number(date->time);
1655 return S_OK;
1658 /* ECMA-262 3rd Edition 15.9.5.39 */
1659 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1660 jsval_t *r)
1662 DateInstance *date;
1663 double t, month, ddate;
1664 HRESULT hres;
1666 TRACE("\n");
1668 if(!(date = date_this(vthis)))
1669 return JS_E_DATE_EXPECTED;
1671 if(!argc)
1672 return JS_E_MISSING_ARG;
1674 t = date->time;
1676 hres = to_number(ctx, argv[0], &month);
1677 if(FAILED(hres))
1678 return hres;
1680 if(argc > 1) {
1681 hres = to_number(ctx, argv[1], &ddate);
1682 if(FAILED(hres))
1683 return hres;
1684 }else {
1685 ddate = date_from_time(t);
1688 t = make_date(make_day(year_from_time(t), month, ddate),
1689 time_within_day(t));
1690 date->time = time_clip(t);
1692 if(r)
1693 *r = jsval_number(date->time);
1694 return S_OK;
1697 /* ECMA-262 3rd Edition 15.9.5.40 */
1698 static HRESULT Date_setFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1699 jsval_t *r)
1701 DateInstance *date;
1702 double t, year, month, ddate;
1703 HRESULT hres;
1705 TRACE("\n");
1707 if(!(date = date_this(vthis)))
1708 return JS_E_DATE_EXPECTED;
1710 if(!argc)
1711 return JS_E_MISSING_ARG;
1713 t = local_time(date->time, date);
1715 hres = to_number(ctx, argv[0], &year);
1716 if(FAILED(hres))
1717 return hres;
1719 if(argc > 1) {
1720 hres = to_number(ctx, argv[1], &month);
1721 if(FAILED(hres))
1722 return hres;
1723 }else {
1724 month = month_from_time(t);
1727 if(argc > 2) {
1728 hres = to_number(ctx, argv[2], &ddate);
1729 if(FAILED(hres))
1730 return hres;
1731 }else {
1732 ddate = date_from_time(t);
1735 t = make_date(make_day(year, month, ddate), time_within_day(t));
1736 date->time = time_clip(utc(t, date));
1738 if(r)
1739 *r = jsval_number(date->time);
1740 return S_OK;
1743 /* ECMA-262 3rd Edition 15.9.5.41 */
1744 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1745 jsval_t *r)
1747 DateInstance *date;
1748 double t, year, month, ddate;
1749 HRESULT hres;
1751 TRACE("\n");
1753 if(!(date = date_this(vthis)))
1754 return JS_E_DATE_EXPECTED;
1756 if(!argc)
1757 return JS_E_MISSING_ARG;
1759 t = date->time;
1761 hres = to_number(ctx, argv[0], &year);
1762 if(FAILED(hres))
1763 return hres;
1765 if(argc > 1) {
1766 hres = to_number(ctx, argv[1], &month);
1767 if(FAILED(hres))
1768 return hres;
1769 }else {
1770 month = month_from_time(t);
1773 if(argc > 2) {
1774 hres = to_number(ctx, argv[2], &ddate);
1775 if(FAILED(hres))
1776 return hres;
1777 }else {
1778 ddate = date_from_time(t);
1781 t = make_date(make_day(year, month, ddate), time_within_day(t));
1782 date->time = time_clip(t);
1784 if(r)
1785 *r = jsval_number(date->time);
1786 return S_OK;
1789 /* ECMA-262 3rd Edition B2.4 */
1790 static HRESULT Date_getYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1791 jsval_t *r)
1793 DateInstance *date;
1794 DOUBLE t, year;
1796 TRACE("\n");
1798 if(!(date = date_this(vthis)))
1799 return JS_E_DATE_EXPECTED;
1801 t = local_time(date->time, date);
1802 if(isnan(t)) {
1803 if(r)
1804 *r = jsval_number(NAN);
1805 return S_OK;
1808 year = year_from_time(t);
1809 if(r)
1810 *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1811 return S_OK;
1814 /* ECMA-262 3rd Edition B2.5 */
1815 static HRESULT Date_setYear(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
1816 jsval_t *r)
1818 DateInstance *date;
1819 DOUBLE t, year;
1820 HRESULT hres;
1822 TRACE("\n");
1824 if(!(date = date_this(vthis)))
1825 return JS_E_DATE_EXPECTED;
1827 if(!argc)
1828 return JS_E_MISSING_ARG;
1830 t = local_time(date->time, date);
1832 hres = to_number(ctx, argv[0], &year);
1833 if(FAILED(hres))
1834 return hres;
1836 if(isnan(year)) {
1837 date->time = year;
1838 if(r)
1839 *r = jsval_number(NAN);
1840 return S_OK;
1843 year = year >= 0.0 ? floor(year) : -floor(-year);
1844 if(-1.0 < year && year < 100.0)
1845 year += 1900.0;
1847 date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1849 if(r)
1850 *r = jsval_number(date->time);
1851 return S_OK;
1854 static const builtin_prop_t Date_props[] = {
1855 {L"getDate", Date_getDate, PROPF_METHOD},
1856 {L"getDay", Date_getDay, PROPF_METHOD},
1857 {L"getFullYear", Date_getFullYear, PROPF_METHOD},
1858 {L"getHours", Date_getHours, PROPF_METHOD},
1859 {L"getMilliseconds", Date_getMilliseconds, PROPF_METHOD},
1860 {L"getMinutes", Date_getMinutes, PROPF_METHOD},
1861 {L"getMonth", Date_getMonth, PROPF_METHOD},
1862 {L"getSeconds", Date_getSeconds, PROPF_METHOD},
1863 {L"getTime", Date_getTime, PROPF_METHOD},
1864 {L"getTimezoneOffset", Date_getTimezoneOffset, PROPF_METHOD},
1865 {L"getUTCDate", Date_getUTCDate, PROPF_METHOD},
1866 {L"getUTCDay", Date_getUTCDay, PROPF_METHOD},
1867 {L"getUTCFullYear", Date_getUTCFullYear, PROPF_METHOD},
1868 {L"getUTCHours", Date_getUTCHours, PROPF_METHOD},
1869 {L"getUTCMilliseconds", Date_getUTCMilliseconds, PROPF_METHOD},
1870 {L"getUTCMinutes", Date_getUTCMinutes, PROPF_METHOD},
1871 {L"getUTCMonth", Date_getUTCMonth, PROPF_METHOD},
1872 {L"getUTCSeconds", Date_getUTCSeconds, PROPF_METHOD},
1873 {L"getYear", Date_getYear, PROPF_METHOD},
1874 {L"setDate", Date_setDate, PROPF_METHOD|1},
1875 {L"setFullYear", Date_setFullYear, PROPF_METHOD|3},
1876 {L"setHours", Date_setHours, PROPF_METHOD|4},
1877 {L"setMilliseconds", Date_setMilliseconds, PROPF_METHOD|1},
1878 {L"setMinutes", Date_setMinutes, PROPF_METHOD|3},
1879 {L"setMonth", Date_setMonth, PROPF_METHOD|2},
1880 {L"setSeconds", Date_setSeconds, PROPF_METHOD|2},
1881 {L"setTime", Date_setTime, PROPF_METHOD|1},
1882 {L"setUTCDate", Date_setUTCDate, PROPF_METHOD|1},
1883 {L"setUTCFullYear", Date_setUTCFullYear, PROPF_METHOD|3},
1884 {L"setUTCHours", Date_setUTCHours, PROPF_METHOD|4},
1885 {L"setUTCMilliseconds", Date_setUTCMilliseconds, PROPF_METHOD|1},
1886 {L"setUTCMinutes", Date_setUTCMinutes, PROPF_METHOD|3},
1887 {L"setUTCMonth", Date_setUTCMonth, PROPF_METHOD|2},
1888 {L"setUTCSeconds", Date_setUTCSeconds, PROPF_METHOD|2},
1889 {L"setYear", Date_setYear, PROPF_METHOD|1},
1890 {L"toDateString", Date_toDateString, PROPF_METHOD},
1891 {L"toGMTString", Date_toGMTString, PROPF_METHOD},
1892 {L"toISOString", Date_toISOString, PROPF_METHOD|PROPF_ES5},
1893 {L"toLocaleDateString", Date_toLocaleDateString, PROPF_METHOD},
1894 {L"toLocaleString", Date_toLocaleString, PROPF_METHOD},
1895 {L"toLocaleTimeString", Date_toLocaleTimeString, PROPF_METHOD},
1896 {L"toString", Date_toString, PROPF_METHOD},
1897 {L"toTimeString", Date_toTimeString, PROPF_METHOD},
1898 {L"toUTCString", Date_toUTCString, PROPF_METHOD},
1899 {L"valueOf", Date_valueOf, PROPF_METHOD},
1902 static const builtin_info_t Date_info = {
1903 JSCLASS_DATE,
1904 NULL,
1905 ARRAY_SIZE(Date_props),
1906 Date_props,
1907 NULL,
1908 NULL
1911 static const builtin_info_t DateInst_info = {
1912 JSCLASS_DATE,
1913 NULL,
1914 0, NULL,
1915 NULL,
1916 NULL
1919 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, DateInstance **ret)
1921 DateInstance *date;
1922 HRESULT hres;
1923 TIME_ZONE_INFORMATION tzi;
1925 GetTimeZoneInformation(&tzi);
1927 date = calloc(1, sizeof(DateInstance));
1928 if(!date)
1929 return E_OUTOFMEMORY;
1931 if(object_prototype)
1932 hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
1933 else
1934 hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
1935 if(FAILED(hres)) {
1936 free(date);
1937 return hres;
1940 date->time = time;
1941 date->bias = tzi.Bias;
1942 date->standardDate = tzi.StandardDate;
1943 date->standardBias = tzi.StandardBias;
1944 date->daylightDate = tzi.DaylightDate;
1945 date->daylightBias = tzi.DaylightBias;
1947 *ret = date;
1948 return S_OK;
1951 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
1952 static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
1953 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
1954 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
1955 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
1956 LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
1957 LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
1958 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
1959 WCHAR *strings[ARRAY_SIZE(string_ids)];
1960 WCHAR *parse;
1961 int input_len, parse_len = 0, nest_level = 0, i, size;
1962 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
1963 int ms = 0, offset = 0, hour_adjust = 0;
1964 BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
1965 BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
1966 BOOL set_hour_adjust = TRUE;
1967 TIME_ZONE_INFORMATION tzi;
1968 const WCHAR *input;
1969 DateInstance di;
1970 DWORD lcid_en;
1972 input_len = jsstr_length(input_str);
1973 input = jsstr_flatten(input_str);
1974 if(!input)
1975 return E_OUTOFMEMORY;
1977 for(i=0; i<input_len; i++) {
1978 if(input[i] == '(') nest_level++;
1979 else if(input[i] == ')') {
1980 nest_level--;
1981 if(nest_level<0) {
1982 *ret = NAN;
1983 return S_OK;
1986 else if(!nest_level) parse_len++;
1989 parse = malloc((parse_len+1)*sizeof(WCHAR));
1990 if(!parse)
1991 return E_OUTOFMEMORY;
1992 nest_level = 0;
1993 parse_len = 0;
1994 for(i=0; i<input_len; i++) {
1995 if(input[i] == '(') nest_level++;
1996 else if(input[i] == ')') nest_level--;
1997 else if(!nest_level) parse[parse_len++] = towupper(input[i]);
1999 parse[parse_len] = 0;
2001 GetTimeZoneInformation(&tzi);
2002 di.bias = tzi.Bias;
2003 di.standardDate = tzi.StandardDate;
2004 di.standardBias = tzi.StandardBias;
2005 di.daylightDate = tzi.DaylightDate;
2006 di.daylightBias = tzi.DaylightBias;
2008 /* FIXME: Cache strings */
2009 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2010 for(i=0; i<ARRAY_SIZE(string_ids); i++) {
2011 size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2012 strings[i] = malloc((size+1)*sizeof(WCHAR));
2013 if(!strings[i]) {
2014 i--;
2015 while(i-- >= 0)
2016 free(strings[i]);
2017 free(parse);
2018 return E_OUTOFMEMORY;
2020 GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2023 for(i=0; i<parse_len;) {
2024 while(iswspace(parse[i])) i++;
2025 if(parse[i] == ',') {
2026 while(parse[i] == ',') i++;
2027 continue;
2030 if(parse[i]>='0' && parse[i]<='9') {
2031 int tmp = wcstol(&parse[i], NULL, 10);
2032 while(parse[i]>='0' && parse[i]<='9') i++;
2033 while(iswspace(parse[i])) i++;
2035 if(parse[i] == ':') {
2036 /* Time */
2037 if(set_hour) break;
2038 set_hour = TRUE;
2040 hour = tmp;
2042 while(parse[i] == ':') i++;
2043 while(iswspace(parse[i])) i++;
2044 if(parse[i]>='0' && parse[i]<='9') {
2045 min = wcstol(&parse[i], NULL, 10);
2046 while(parse[i]>='0' && parse[i]<='9') i++;
2049 while(iswspace(parse[i])) i++;
2050 while(parse[i] == ':') i++;
2051 while(iswspace(parse[i])) i++;
2052 if(parse[i]>='0' && parse[i]<='9') {
2053 sec = wcstol(&parse[i], NULL, 10);
2054 while(parse[i]>='0' && parse[i]<='9') i++;
2057 else if(parse[i]=='-' || parse[i]=='/') {
2058 /* Short or long date */
2059 if(set_day || set_month || set_year) break;
2060 set_day = TRUE;
2061 set_month = TRUE;
2062 set_year = TRUE;
2064 month = tmp-1;
2066 while(iswspace(parse[i])) i++;
2067 while(parse[i]=='-' || parse[i]=='/') i++;
2068 while(iswspace(parse[i])) i++;
2069 if(parse[i]<'0' || parse[i]>'9') break;
2070 day = wcstol(&parse[i], NULL, 10);
2071 while(parse[i]>='0' && parse[i]<='9') i++;
2073 while(parse[i]=='-' || parse[i]=='/') i++;
2074 while(iswspace(parse[i])) i++;
2075 if(parse[i]<'0' || parse[i]>'9') break;
2076 year = wcstol(&parse[i], NULL, 10);
2077 while(parse[i]>='0' && parse[i]<='9') i++;
2079 if(tmp >= 70){
2080 /* long date */
2081 month = day - 1;
2082 day = year;
2083 year = tmp;
2086 else if(tmp<0) break;
2087 else if(tmp<70) {
2088 /* Day */
2089 if(set_day) break;
2090 set_day = TRUE;
2091 day = tmp;
2093 else {
2094 /* Year */
2095 if(set_year) break;
2096 set_year = TRUE;
2097 year = tmp;
2100 else if(parse[i]=='+' || parse[i]=='-') {
2101 /* Timezone offset */
2102 BOOL positive = TRUE;
2104 if(set_offset && set_hour_adjust) break;
2105 set_offset = TRUE;
2106 set_hour_adjust = FALSE;
2108 if(parse[i] == '-') positive = FALSE;
2110 i++;
2111 while(iswspace(parse[i])) i++;
2112 if(parse[i]<'0' || parse[i]>'9') break;
2113 offset = wcstol(&parse[i], NULL, 10);
2114 while(parse[i]>='0' && parse[i]<='9') i++;
2116 if(offset<24) offset *= 60;
2117 else offset = (offset/100)*60 + offset%100;
2119 if(positive) offset = -offset;
2122 else {
2123 if(parse[i]<'A' || parse[i]>'Z') break;
2124 else if(parse[i]=='B' && (parse[i+1]=='C' ||
2125 (parse[i+1]=='.' && parse[i+2]=='C'))) {
2126 /* AD/BC */
2127 if(set_era) break;
2128 set_era = TRUE;
2129 ad = FALSE;
2131 i++;
2132 if(parse[i] == '.') i++;
2133 i++;
2134 if(parse[i] == '.') i++;
2136 else if(parse[i]=='A' && (parse[i+1]=='D' ||
2137 (parse[i+1]=='.' && parse[i+2]=='D'))) {
2138 /* AD/BC */
2139 if(set_era) break;
2140 set_era = TRUE;
2142 i++;
2143 if(parse[i] == '.') i++;
2144 i++;
2145 if(parse[i] == '.') i++;
2147 else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2148 /* Timezone */
2149 if(set_offset) break;
2150 set_offset = TRUE;
2152 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2153 else if(parse[i] == 'J') break;
2154 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2155 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2156 else hour_adjust = 1;
2158 i++;
2159 if(parse[i] == '.') i++;
2161 else if(parse[i]=='A' && parse[i+1]=='M') {
2162 /* AM/PM */
2163 if(set_am) break;
2164 set_am = TRUE;
2165 am = TRUE;
2166 i += 2;
2168 else if(parse[i]=='P' && parse[i+1]=='M') {
2169 /* AM/PM */
2170 if(set_am) break;
2171 set_am = TRUE;
2172 am = FALSE;
2173 i += 2;
2175 else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2176 || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2177 /* Timezone */
2178 if(set_offset) break;
2179 set_offset = TRUE;
2180 set_hour_adjust = FALSE;
2182 i += 3;
2184 else {
2185 /* Month or garbage */
2186 unsigned int j;
2188 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2189 size -= i;
2191 for(j=0; j<ARRAY_SIZE(string_ids); j++)
2192 if(!wcsnicmp(&parse[i], strings[j], size)) break;
2194 if(j < 12) {
2195 if(set_month) break;
2196 set_month = TRUE;
2197 month = 11-j;
2199 else if(j == ARRAY_SIZE(string_ids)) break;
2201 i += size;
2206 if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2207 if(set_am) {
2208 if(hour == 12) hour = 0;
2209 if(!am) hour += 12;
2212 if(!ad) year = -year+1;
2213 else if(year<100) year += 1900;
2215 *ret = time_clip(make_date(make_day(year, month, day),
2216 make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2218 if(set_hour_adjust)
2219 *ret = utc(*ret, &di);
2220 }else {
2221 *ret = NAN;
2224 for(i=0; i<ARRAY_SIZE(string_ids); i++)
2225 free(strings[i]);
2226 free(parse);
2228 return S_OK;
2231 static HRESULT DateConstr_parse(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
2232 jsval_t *r)
2234 jsstr_t *parse_str;
2235 double n;
2236 HRESULT hres;
2238 TRACE("\n");
2240 if(!argc) {
2241 if(r)
2242 *r = jsval_number(NAN);
2243 return S_OK;
2246 hres = to_string(ctx, argv[0], &parse_str);
2247 if(FAILED(hres))
2248 return hres;
2250 hres = date_parse(parse_str, &n);
2251 jsstr_release(parse_str);
2252 if(FAILED(hres))
2253 return hres;
2255 if(r)
2256 *r = jsval_number(n);
2257 return S_OK;
2260 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2262 double year, month, vdate, hours, minutes, seconds, ms;
2263 HRESULT hres;
2265 TRACE("\n");
2267 if(argc) {
2268 hres = to_number(ctx, argv[0], &year);
2269 if(FAILED(hres))
2270 return hres;
2271 if(0 <= year && year <= 99)
2272 year += 1900;
2273 }else {
2274 year = 1900;
2277 if(argc>1) {
2278 hres = to_number(ctx, argv[1], &month);
2279 if(FAILED(hres))
2280 return hres;
2281 }else {
2282 month = 0;
2285 if(argc>2) {
2286 hres = to_number(ctx, argv[2], &vdate);
2287 if(FAILED(hres))
2288 return hres;
2289 }else {
2290 vdate = 1;
2293 if(argc>3) {
2294 hres = to_number(ctx, argv[3], &hours);
2295 if(FAILED(hres))
2296 return hres;
2297 }else {
2298 hours = 0;
2301 if(argc>4) {
2302 hres = to_number(ctx, argv[4], &minutes);
2303 if(FAILED(hres))
2304 return hres;
2305 }else {
2306 minutes = 0;
2309 if(argc>5) {
2310 hres = to_number(ctx, argv[5], &seconds);
2311 if(FAILED(hres))
2312 return hres;
2313 }else {
2314 seconds = 0;
2317 if(argc>6) {
2318 hres = to_number(ctx, argv[6], &ms);
2319 if(FAILED(hres))
2320 return hres;
2321 } else {
2322 ms = 0;
2325 *ret = time_clip(make_date(make_day(year, month, vdate),
2326 make_time(hours, minutes,seconds, ms)));
2327 return S_OK;
2330 static HRESULT DateConstr_UTC(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
2331 jsval_t *r)
2333 double n;
2334 HRESULT hres;
2336 TRACE("\n");
2338 hres = date_utc(ctx, argc, argv, &n);
2339 if(SUCCEEDED(hres) && r)
2340 *r = jsval_number(n);
2341 return hres;
2344 /* ECMA-262 5.1 Edition 15.9.4.4 */
2345 static HRESULT DateConstr_now(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
2347 TRACE("\n");
2349 if(r) *r = jsval_number(date_now());
2350 return S_OK;
2353 static HRESULT DateConstr_value(script_ctx_t *ctx, jsval_t vthis, WORD flags, unsigned argc, jsval_t *argv,
2354 jsval_t *r)
2356 DateInstance *date;
2357 HRESULT hres;
2359 TRACE("\n");
2361 switch(flags) {
2362 case DISPATCH_CONSTRUCT:
2363 switch(argc) {
2364 /* ECMA-262 3rd Edition 15.9.3.3 */
2365 case 0:
2366 hres = create_date(ctx, NULL, date_now(), &date);
2367 if(FAILED(hres))
2368 return hres;
2369 break;
2371 /* ECMA-262 3rd Edition 15.9.3.2 */
2372 case 1: {
2373 jsval_t prim;
2374 double n;
2376 hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2377 if(FAILED(hres))
2378 return hres;
2380 if(is_string(prim))
2381 hres = date_parse(get_string(prim), &n);
2382 else
2383 hres = to_number(ctx, prim, &n);
2385 jsval_release(prim);
2386 if(FAILED(hres))
2387 return hres;
2389 hres = create_date(ctx, NULL, time_clip(n), &date);
2390 if(FAILED(hres))
2391 return hres;
2392 break;
2395 /* ECMA-262 3rd Edition 15.9.3.1 */
2396 default: {
2397 double ret_date;
2399 hres = date_utc(ctx, argc, argv, &ret_date);
2400 if(FAILED(hres))
2401 return hres;
2403 hres = create_date(ctx, NULL, ret_date, &date);
2404 if(FAILED(hres))
2405 return hres;
2407 date->time = utc(date->time, date);
2411 if(r) *r = jsval_obj(&date->dispex);
2412 else jsdisp_release(&date->dispex);
2413 return S_OK;
2415 case INVOKE_FUNC: {
2416 FILETIME system_time, local_time;
2418 GetSystemTimeAsFileTime(&system_time);
2419 FileTimeToLocalFileTime(&system_time, &local_time);
2421 return date_to_string(file_time_to_date_time(&local_time), FALSE, 0, r);
2424 default:
2425 FIXME("unimplemented flags %x\n", flags);
2426 return E_NOTIMPL;
2429 return S_OK;
2432 static const builtin_prop_t DateConstr_props[] = {
2433 {L"UTC", DateConstr_UTC, PROPF_METHOD},
2434 {L"now", DateConstr_now, PROPF_HTML|PROPF_METHOD},
2435 {L"parse", DateConstr_parse, PROPF_METHOD}
2438 static const builtin_info_t DateConstr_info = {
2439 JSCLASS_FUNCTION,
2440 Function_value,
2441 ARRAY_SIZE(DateConstr_props),
2442 DateConstr_props,
2443 NULL,
2444 NULL
2447 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2449 DateInstance *date;
2450 HRESULT hres;
2452 hres = create_date(ctx, object_prototype, 0.0, &date);
2453 if(FAILED(hres))
2454 return hres;
2456 hres = create_builtin_constructor(ctx, DateConstr_value, L"Date", &DateConstr_info,
2457 PROPF_CONSTR|7, &date->dispex, ret);
2459 jsdisp_release(&date->dispex);
2460 return hres;
2463 HRESULT variant_date_to_number(double date, double *ret)
2465 SYSTEMTIME st;
2466 UDATE udate;
2467 HRESULT hres;
2469 hres = VarUdateFromDate(date, 0, &udate);
2470 if(FAILED(hres))
2471 return hres;
2473 if(!TzSpecificLocalTimeToSystemTime(NULL, &udate.st, &st))
2474 return E_FAIL;
2476 TRACE("%uy %um %u %ud %uh %um %u.%us\n", st.wYear, st.wMonth, st.wDayOfWeek, st.wDay, st.wHour, st.wMinute,
2477 st.wSecond, st.wMilliseconds);
2479 *ret = make_date(make_day(st.wYear, st.wMonth - 1, st.wDay),
2480 make_time(st.wHour, st.wMinute, st.wSecond, st.wMilliseconds));
2481 return S_OK;
2484 HRESULT variant_date_to_string(script_ctx_t *ctx, double date, jsstr_t **r)
2486 DateInstance *date_obj;
2487 jsval_t val;
2488 double time;
2489 HRESULT hres;
2491 hres = variant_date_to_number(date, &time);
2492 if(FAILED(hres))
2493 return hres;
2495 hres = create_date(ctx, NULL, time, &date_obj);
2496 if(FAILED(hres))
2497 return hres;
2499 hres = dateobj_to_string(date_obj, &val);
2500 jsdisp_release(&date_obj->dispex);
2501 if(FAILED(hres))
2502 return hres;
2504 assert(is_string(val));
2505 *r = get_string(val);
2506 return hres;