ntdll/tests: Remove duplicated entry.
[wine.git] / dlls / jscript / date.c
blob81b714fe92ad0734ba224a23739d372c5ed42ec5
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
20 #include "config.h"
21 #include "wine/port.h"
23 #include <limits.h>
24 #include <math.h>
25 #include <assert.h>
27 #include "jscript.h"
29 #include "wine/debug.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
33 /* 1601 to 1970 is 369 years plus 89 leap days */
34 #define TIME_EPOCH ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
36 typedef struct {
37 jsdisp_t dispex;
39 /* ECMA-262 3rd Edition 15.9.1.1 */
40 DOUBLE time;
42 LONG bias;
43 SYSTEMTIME standardDate;
44 LONG standardBias;
45 SYSTEMTIME daylightDate;
46 LONG daylightBias;
47 } DateInstance;
49 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
50 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
51 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
52 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
53 static const WCHAR toGMTStringW[] = {'t','o','G','M','T','S','t','r','i','n','g',0};
54 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
55 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
56 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
57 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
58 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
59 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
60 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
61 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
62 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
63 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
64 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
65 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
66 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
67 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
68 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
69 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
70 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
71 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
72 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
73 static const WCHAR getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
74 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
75 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
76 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
77 static const WCHAR setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
78 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','l','i','s','e','c','o','n','d','s',0};
79 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
80 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
81 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
82 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
83 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
84 static const WCHAR setUTCHoursW[] = {'s','e','t','U','T','C','H','o','u','r','s',0};
85 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
86 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
87 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
88 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
89 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
90 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
91 static const WCHAR getYearW[] = {'g','e','t','Y','e','a','r',0};
92 static const WCHAR setYearW[] = {'s','e','t','Y','e','a','r',0};
94 static const WCHAR UTCW[] = {'U','T','C',0};
95 static const WCHAR parseW[] = {'p','a','r','s','e',0};
97 static inline DateInstance *date_this(vdisp_t *jsthis)
99 return is_vclass(jsthis, JSCLASS_DATE) ? (DateInstance*)jsthis->u.jsdisp : NULL;
102 /*ECMA-262 3rd Edition 15.9.1.2 */
103 #define MS_PER_DAY 86400000
104 #define MS_PER_HOUR 3600000
105 #define MS_PER_MINUTE 60000
107 /* ECMA-262 3rd Edition 15.9.1.2 */
108 static inline DOUBLE day(DOUBLE time)
110 return floor(time / MS_PER_DAY);
113 /* ECMA-262 3rd Edition 15.9.1.2 */
114 static inline DOUBLE time_within_day(DOUBLE time)
116 DOUBLE ret;
118 ret = fmod(time, MS_PER_DAY);
119 if(ret < 0)
120 ret += MS_PER_DAY;
122 return ret;
125 /* ECMA-262 3rd Edition 15.9.1.3 */
126 static inline DOUBLE days_in_year(DOUBLE year)
128 int y;
130 if(year != (int)year)
131 return NAN;
133 y = year;
134 if(y%4 != 0) return 365;
135 if(y%100 != 0) return 366;
136 if(y%400 != 0) return 365;
137 return 366;
140 /* ECMA-262 3rd Edition 15.9.1.3 */
141 static inline DOUBLE day_from_year(DOUBLE year)
143 if(year != (int)year)
144 return NAN;
146 return floor(365.0*(year-1970) + floor((year-1969)/4)
147 - floor((year-1901)/100) + floor((year-1601)/400));
150 static inline int day_from_month(int month, int in_leap_year)
152 switch(month)
154 case 0:
155 return 0;
156 case 1:
157 return 31;
158 case 2:
159 return 59+in_leap_year;
160 case 3:
161 return 90+in_leap_year;
162 case 4:
163 return 120+in_leap_year;
164 case 5:
165 return 151+in_leap_year;
166 case 6:
167 return 181+in_leap_year;
168 case 7:
169 return 212+in_leap_year;
170 case 8:
171 return 243+in_leap_year;
172 case 9:
173 return 273+in_leap_year;
174 case 10:
175 return 304+in_leap_year;
176 default:
177 return 334+in_leap_year;
181 /* ECMA-262 3rd Edition 15.9.1.3 */
182 static inline DOUBLE time_from_year(DOUBLE year)
184 return MS_PER_DAY*day_from_year(year);
187 /* ECMA-262 3rd Edition 15.9.1.3 */
188 static inline DOUBLE year_from_time(DOUBLE time)
190 int y;
192 if(isnan(time))
193 return NAN;
195 y = 1970 + time/365.25/MS_PER_DAY;
197 if(time_from_year(y) > time)
198 while(time_from_year(y) > time) y--;
199 else
200 while(time_from_year(y+1)<=time) y++;
202 return y;
205 /* ECMA-262 3rd Edition 15.9.1.3 */
206 static inline int in_leap_year(DOUBLE time)
208 if(days_in_year(year_from_time(time))==366)
209 return 1;
210 return 0;
213 /* ECMA-262 3rd Edition 15.9.1.4 */
214 static inline int day_within_year(DOUBLE time)
216 return day(time) - day_from_year(year_from_time(time));
219 /* ECMA-262 3rd Edition 15.9.1.4 */
220 static inline DOUBLE month_from_time(DOUBLE time)
222 int ily = in_leap_year(time);
223 int dwy = day_within_year(time);
225 if(isnan(time))
226 return NAN;
228 if(0<=dwy && dwy<31) return 0;
229 if(dwy < 59+ily) return 1;
230 if(dwy < 90+ily) return 2;
231 if(dwy < 120+ily) return 3;
232 if(dwy < 151+ily) return 4;
233 if(dwy < 181+ily) return 5;
234 if(dwy < 212+ily) return 6;
235 if(dwy < 243+ily) return 7;
236 if(dwy < 273+ily) return 8;
237 if(dwy < 304+ily) return 9;
238 if(dwy < 334+ily) return 10;
239 return 11;
242 /* ECMA-262 3rd Edition 15.9.1.5 */
243 static inline DOUBLE date_from_time(DOUBLE time)
245 int dwy = day_within_year(time);
246 int ily = in_leap_year(time);
247 int mft = month_from_time(time);
249 if(isnan(time))
250 return NAN;
252 if(mft==0) return dwy+1;
253 if(mft==1) return dwy-30;
254 if(mft==2) return dwy-58-ily;
255 if(mft==3) return dwy-89-ily;
256 if(mft==4) return dwy-119-ily;
257 if(mft==5) return dwy-150-ily;
258 if(mft==6) return dwy-180-ily;
259 if(mft==7) return dwy-211-ily;
260 if(mft==8) return dwy-242-ily;
261 if(mft==9) return dwy-272-ily;
262 if(mft==10) return dwy-303-ily;
263 return dwy-333-ily;
266 /* ECMA-262 3rd Edition 15.9.1.6 */
267 static inline DOUBLE week_day(DOUBLE time)
269 DOUBLE ret;
271 if(isnan(time))
272 return NAN;
274 ret = fmod(day(time)+4, 7);
275 if(ret<0) ret += 7;
277 return ret;
280 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
282 DOUBLE time;
283 int set_week_day;
285 if(st.wMonth == 0)
286 return NAN;
288 if(st.wYear != 0)
289 year = st.wYear;
291 time = time_from_year(year);
292 time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
294 if(st.wYear == 0) {
295 set_week_day = st.wDayOfWeek-week_day(time);
296 if(set_week_day < 0)
297 set_week_day += 7;
298 time += set_week_day * MS_PER_DAY;
300 time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
301 if(month_from_time(time) != st.wMonth-1)
302 time -= 7 * MS_PER_DAY;
304 else
305 time += st.wDay * MS_PER_DAY;
307 time += st.wHour * MS_PER_HOUR;
308 time += st.wMinute * MS_PER_MINUTE;
310 return time;
313 /* ECMA-262 3rd Edition 15.9.1.9 */
314 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
316 int year = year_from_time(time);
317 DOUBLE standardTime, daylightTime;
319 if(isnan(time))
320 return 0;
322 standardTime = convert_time(year, date->standardDate);
323 daylightTime = convert_time(year, date->daylightDate);
325 if(isnan(standardTime) || isnan(daylightTime))
326 return 0;
327 else if(standardTime > daylightTime) {
328 if(daylightTime <= time && time < standardTime)
329 return date->daylightBias;
331 return date->standardBias;
333 else {
334 if(standardTime <= time && time < daylightTime)
335 return date->standardBias;
337 return date->daylightBias;
341 /* ECMA-262 3rd Edition 15.9.1.9 */
342 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
344 return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
347 /* ECMA-262 3rd Edition 15.9.1.9 */
348 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
350 time += date->bias * MS_PER_MINUTE;
351 return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
354 /* ECMA-262 3rd Edition 15.9.1.10 */
355 static inline DOUBLE hour_from_time(DOUBLE time)
357 DOUBLE ret;
359 if(isnan(time))
360 return NAN;
362 ret = fmod(floor(time/MS_PER_HOUR), 24);
363 if(ret<0) ret += 24;
365 return ret;
368 /* ECMA-262 3rd Edition 15.9.1.10 */
369 static inline DOUBLE min_from_time(DOUBLE time)
371 DOUBLE ret;
373 if(isnan(time))
374 return NAN;
376 ret = fmod(floor(time/MS_PER_MINUTE), 60);
377 if(ret<0) ret += 60;
379 return ret;
382 /* ECMA-262 3rd Edition 15.9.1.10 */
383 static inline DOUBLE sec_from_time(DOUBLE time)
385 DOUBLE ret;
387 if(isnan(time))
388 return NAN;
390 ret = fmod(floor(time/1000), 60);
391 if(ret<0) ret += 60;
393 return ret;
396 /* ECMA-262 3rd Edition 15.9.1.10 */
397 static inline DOUBLE ms_from_time(DOUBLE time)
399 DOUBLE ret;
401 if(isnan(time))
402 return NAN;
404 ret = fmod(time, 1000);
405 if(ret<0) ret += 1000;
407 return ret;
410 /* ECMA-262 3rd Edition 15.9.1.11 */
411 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
413 return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
416 /* ECMA-262 3rd Edition 15.9.1.12 */
417 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
419 DOUBLE time;
421 year += floor(month/12);
423 month = fmod(month, 12);
424 if(month<0) month += 12;
426 time = time_from_year(year);
428 day += floor(time / MS_PER_DAY);
429 day += day_from_month(month, in_leap_year(time));
431 return day-1;
434 /* ECMA-262 3rd Edition 15.9.1.13 */
435 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
437 return day*MS_PER_DAY + time;
440 /* ECMA-262 3rd Edition 15.9.1.14 */
441 static inline DOUBLE time_clip(DOUBLE time)
443 if(8.64e15 < time || time < -8.64e15) {
444 return NAN;
447 return floor(time);
450 static SYSTEMTIME create_systemtime(DOUBLE time)
452 SYSTEMTIME st;
454 st.wYear = year_from_time(time);
455 st.wMonth = month_from_time(time) + 1;
456 st.wDayOfWeek = week_day(time);
457 st.wDay = date_from_time(time);
458 st.wHour = hour_from_time(time);
459 st.wMinute = min_from_time(time);
460 st.wSecond = sec_from_time(time);
461 st.wMilliseconds = ms_from_time(time);
463 return st;
466 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
468 static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
469 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
470 'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
471 static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
472 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
473 'U','T','C',' ','%','d','%','s',0 };
474 static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
475 '%','d',' ','%','0','2','d',':','%','0','2','d',':',
476 '%','0','2','d',' ','%','d','%','s',0 };
477 static const WCHAR ADW[] = { 0 };
478 static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
480 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
481 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
482 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
483 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
484 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
485 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
486 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
487 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
488 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
490 BOOL formatAD = TRUE;
491 WCHAR week[64], month[64];
492 jsstr_t *date_jsstr;
493 int len, size, year, day;
494 DWORD lcid_en;
495 WCHAR sign = '-';
497 if(isnan(time)) {
498 if(r)
499 *r = jsval_string(jsstr_nan());
500 return S_OK;
503 if(r) {
504 WCHAR *date_str;
506 len = 21;
508 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
510 size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
511 assert(size);
512 len += size-1;
514 size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
515 len += size-1;
517 year = year_from_time(time);
518 if(year<0)
519 year = -year+1;
520 do {
521 year /= 10;
522 len++;
523 } while(year);
525 year = year_from_time(time);
526 if(year<0) {
527 formatAD = FALSE;
528 year = -year+1;
529 len += 5;
532 day = date_from_time(time);
533 do {
534 day /= 10;
535 len++;
536 } while(day);
537 day = date_from_time(time);
539 if(!show_offset) len -= 9;
540 else if(offset == 0) len -= 5;
541 else if(offset < 0) {
542 sign = '+';
543 offset = -offset;
546 date_str = jsstr_alloc_buf(len, &date_jsstr);
547 if(!date_str)
548 return E_OUTOFMEMORY;
550 if(!show_offset)
551 sprintfW(date_str, formatNoOffsetW, week, month, day,
552 (int)hour_from_time(time), (int)min_from_time(time),
553 (int)sec_from_time(time), year, formatAD?ADW:BCW);
554 else if(offset)
555 sprintfW(date_str, formatW, week, month, day,
556 (int)hour_from_time(time), (int)min_from_time(time),
557 (int)sec_from_time(time), sign, offset/60, offset%60,
558 year, formatAD?ADW:BCW);
559 else
560 sprintfW(date_str, formatUTCW, week, month, day,
561 (int)hour_from_time(time), (int)min_from_time(time),
562 (int)sec_from_time(time), year, formatAD?ADW:BCW);
564 *r = jsval_string(date_jsstr);
566 return S_OK;
569 /* ECMA-262 3rd Edition 15.9.1.2 */
570 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
572 DOUBLE time;
573 int offset;
575 time = local_time(date->time, date);
576 offset = date->bias +
577 daylight_saving_ta(time, date);
579 return date_to_string(time, TRUE, offset, r);
582 static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
584 DateInstance *date;
586 TRACE("\n");
588 if(!(date = date_this(jsthis)))
589 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
591 return dateobj_to_string(date, r);
594 /* ECMA-262 3rd Edition 15.9.1.5 */
595 static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
596 jsval_t *r)
598 SYSTEMTIME st;
599 DateInstance *date;
600 jsstr_t *date_str;
601 int date_len, time_len;
603 TRACE("\n");
605 if(!(date = date_this(jsthis)))
606 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
608 if(isnan(date->time)) {
609 if(r)
610 *r = jsval_string(jsstr_nan());
611 return S_OK;
614 st = create_systemtime(local_time(date->time, date));
616 if(st.wYear<1601 || st.wYear>9999)
617 return dateobj_to_string(date, r);
619 if(r) {
620 WCHAR *ptr;
622 date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
623 time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
625 ptr = jsstr_alloc_buf(date_len+time_len-1, &date_str);
626 if(!date_str)
627 return E_OUTOFMEMORY;
629 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
630 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
631 ptr[date_len-1] = ' ';
633 *r = jsval_string(date_str);
635 return S_OK;
638 static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
639 jsval_t *r)
641 DateInstance *date;
643 TRACE("\n");
645 if(!(date = date_this(jsthis)))
646 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
648 if(r)
649 *r = jsval_number(date->time);
650 return S_OK;
653 static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
655 static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
656 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
657 static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
658 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
660 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
661 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
662 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
663 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
664 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
665 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
666 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
667 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
668 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
670 BOOL formatAD = TRUE;
671 WCHAR week[64], month[64];
672 DateInstance *date;
673 jsstr_t *date_str;
674 int len, size, year, day;
675 DWORD lcid_en;
677 if(!(date = date_this(jsthis)))
678 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
680 if(isnan(date->time)) {
681 if(r)
682 *r = jsval_string(jsstr_nan());
683 return S_OK;
686 if(r) {
687 WCHAR *ptr;
689 len = 17;
691 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
693 size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, sizeof(week)/sizeof(*week));
694 len += size-1;
696 size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, sizeof(month)/sizeof(*month));
697 len += size-1;
699 year = year_from_time(date->time);
700 if(year<0)
701 year = -year+1;
702 do {
703 year /= 10;
704 len++;
705 } while(year);
707 year = year_from_time(date->time);
708 if(year<0) {
709 formatAD = FALSE;
710 year = -year+1;
711 len += 5;
714 day = date_from_time(date->time);
715 do {
716 day /= 10;
717 len++;
718 } while(day);
719 day = date_from_time(date->time);
721 ptr = jsstr_alloc_buf(len, &date_str);
722 if(!date_str)
723 return E_OUTOFMEMORY;
725 sprintfW(ptr, formatAD?formatADW:formatBCW, week, day, month, year,
726 (int)hour_from_time(date->time), (int)min_from_time(date->time),
727 (int)sec_from_time(date->time));
729 *r = jsval_string(date_str);
731 return S_OK;
734 /* ECMA-262 3rd Edition 15.9.5.42 */
735 static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
736 jsval_t *r)
738 TRACE("\n");
739 return create_utc_string(ctx, jsthis, r);
742 static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
743 jsval_t *r)
745 TRACE("\n");
746 return create_utc_string(ctx, jsthis, r);
749 /* ECMA-262 3rd Edition 15.9.5.3 */
750 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
752 static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
753 static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
755 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
756 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
757 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
758 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
759 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
760 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
761 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
762 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
763 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
765 BOOL formatAD = TRUE;
766 WCHAR week[64], month[64];
767 jsstr_t *date_str;
768 DOUBLE time;
769 int len, size, year, day;
770 DWORD lcid_en;
772 if(isnan(date->time)) {
773 if(r)
774 *r = jsval_string(jsstr_nan());
775 return S_OK;
778 time = local_time(date->time, date);
780 if(r) {
781 WCHAR *ptr;
783 len = 5;
785 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
787 size = GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
788 assert(size);
789 len += size-1;
791 size = GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
792 assert(size);
793 len += size-1;
795 year = year_from_time(time);
796 if(year<0)
797 year = -year+1;
798 do {
799 year /= 10;
800 len++;
801 } while(year);
803 year = year_from_time(time);
804 if(year<0) {
805 formatAD = FALSE;
806 year = -year+1;
807 len += 5;
810 day = date_from_time(time);
811 do {
812 day /= 10;
813 len++;
814 } while(day);
815 day = date_from_time(time);
817 ptr = jsstr_alloc_buf(len, &date_str);
818 if(!ptr)
819 return E_OUTOFMEMORY;
820 sprintfW(ptr, formatAD?formatADW:formatBCW, week, month, day, year);
822 *r = jsval_string(date_str);
824 return S_OK;
827 static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
828 jsval_t *r)
830 DateInstance *date;
832 if(!(date = date_this(jsthis)))
833 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
835 return dateobj_to_date_string(date, r);
838 /* ECMA-262 3rd Edition 15.9.5.4 */
839 static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
840 jsval_t *r)
842 static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
843 ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
844 static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
845 ':','%','0','2','d',' ','U','T','C',0 };
846 DateInstance *date;
847 jsstr_t *date_str;
848 DOUBLE time;
849 WCHAR sign;
850 int offset;
852 TRACE("\n");
854 if(!(date = date_this(jsthis)))
855 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
857 if(isnan(date->time)) {
858 if(r)
859 *r = jsval_string(jsstr_nan());
860 return S_OK;
863 time = local_time(date->time, date);
865 if(r) {
866 WCHAR *ptr;
868 ptr = jsstr_alloc_buf(17, &date_str);
869 if(!date_str)
870 return E_OUTOFMEMORY;
872 offset = date->bias +
873 daylight_saving_ta(time, date);
875 if(offset < 0) {
876 sign = '+';
877 offset = -offset;
879 else sign = '-';
881 if(offset)
882 sprintfW(ptr, formatW, (int)hour_from_time(time),
883 (int)min_from_time(time), (int)sec_from_time(time),
884 sign, offset/60, offset%60);
885 else
886 sprintfW(ptr, formatUTCW, (int)hour_from_time(time),
887 (int)min_from_time(time), (int)sec_from_time(time));
889 *r = jsval_string(date_str);
891 return S_OK;
894 /* ECMA-262 3rd Edition 15.9.5.6 */
895 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
896 jsval_t *r)
898 SYSTEMTIME st;
899 DateInstance *date;
900 jsstr_t *date_str;
901 int len;
903 TRACE("\n");
905 if(!(date = date_this(jsthis)))
906 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
908 if(isnan(date->time)) {
909 if(r)
910 *r = jsval_string(jsstr_nan());
911 return S_OK;
914 st = create_systemtime(local_time(date->time, date));
916 if(st.wYear<1601 || st.wYear>9999)
917 return dateobj_to_date_string(date, r);
919 if(r) {
920 WCHAR *ptr;
922 len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
923 ptr = jsstr_alloc_buf(len, &date_str);
924 if(!ptr)
925 return E_OUTOFMEMORY;
926 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
928 *r = jsval_string(date_str);
930 return S_OK;
933 /* ECMA-262 3rd Edition 15.9.5.7 */
934 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
935 jsval_t *r)
937 SYSTEMTIME st;
938 DateInstance *date;
939 jsstr_t *date_str;
940 int len;
942 TRACE("\n");
944 if(!(date = date_this(jsthis)))
945 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
947 if(isnan(date->time)) {
948 if(r)
949 *r = jsval_string(jsstr_nan());
950 return S_OK;
953 st = create_systemtime(local_time(date->time, date));
955 if(st.wYear<1601 || st.wYear>9999)
956 return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
958 if(r) {
959 WCHAR *ptr;
961 len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
962 ptr = jsstr_alloc_buf(len, &date_str);
963 if(!ptr)
964 return E_OUTOFMEMORY;
965 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
967 *r = jsval_string(date_str);
969 return S_OK;
972 /* ECMA-262 3rd Edition 15.9.5.9 */
973 static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
974 jsval_t *r)
976 DateInstance *date;
978 TRACE("\n");
980 if(!(date = date_this(jsthis)))
981 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
983 if(r)
984 *r = jsval_number(date->time);
985 return S_OK;
988 /* ECMA-262 3rd Edition 15.9.5.10 */
989 static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
990 jsval_t *r)
992 DateInstance *date;
994 TRACE("\n");
996 if(!(date = date_this(jsthis)))
997 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
999 if(r) {
1000 DOUBLE time = local_time(date->time, date);
1002 *r = jsval_number(year_from_time(time));
1004 return S_OK;
1007 /* ECMA-262 3rd Edition 15.9.5.11 */
1008 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1009 jsval_t *r)
1011 DateInstance *date;
1013 TRACE("\n");
1015 if(!(date = date_this(jsthis)))
1016 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1018 if(r)
1019 *r = jsval_number(year_from_time(date->time));
1020 return S_OK;
1023 /* ECMA-262 3rd Edition 15.9.5.12 */
1024 static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1026 DateInstance *date;
1028 TRACE("\n");
1030 if(!(date = date_this(jsthis)))
1031 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1033 if(r)
1034 *r = jsval_number(month_from_time(local_time(date->time, date)));
1035 return S_OK;
1038 /* ECMA-262 3rd Edition 15.9.5.13 */
1039 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1040 jsval_t *r)
1042 DateInstance *date;
1044 TRACE("\n");
1046 if(!(date = date_this(jsthis)))
1047 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1049 if(r)
1050 *r = jsval_number(month_from_time(date->time));
1051 return S_OK;
1054 /* ECMA-262 3rd Edition 15.9.5.14 */
1055 static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1057 DateInstance *date;
1059 TRACE("\n");
1061 if(!(date = date_this(jsthis)))
1062 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1064 if(r)
1065 *r = jsval_number(date_from_time(local_time(date->time, date)));
1066 return S_OK;
1069 /* ECMA-262 3rd Edition 15.9.5.15 */
1070 static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1071 jsval_t *r)
1073 DateInstance *date;
1075 TRACE("\n");
1077 if(!(date = date_this(jsthis)))
1078 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1080 if(r)
1081 *r = jsval_number(date_from_time(date->time));
1082 return S_OK;
1085 /* ECMA-262 3rd Edition 15.9.5.16 */
1086 static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1087 jsval_t *r)
1089 DateInstance *date;
1091 TRACE("\n");
1093 if(!(date = date_this(jsthis)))
1094 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1096 if(r)
1097 *r = jsval_number(week_day(local_time(date->time, date)));
1098 return S_OK;
1101 /* ECMA-262 3rd Edition 15.9.5.17 */
1102 static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1103 jsval_t *r)
1105 DateInstance *date;
1107 TRACE("\n");
1109 if(!(date = date_this(jsthis)))
1110 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1112 if(r)
1113 *r = jsval_number(week_day(date->time));
1114 return S_OK;
1117 /* ECMA-262 3rd Edition 15.9.5.18 */
1118 static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1119 jsval_t *r)
1121 DateInstance *date;
1123 TRACE("\n");
1125 if(!(date = date_this(jsthis)))
1126 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1128 if(r)
1129 *r = jsval_number(hour_from_time(local_time(date->time, date)));
1130 return S_OK;
1133 /* ECMA-262 3rd Edition 15.9.5.19 */
1134 static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1135 jsval_t *r)
1137 DateInstance *date;
1139 TRACE("\n");
1141 if(!(date = date_this(jsthis)))
1142 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1144 if(r)
1145 *r = jsval_number(hour_from_time(date->time));
1146 return S_OK;
1149 /* ECMA-262 3rd Edition 15.9.5.20 */
1150 static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1151 jsval_t *r)
1153 DateInstance *date;
1155 TRACE("\n");
1157 if(!(date = date_this(jsthis)))
1158 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1160 if(r)
1161 *r = jsval_number(min_from_time(local_time(date->time, date)));
1162 return S_OK;
1165 /* ECMA-262 3rd Edition 15.9.5.21 */
1166 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1167 jsval_t *r)
1169 DateInstance *date;
1171 TRACE("\n");
1173 if(!(date = date_this(jsthis)))
1174 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1176 if(r)
1177 *r = jsval_number(min_from_time(date->time));
1178 return S_OK;
1181 /* ECMA-262 3rd Edition 15.9.5.22 */
1182 static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1184 DateInstance *date;
1186 TRACE("\n");
1188 if(!(date = date_this(jsthis)))
1189 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1191 if(r)
1192 *r = jsval_number(sec_from_time(local_time(date->time, date)));
1193 return S_OK;
1196 /* ECMA-262 3rd Edition 15.9.5.23 */
1197 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1198 jsval_t *r)
1200 DateInstance *date;
1202 TRACE("\n");
1204 if(!(date = date_this(jsthis)))
1205 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1207 if(r)
1208 *r = jsval_number(sec_from_time(date->time));
1209 return S_OK;
1212 /* ECMA-262 3rd Edition 15.9.5.24 */
1213 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1214 jsval_t *r)
1216 DateInstance *date;
1218 TRACE("\n");
1220 if(!(date = date_this(jsthis)))
1221 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1223 if(r)
1224 *r = jsval_number(ms_from_time(local_time(date->time, date)));
1225 return S_OK;
1228 /* ECMA-262 3rd Edition 15.9.5.25 */
1229 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1230 jsval_t *r)
1232 DateInstance *date;
1234 TRACE("\n");
1236 if(!(date = date_this(jsthis)))
1237 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1239 if(r)
1240 *r = jsval_number(ms_from_time(date->time));
1241 return S_OK;
1244 /* ECMA-262 3rd Edition 15.9.5.26 */
1245 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1246 jsval_t *r)
1248 DateInstance *date;
1250 TRACE("\n");
1252 if(!(date = date_this(jsthis)))
1253 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1255 if(r)
1256 *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1257 return S_OK;
1260 /* ECMA-262 3rd Edition 15.9.5.27 */
1261 static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1262 jsval_t *r)
1264 double n;
1265 HRESULT hres;
1266 DateInstance *date;
1268 TRACE("\n");
1270 if(!(date = date_this(jsthis)))
1271 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1273 if(!argc)
1274 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1276 hres = to_number(ctx, argv[0], &n);
1277 if(FAILED(hres))
1278 return hres;
1280 date->time = time_clip(n);
1282 if(r)
1283 *r = jsval_number(date->time);
1284 return S_OK;
1287 /* ECMA-262 3rd Edition 15.9.5.28 */
1288 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1289 jsval_t *r)
1291 DateInstance *date;
1292 double n, t;
1293 HRESULT hres;
1295 TRACE("\n");
1297 if(!(date = date_this(jsthis)))
1298 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1300 if(!argc)
1301 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1303 hres = to_number(ctx, argv[0], &n);
1304 if(FAILED(hres))
1305 return hres;
1307 t = local_time(date->time, date);
1308 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1309 sec_from_time(t), n));
1310 date->time = time_clip(utc(t, date));
1312 if(r)
1313 *r = jsval_number(date->time);
1314 return S_OK;
1317 /* ECMA-262 3rd Edition 15.9.5.29 */
1318 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1319 jsval_t *r)
1321 DateInstance *date;
1322 double n, t;
1323 HRESULT hres;
1325 TRACE("\n");
1327 if(!(date = date_this(jsthis)))
1328 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1330 if(!argc)
1331 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1333 hres = to_number(ctx, argv[0], &n);
1334 if(FAILED(hres))
1335 return hres;
1337 t = date->time;
1338 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1339 sec_from_time(t), n));
1340 date->time = time_clip(t);
1342 if(r)
1343 *r = jsval_number(date->time);
1344 return S_OK;
1347 /* ECMA-262 3rd Edition 15.9.5.30 */
1348 static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1349 jsval_t *r)
1351 DateInstance *date;
1352 double t, sec, ms;
1353 HRESULT hres;
1355 TRACE("\n");
1357 if(!(date = date_this(jsthis)))
1358 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1360 if(!argc)
1361 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1363 t = local_time(date->time, date);
1365 hres = to_number(ctx, argv[0], &sec);
1366 if(FAILED(hres))
1367 return hres;
1369 if(argc > 1) {
1370 hres = to_number(ctx, argv[1], &ms);
1371 if(FAILED(hres))
1372 return hres;
1373 }else {
1374 ms = ms_from_time(t);
1377 t = make_date(day(t), make_time(hour_from_time(t),
1378 min_from_time(t), sec, ms));
1379 date->time = time_clip(utc(t, date));
1381 if(r)
1382 *r = jsval_number(date->time);
1383 return S_OK;
1386 /* ECMA-262 3rd Edition 15.9.5.31 */
1387 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1388 jsval_t *r)
1390 DateInstance *date;
1391 double t, sec, ms;
1392 HRESULT hres;
1394 TRACE("\n");
1396 if(!(date = date_this(jsthis)))
1397 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1399 if(!argc)
1400 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1402 t = date->time;
1404 hres = to_number(ctx, argv[0], &sec);
1405 if(FAILED(hres))
1406 return hres;
1408 if(argc > 1) {
1409 hres = to_number(ctx, argv[1], &ms);
1410 if(FAILED(hres))
1411 return hres;
1412 }else {
1413 ms = ms_from_time(t);
1416 t = make_date(day(t), make_time(hour_from_time(t),
1417 min_from_time(t), sec, ms));
1418 date->time = time_clip(t);
1420 if(r)
1421 *r = jsval_number(date->time);
1422 return S_OK;
1425 /* ECMA-262 3rd Edition 15.9.5.33 */
1426 static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1427 jsval_t *r)
1429 DateInstance *date;
1430 double t, min, sec, ms;
1431 HRESULT hres;
1433 TRACE("\n");
1435 if(!(date = date_this(jsthis)))
1436 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1438 if(!argc)
1439 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1441 t = local_time(date->time, date);
1443 hres = to_number(ctx, argv[0], &min);
1444 if(FAILED(hres))
1445 return hres;
1447 if(argc > 1) {
1448 hres = to_number(ctx, argv[1], &sec);
1449 if(FAILED(hres))
1450 return hres;
1451 }else {
1452 sec = sec_from_time(t);
1455 if(argc > 2) {
1456 hres = to_number(ctx, argv[2], &ms);
1457 if(FAILED(hres))
1458 return hres;
1459 }else {
1460 ms = ms_from_time(t);
1463 t = make_date(day(t), make_time(hour_from_time(t),
1464 min, sec, ms));
1465 date->time = time_clip(utc(t, date));
1467 if(r)
1468 *r = jsval_number(date->time);
1469 return S_OK;
1472 /* ECMA-262 3rd Edition 15.9.5.34 */
1473 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1474 jsval_t *r)
1476 DateInstance *date;
1477 double t, min, sec, ms;
1478 HRESULT hres;
1480 TRACE("\n");
1482 if(!(date = date_this(jsthis)))
1483 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1485 if(!argc)
1486 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1488 t = date->time;
1490 hres = to_number(ctx, argv[0], &min);
1491 if(FAILED(hres))
1492 return hres;
1494 if(argc > 1) {
1495 hres = to_number(ctx, argv[1], &sec);
1496 if(FAILED(hres))
1497 return hres;
1498 }else {
1499 sec = sec_from_time(t);
1502 if(argc > 2) {
1503 hres = to_number(ctx, argv[2], &ms);
1504 if(FAILED(hres))
1505 return hres;
1506 }else {
1507 ms = ms_from_time(t);
1510 t = make_date(day(t), make_time(hour_from_time(t),
1511 min, sec, ms));
1512 date->time = time_clip(t);
1514 if(r)
1515 *r = jsval_number(date->time);
1516 return S_OK;
1519 /* ECMA-262 3rd Edition 15.9.5.35 */
1520 static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1521 jsval_t *r)
1523 DateInstance *date;
1524 double t, hour, min, sec, ms;
1525 HRESULT hres;
1527 TRACE("\n");
1529 if(!(date = date_this(jsthis)))
1530 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1532 if(!argc)
1533 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1535 t = local_time(date->time, date);
1537 hres = to_number(ctx, argv[0], &hour);
1538 if(FAILED(hres))
1539 return hres;
1541 if(argc > 1) {
1542 hres = to_number(ctx, argv[1], &min);
1543 if(FAILED(hres))
1544 return hres;
1545 }else {
1546 min = min_from_time(t);
1549 if(argc > 2) {
1550 hres = to_number(ctx, argv[2], &sec);
1551 if(FAILED(hres))
1552 return hres;
1553 }else {
1554 sec = sec_from_time(t);
1557 if(argc > 3) {
1558 hres = to_number(ctx, argv[3], &ms);
1559 if(FAILED(hres))
1560 return hres;
1561 }else {
1562 ms = ms_from_time(t);
1565 t = make_date(day(t), make_time(hour, min, sec, ms));
1566 date->time = time_clip(utc(t, date));
1568 if(r)
1569 *r = jsval_number(date->time);
1570 return S_OK;
1573 /* ECMA-262 3rd Edition 15.9.5.36 */
1574 static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1575 jsval_t *r)
1577 DateInstance *date;
1578 double t, hour, min, sec, ms;
1579 HRESULT hres;
1581 TRACE("\n");
1583 if(!(date = date_this(jsthis)))
1584 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1586 if(!argc)
1587 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1589 t = date->time;
1591 hres = to_number(ctx, argv[0], &hour);
1592 if(FAILED(hres))
1593 return hres;
1595 if(argc > 1) {
1596 hres = to_number(ctx, argv[1], &min);
1597 if(FAILED(hres))
1598 return hres;
1599 }else {
1600 min = min_from_time(t);
1603 if(argc > 2) {
1604 hres = to_number(ctx, argv[2], &sec);
1605 if(FAILED(hres))
1606 return hres;
1607 }else {
1608 sec = sec_from_time(t);
1611 if(argc > 3) {
1612 hres = to_number(ctx, argv[3], &ms);
1613 if(FAILED(hres))
1614 return hres;
1615 }else {
1616 ms = ms_from_time(t);
1619 t = make_date(day(t), make_time(hour, min, sec, ms));
1620 date->time = time_clip(t);
1622 if(r)
1623 *r = jsval_number(date->time);
1624 return S_OK;
1627 /* ECMA-262 3rd Edition 15.9.5.36 */
1628 static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1629 jsval_t *r)
1631 DateInstance *date;
1632 double t, n;
1633 HRESULT hres;
1635 TRACE("\n");
1637 if(!(date = date_this(jsthis)))
1638 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1640 if(!argc)
1641 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1643 hres = to_number(ctx, argv[0], &n);
1644 if(FAILED(hres))
1645 return hres;
1647 t = local_time(date->time, date);
1648 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1649 date->time = time_clip(utc(t, date));
1651 if(r)
1652 *r = jsval_number(date->time);
1653 return S_OK;
1656 /* ECMA-262 3rd Edition 15.9.5.37 */
1657 static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1658 jsval_t *r)
1660 DateInstance *date;
1661 double t, n;
1662 HRESULT hres;
1664 TRACE("\n");
1666 if(!(date = date_this(jsthis)))
1667 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1669 if(!argc)
1670 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1672 hres = to_number(ctx, argv[0], &n);
1673 if(FAILED(hres))
1674 return hres;
1676 t = date->time;
1677 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1678 date->time = time_clip(t);
1680 if(r)
1681 *r = jsval_number(date->time);
1682 return S_OK;
1685 /* ECMA-262 3rd Edition 15.9.5.38 */
1686 static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1687 jsval_t *r)
1689 DateInstance *date;
1690 DOUBLE t, month, ddate;
1691 HRESULT hres;
1693 TRACE("\n");
1695 if(!(date = date_this(jsthis)))
1696 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1698 if(!argc)
1699 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1701 t = local_time(date->time, date);
1703 hres = to_number(ctx, argv[0], &month);
1704 if(FAILED(hres))
1705 return hres;
1707 if(argc > 1) {
1708 hres = to_number(ctx, argv[1], &ddate);
1709 if(FAILED(hres))
1710 return hres;
1711 }else {
1712 ddate = date_from_time(t);
1715 t = make_date(make_day(year_from_time(t), month, ddate),
1716 time_within_day(t));
1717 date->time = time_clip(utc(t, date));
1719 if(r)
1720 *r = jsval_number(date->time);
1721 return S_OK;
1724 /* ECMA-262 3rd Edition 15.9.5.39 */
1725 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1726 jsval_t *r)
1728 DateInstance *date;
1729 double t, month, ddate;
1730 HRESULT hres;
1732 TRACE("\n");
1734 if(!(date = date_this(jsthis)))
1735 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1737 if(!argc)
1738 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1740 t = date->time;
1742 hres = to_number(ctx, argv[0], &month);
1743 if(FAILED(hres))
1744 return hres;
1746 if(argc > 1) {
1747 hres = to_number(ctx, argv[1], &ddate);
1748 if(FAILED(hres))
1749 return hres;
1750 }else {
1751 ddate = date_from_time(t);
1754 t = make_date(make_day(year_from_time(t), month, ddate),
1755 time_within_day(t));
1756 date->time = time_clip(t);
1758 if(r)
1759 *r = jsval_number(date->time);
1760 return S_OK;
1763 /* ECMA-262 3rd Edition 15.9.5.40 */
1764 static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1765 jsval_t *r)
1767 DateInstance *date;
1768 double t, year, month, ddate;
1769 HRESULT hres;
1771 TRACE("\n");
1773 if(!(date = date_this(jsthis)))
1774 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1776 if(!argc)
1777 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1779 t = local_time(date->time, date);
1781 hres = to_number(ctx, argv[0], &year);
1782 if(FAILED(hres))
1783 return hres;
1785 if(argc > 1) {
1786 hres = to_number(ctx, argv[1], &month);
1787 if(FAILED(hres))
1788 return hres;
1789 }else {
1790 month = month_from_time(t);
1793 if(argc > 2) {
1794 hres = to_number(ctx, argv[2], &ddate);
1795 if(FAILED(hres))
1796 return hres;
1797 }else {
1798 ddate = date_from_time(t);
1801 t = make_date(make_day(year, month, ddate), time_within_day(t));
1802 date->time = time_clip(utc(t, date));
1804 if(r)
1805 *r = jsval_number(date->time);
1806 return S_OK;
1809 /* ECMA-262 3rd Edition 15.9.5.41 */
1810 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1811 jsval_t *r)
1813 DateInstance *date;
1814 double t, year, month, ddate;
1815 HRESULT hres;
1817 TRACE("\n");
1819 if(!(date = date_this(jsthis)))
1820 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1822 if(!argc)
1823 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1825 t = date->time;
1827 hres = to_number(ctx, argv[0], &year);
1828 if(FAILED(hres))
1829 return hres;
1831 if(argc > 1) {
1832 hres = to_number(ctx, argv[1], &month);
1833 if(FAILED(hres))
1834 return hres;
1835 }else {
1836 month = month_from_time(t);
1839 if(argc > 2) {
1840 hres = to_number(ctx, argv[2], &ddate);
1841 if(FAILED(hres))
1842 return hres;
1843 }else {
1844 ddate = date_from_time(t);
1847 t = make_date(make_day(year, month, ddate), time_within_day(t));
1848 date->time = time_clip(t);
1850 if(r)
1851 *r = jsval_number(date->time);
1852 return S_OK;
1855 /* ECMA-262 3rd Edition B2.4 */
1856 static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1857 jsval_t *r)
1859 DateInstance *date;
1860 DOUBLE t, year;
1862 TRACE("\n");
1864 if(!(date = date_this(jsthis)))
1865 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1867 t = local_time(date->time, date);
1868 if(isnan(t)) {
1869 if(r)
1870 *r = jsval_number(NAN);
1871 return S_OK;
1874 year = year_from_time(t);
1875 if(r)
1876 *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1877 return S_OK;
1880 /* ECMA-262 3rd Edition B2.5 */
1881 static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1882 jsval_t *r)
1884 DateInstance *date;
1885 DOUBLE t, year;
1886 HRESULT hres;
1888 TRACE("\n");
1890 if(!(date = date_this(jsthis)))
1891 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1893 if(!argc)
1894 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1896 t = local_time(date->time, date);
1898 hres = to_number(ctx, argv[0], &year);
1899 if(FAILED(hres))
1900 return hres;
1902 if(isnan(year)) {
1903 date->time = year;
1904 if(r)
1905 *r = jsval_number(NAN);
1906 return S_OK;
1909 year = year >= 0.0 ? floor(year) : -floor(-year);
1910 if(-1.0 < year && year < 100.0)
1911 year += 1900.0;
1913 date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1915 if(r)
1916 *r = jsval_number(date->time);
1917 return S_OK;
1920 static HRESULT Date_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1921 jsval_t *r)
1923 TRACE("\n");
1925 switch(flags) {
1926 case INVOKE_FUNC:
1927 return throw_type_error(ctx, JS_E_FUNCTION_EXPECTED, NULL);
1928 default:
1929 FIXME("unimplemented flags %x\n", flags);
1930 return E_NOTIMPL;
1933 return S_OK;
1936 static const builtin_prop_t Date_props[] = {
1937 {getDateW, Date_getDate, PROPF_METHOD},
1938 {getDayW, Date_getDay, PROPF_METHOD},
1939 {getFullYearW, Date_getFullYear, PROPF_METHOD},
1940 {getHoursW, Date_getHours, PROPF_METHOD},
1941 {getMillisecondsW, Date_getMilliseconds, PROPF_METHOD},
1942 {getMinutesW, Date_getMinutes, PROPF_METHOD},
1943 {getMonthW, Date_getMonth, PROPF_METHOD},
1944 {getSecondsW, Date_getSeconds, PROPF_METHOD},
1945 {getTimeW, Date_getTime, PROPF_METHOD},
1946 {getTimezoneOffsetW, Date_getTimezoneOffset, PROPF_METHOD},
1947 {getUTCDateW, Date_getUTCDate, PROPF_METHOD},
1948 {getUTCDayW, Date_getUTCDay, PROPF_METHOD},
1949 {getUTCFullYearW, Date_getUTCFullYear, PROPF_METHOD},
1950 {getUTCHoursW, Date_getUTCHours, PROPF_METHOD},
1951 {getUTCMillisecondsW, Date_getUTCMilliseconds, PROPF_METHOD},
1952 {getUTCMinutesW, Date_getUTCMinutes, PROPF_METHOD},
1953 {getUTCMonthW, Date_getUTCMonth, PROPF_METHOD},
1954 {getUTCSecondsW, Date_getUTCSeconds, PROPF_METHOD},
1955 {getYearW, Date_getYear, PROPF_METHOD},
1956 {setDateW, Date_setDate, PROPF_METHOD|1},
1957 {setFullYearW, Date_setFullYear, PROPF_METHOD|3},
1958 {setHoursW, Date_setHours, PROPF_METHOD|4},
1959 {setMillisecondsW, Date_setMilliseconds, PROPF_METHOD|1},
1960 {setMinutesW, Date_setMinutes, PROPF_METHOD|3},
1961 {setMonthW, Date_setMonth, PROPF_METHOD|2},
1962 {setSecondsW, Date_setSeconds, PROPF_METHOD|2},
1963 {setTimeW, Date_setTime, PROPF_METHOD|1},
1964 {setUTCDateW, Date_setUTCDate, PROPF_METHOD|1},
1965 {setUTCFullYearW, Date_setUTCFullYear, PROPF_METHOD|3},
1966 {setUTCHoursW, Date_setUTCHours, PROPF_METHOD|4},
1967 {setUTCMillisecondsW, Date_setUTCMilliseconds, PROPF_METHOD|1},
1968 {setUTCMinutesW, Date_setUTCMinutes, PROPF_METHOD|3},
1969 {setUTCMonthW, Date_setUTCMonth, PROPF_METHOD|2},
1970 {setUTCSecondsW, Date_setUTCSeconds, PROPF_METHOD|2},
1971 {setYearW, Date_setYear, PROPF_METHOD|1},
1972 {toDateStringW, Date_toDateString, PROPF_METHOD},
1973 {toGMTStringW, Date_toGMTString, PROPF_METHOD},
1974 {toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD},
1975 {toLocaleStringW, Date_toLocaleString, PROPF_METHOD},
1976 {toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD},
1977 {toStringW, Date_toString, PROPF_METHOD},
1978 {toTimeStringW, Date_toTimeString, PROPF_METHOD},
1979 {toUTCStringW, Date_toUTCString, PROPF_METHOD},
1980 {valueOfW, Date_valueOf, PROPF_METHOD},
1983 static const builtin_info_t Date_info = {
1984 JSCLASS_DATE,
1985 {NULL, Date_value, 0},
1986 sizeof(Date_props)/sizeof(*Date_props),
1987 Date_props,
1988 NULL,
1989 NULL
1992 static const builtin_info_t DateInst_info = {
1993 JSCLASS_DATE,
1994 {NULL, Date_value, 0},
1995 0, NULL,
1996 NULL,
1997 NULL
2000 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
2002 DateInstance *date;
2003 HRESULT hres;
2004 TIME_ZONE_INFORMATION tzi;
2006 GetTimeZoneInformation(&tzi);
2008 date = heap_alloc_zero(sizeof(DateInstance));
2009 if(!date)
2010 return E_OUTOFMEMORY;
2012 if(object_prototype)
2013 hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
2014 else
2015 hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
2016 if(FAILED(hres)) {
2017 heap_free(date);
2018 return hres;
2021 date->time = time;
2022 date->bias = tzi.Bias;
2023 date->standardDate = tzi.StandardDate;
2024 date->standardBias = tzi.StandardBias;
2025 date->daylightDate = tzi.DaylightDate;
2026 date->daylightBias = tzi.DaylightBias;
2028 *ret = &date->dispex;
2029 return S_OK;
2032 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
2033 static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
2034 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
2035 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
2036 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
2037 LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
2038 LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
2039 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
2040 WCHAR *strings[sizeof(string_ids)/sizeof(DWORD)];
2041 WCHAR *parse;
2042 int input_len, parse_len = 0, nest_level = 0, i, size;
2043 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
2044 int ms = 0, offset = 0, hour_adjust = 0;
2045 BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
2046 BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
2047 BOOL set_hour_adjust = TRUE;
2048 TIME_ZONE_INFORMATION tzi;
2049 const WCHAR *input;
2050 DateInstance di;
2051 DWORD lcid_en;
2053 input_len = jsstr_length(input_str);
2054 input = jsstr_flatten(input_str);
2055 if(!input)
2056 return E_OUTOFMEMORY;
2058 for(i=0; i<input_len; i++) {
2059 if(input[i] == '(') nest_level++;
2060 else if(input[i] == ')') {
2061 nest_level--;
2062 if(nest_level<0) {
2063 *ret = NAN;
2064 return S_OK;
2067 else if(!nest_level) parse_len++;
2070 parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2071 if(!parse)
2072 return E_OUTOFMEMORY;
2073 nest_level = 0;
2074 parse_len = 0;
2075 for(i=0; i<input_len; i++) {
2076 if(input[i] == '(') nest_level++;
2077 else if(input[i] == ')') nest_level--;
2078 else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
2080 parse[parse_len] = 0;
2082 GetTimeZoneInformation(&tzi);
2083 di.bias = tzi.Bias;
2084 di.standardDate = tzi.StandardDate;
2085 di.standardBias = tzi.StandardBias;
2086 di.daylightDate = tzi.DaylightDate;
2087 di.daylightBias = tzi.DaylightBias;
2089 /* FIXME: Cache strings */
2090 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2091 for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++) {
2092 size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2093 strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
2094 if(!strings[i]) {
2095 i--;
2096 while(i-- >= 0)
2097 heap_free(strings[i]);
2098 heap_free(parse);
2099 return E_OUTOFMEMORY;
2101 GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2104 for(i=0; i<parse_len;) {
2105 while(isspaceW(parse[i])) i++;
2106 if(parse[i] == ',') {
2107 while(parse[i] == ',') i++;
2108 continue;
2111 if(parse[i]>='0' && parse[i]<='9') {
2112 int tmp = atoiW(&parse[i]);
2113 while(parse[i]>='0' && parse[i]<='9') i++;
2114 while(isspaceW(parse[i])) i++;
2116 if(parse[i] == ':') {
2117 /* Time */
2118 if(set_hour) break;
2119 set_hour = TRUE;
2121 hour = tmp;
2123 while(parse[i] == ':') i++;
2124 while(isspaceW(parse[i])) i++;
2125 if(parse[i]>='0' && parse[i]<='9') {
2126 min = atoiW(&parse[i]);
2127 while(parse[i]>='0' && parse[i]<='9') i++;
2130 while(isspaceW(parse[i])) i++;
2131 while(parse[i] == ':') i++;
2132 while(isspaceW(parse[i])) i++;
2133 if(parse[i]>='0' && parse[i]<='9') {
2134 sec = atoiW(&parse[i]);
2135 while(parse[i]>='0' && parse[i]<='9') i++;
2138 else if(parse[i]=='-' || parse[i]=='/') {
2139 /* Short date */
2140 if(set_day || set_month || set_year) break;
2141 set_day = TRUE;
2142 set_month = TRUE;
2143 set_year = TRUE;
2145 month = tmp-1;
2147 while(isspaceW(parse[i])) i++;
2148 while(parse[i]=='-' || parse[i]=='/') i++;
2149 while(isspaceW(parse[i])) i++;
2150 if(parse[i]<'0' || parse[i]>'9') break;
2151 day = atoiW(&parse[i]);
2152 while(parse[i]>='0' && parse[i]<='9') i++;
2154 while(parse[i]=='-' || parse[i]=='/') i++;
2155 while(isspaceW(parse[i])) i++;
2156 if(parse[i]<'0' || parse[i]>'9') break;
2157 year = atoiW(&parse[i]);
2158 while(parse[i]>='0' && parse[i]<='9') i++;
2160 else if(tmp<0) break;
2161 else if(tmp<70) {
2162 /* Day */
2163 if(set_day) break;
2164 set_day = TRUE;
2165 day = tmp;
2167 else {
2168 /* Year */
2169 if(set_year) break;
2170 set_year = TRUE;
2171 year = tmp;
2174 else {
2175 if(parse[i]<'A' || parse[i]>'Z') break;
2176 else if(parse[i]=='B' && (parse[i+1]=='C' ||
2177 (parse[i+1]=='.' && parse[i+2]=='C'))) {
2178 /* AD/BC */
2179 if(set_era) break;
2180 set_era = TRUE;
2181 ad = FALSE;
2183 i++;
2184 if(parse[i] == '.') i++;
2185 i++;
2186 if(parse[i] == '.') i++;
2188 else if(parse[i]=='A' && (parse[i+1]=='D' ||
2189 (parse[i+1]=='.' && parse[i+2]=='D'))) {
2190 /* AD/BC */
2191 if(set_era) break;
2192 set_era = TRUE;
2194 i++;
2195 if(parse[i] == '.') i++;
2196 i++;
2197 if(parse[i] == '.') i++;
2199 else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2200 /* Timezone */
2201 if(set_offset) break;
2202 set_offset = TRUE;
2204 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2205 else if(parse[i] == 'J') break;
2206 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2207 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2208 else hour_adjust = 1;
2210 i++;
2211 if(parse[i] == '.') i++;
2213 else if(parse[i]=='A' && parse[i+1]=='M') {
2214 /* AM/PM */
2215 if(set_am) break;
2216 set_am = TRUE;
2217 am = TRUE;
2218 i += 2;
2220 else if(parse[i]=='P' && parse[i+1]=='M') {
2221 /* AM/PM */
2222 if(set_am) break;
2223 set_am = TRUE;
2224 am = FALSE;
2225 i += 2;
2227 else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2228 || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2229 /* Timezone */
2230 BOOL positive = TRUE;
2232 if(set_offset) break;
2233 set_offset = TRUE;
2234 set_hour_adjust = FALSE;
2236 i += 3;
2237 while(isspaceW(parse[i])) i++;
2238 if(parse[i] == '-') positive = FALSE;
2239 else if(parse[i] != '+') continue;
2241 i++;
2242 while(isspaceW(parse[i])) i++;
2243 if(parse[i]<'0' || parse[i]>'9') break;
2244 offset = atoiW(&parse[i]);
2245 while(parse[i]>='0' && parse[i]<='9') i++;
2247 if(offset<24) offset *= 60;
2248 else offset = (offset/100)*60 + offset%100;
2250 if(positive) offset = -offset;
2252 else {
2253 /* Month or garbage */
2254 unsigned int j;
2256 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2257 size -= i;
2259 for(j=0; j<sizeof(string_ids)/sizeof(DWORD); j++)
2260 if(!strncmpiW(&parse[i], strings[j], size)) break;
2262 if(j < 12) {
2263 if(set_month) break;
2264 set_month = TRUE;
2265 month = 11-j;
2267 else if(j == sizeof(string_ids)/sizeof(DWORD)) break;
2269 i += size;
2274 if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2275 if(set_am) {
2276 if(hour == 12) hour = 0;
2277 if(!am) hour += 12;
2280 if(!ad) year = -year+1;
2281 else if(year<100) year += 1900;
2283 *ret = time_clip(make_date(make_day(year, month, day),
2284 make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2286 if(set_hour_adjust)
2287 *ret = utc(*ret, &di);
2288 }else {
2289 *ret = NAN;
2292 for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++)
2293 heap_free(strings[i]);
2294 heap_free(parse);
2296 return S_OK;
2299 static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2300 jsval_t *r)
2302 jsstr_t *parse_str;
2303 double n;
2304 HRESULT hres;
2306 TRACE("\n");
2308 if(!argc) {
2309 if(r)
2310 *r = jsval_number(NAN);
2311 return S_OK;
2314 hres = to_string(ctx, argv[0], &parse_str);
2315 if(FAILED(hres))
2316 return hres;
2318 hres = date_parse(parse_str, &n);
2319 jsstr_release(parse_str);
2320 if(FAILED(hres))
2321 return hres;
2323 *r = jsval_number(n);
2324 return S_OK;
2327 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2329 double year, month, vdate, hours, minutes, seconds, ms;
2330 HRESULT hres;
2332 TRACE("\n");
2334 if(argc) {
2335 hres = to_number(ctx, argv[0], &year);
2336 if(FAILED(hres))
2337 return hres;
2338 if(0 <= year && year <= 99)
2339 year += 1900;
2340 }else {
2341 year = 1900;
2344 if(argc>1) {
2345 hres = to_number(ctx, argv[1], &month);
2346 if(FAILED(hres))
2347 return hres;
2348 }else {
2349 month = 0;
2352 if(argc>2) {
2353 hres = to_number(ctx, argv[2], &vdate);
2354 if(FAILED(hres))
2355 return hres;
2356 }else {
2357 vdate = 1;
2360 if(argc>3) {
2361 hres = to_number(ctx, argv[3], &hours);
2362 if(FAILED(hres))
2363 return hres;
2364 }else {
2365 hours = 0;
2368 if(argc>4) {
2369 hres = to_number(ctx, argv[4], &minutes);
2370 if(FAILED(hres))
2371 return hres;
2372 }else {
2373 minutes = 0;
2376 if(argc>5) {
2377 hres = to_number(ctx, argv[5], &seconds);
2378 if(FAILED(hres))
2379 return hres;
2380 }else {
2381 seconds = 0;
2384 if(argc>6) {
2385 hres = to_number(ctx, argv[6], &ms);
2386 if(FAILED(hres))
2387 return hres;
2388 } else {
2389 ms = 0;
2392 *ret = time_clip(make_date(make_day(year, month, vdate),
2393 make_time(hours, minutes,seconds, ms)));
2394 return S_OK;
2397 static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2398 jsval_t *r)
2400 double n;
2401 HRESULT hres;
2403 TRACE("\n");
2405 hres = date_utc(ctx, argc, argv, &n);
2406 if(SUCCEEDED(hres) && r)
2407 *r = jsval_number(n);
2408 return hres;
2411 static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2412 jsval_t *r)
2414 jsdisp_t *date;
2415 HRESULT hres;
2417 TRACE("\n");
2419 switch(flags) {
2420 case DISPATCH_CONSTRUCT:
2421 switch(argc) {
2422 /* ECMA-262 3rd Edition 15.9.3.3 */
2423 case 0: {
2424 FILETIME time;
2425 LONGLONG lltime;
2427 GetSystemTimeAsFileTime(&time);
2428 lltime = ((LONGLONG)time.dwHighDateTime<<32)
2429 + time.dwLowDateTime;
2431 hres = create_date(ctx, NULL, lltime/10000-TIME_EPOCH, &date);
2432 if(FAILED(hres))
2433 return hres;
2434 break;
2437 /* ECMA-262 3rd Edition 15.9.3.2 */
2438 case 1: {
2439 jsval_t prim;
2440 double n;
2442 hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2443 if(FAILED(hres))
2444 return hres;
2446 if(is_string(prim))
2447 hres = date_parse(get_string(prim), &n);
2448 else
2449 hres = to_number(ctx, prim, &n);
2451 jsval_release(prim);
2452 if(FAILED(hres))
2453 return hres;
2455 hres = create_date(ctx, NULL, time_clip(n), &date);
2456 if(FAILED(hres))
2457 return hres;
2458 break;
2461 /* ECMA-262 3rd Edition 15.9.3.1 */
2462 default: {
2463 double ret_date;
2464 DateInstance *di;
2466 hres = date_utc(ctx, argc, argv, &ret_date);
2467 if(FAILED(hres))
2468 return hres;
2470 hres = create_date(ctx, NULL, ret_date, &date);
2471 if(FAILED(hres))
2472 return hres;
2474 di = (DateInstance*)date;
2475 di->time = utc(di->time, di);
2479 *r = jsval_obj(date);
2480 return S_OK;
2482 case INVOKE_FUNC: {
2483 FILETIME system_time, local_time;
2484 LONGLONG lltime;
2486 GetSystemTimeAsFileTime(&system_time);
2487 FileTimeToLocalFileTime(&system_time, &local_time);
2488 lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2489 + local_time.dwLowDateTime;
2491 return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2494 default:
2495 FIXME("unimplemented flags %x\n", flags);
2496 return E_NOTIMPL;
2499 return S_OK;
2502 static const builtin_prop_t DateConstr_props[] = {
2503 {UTCW, DateConstr_UTC, PROPF_METHOD},
2504 {parseW, DateConstr_parse, PROPF_METHOD}
2507 static const builtin_info_t DateConstr_info = {
2508 JSCLASS_FUNCTION,
2509 {NULL, Function_value, 0},
2510 sizeof(DateConstr_props)/sizeof(*DateConstr_props),
2511 DateConstr_props,
2512 NULL,
2513 NULL
2516 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2518 jsdisp_t *date;
2519 HRESULT hres;
2521 static const WCHAR DateW[] = {'D','a','t','e',0};
2523 hres = create_date(ctx, object_prototype, 0.0, &date);
2524 if(FAILED(hres))
2525 return hres;
2527 hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2528 PROPF_CONSTR|7, date, ret);
2530 jsdisp_release(date);
2531 return hres;