usp10: Fall back to 'dflt' language if shaping language tag isn't found.
[wine.git] / dlls / jscript / date.c
blob21a359a10f156ae781ebc817b669174623eb2ca2
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_from_jsdisp(jsdisp_t *jsdisp)
99 return CONTAINING_RECORD(jsdisp, DateInstance, dispex);
102 static inline DateInstance *date_this(vdisp_t *jsthis)
104 return is_vclass(jsthis, JSCLASS_DATE) ? date_from_jsdisp(jsthis->u.jsdisp) : NULL;
107 /*ECMA-262 3rd Edition 15.9.1.2 */
108 #define MS_PER_DAY 86400000
109 #define MS_PER_HOUR 3600000
110 #define MS_PER_MINUTE 60000
112 /* ECMA-262 3rd Edition 15.9.1.2 */
113 static inline DOUBLE day(DOUBLE time)
115 return floor(time / MS_PER_DAY);
118 /* ECMA-262 3rd Edition 15.9.1.2 */
119 static inline DOUBLE time_within_day(DOUBLE time)
121 DOUBLE ret;
123 ret = fmod(time, MS_PER_DAY);
124 if(ret < 0)
125 ret += MS_PER_DAY;
127 return ret;
130 /* ECMA-262 3rd Edition 15.9.1.3 */
131 static inline DOUBLE days_in_year(DOUBLE year)
133 int y;
135 if(year != (int)year)
136 return NAN;
138 y = year;
139 if(y%4 != 0) return 365;
140 if(y%100 != 0) return 366;
141 if(y%400 != 0) return 365;
142 return 366;
145 /* ECMA-262 3rd Edition 15.9.1.3 */
146 static inline DOUBLE day_from_year(DOUBLE year)
148 if(year != (int)year)
149 return NAN;
151 return floor(365.0*(year-1970) + floor((year-1969)/4)
152 - floor((year-1901)/100) + floor((year-1601)/400));
155 static inline int day_from_month(int month, int in_leap_year)
157 switch(month)
159 case 0:
160 return 0;
161 case 1:
162 return 31;
163 case 2:
164 return 59+in_leap_year;
165 case 3:
166 return 90+in_leap_year;
167 case 4:
168 return 120+in_leap_year;
169 case 5:
170 return 151+in_leap_year;
171 case 6:
172 return 181+in_leap_year;
173 case 7:
174 return 212+in_leap_year;
175 case 8:
176 return 243+in_leap_year;
177 case 9:
178 return 273+in_leap_year;
179 case 10:
180 return 304+in_leap_year;
181 default:
182 return 334+in_leap_year;
186 /* ECMA-262 3rd Edition 15.9.1.3 */
187 static inline DOUBLE time_from_year(DOUBLE year)
189 return MS_PER_DAY*day_from_year(year);
192 /* ECMA-262 3rd Edition 15.9.1.3 */
193 static inline DOUBLE year_from_time(DOUBLE time)
195 int y;
197 if(isnan(time))
198 return NAN;
200 y = 1970 + time/365.25/MS_PER_DAY;
202 if(time_from_year(y) > time)
203 while(time_from_year(y) > time) y--;
204 else
205 while(time_from_year(y+1)<=time) y++;
207 return y;
210 /* ECMA-262 3rd Edition 15.9.1.3 */
211 static inline int in_leap_year(DOUBLE time)
213 if(days_in_year(year_from_time(time))==366)
214 return 1;
215 return 0;
218 /* ECMA-262 3rd Edition 15.9.1.4 */
219 static inline int day_within_year(DOUBLE time)
221 return day(time) - day_from_year(year_from_time(time));
224 /* ECMA-262 3rd Edition 15.9.1.4 */
225 static inline DOUBLE month_from_time(DOUBLE time)
227 int ily = in_leap_year(time);
228 int dwy = day_within_year(time);
230 if(isnan(time))
231 return NAN;
233 if(0<=dwy && dwy<31) return 0;
234 if(dwy < 59+ily) return 1;
235 if(dwy < 90+ily) return 2;
236 if(dwy < 120+ily) return 3;
237 if(dwy < 151+ily) return 4;
238 if(dwy < 181+ily) return 5;
239 if(dwy < 212+ily) return 6;
240 if(dwy < 243+ily) return 7;
241 if(dwy < 273+ily) return 8;
242 if(dwy < 304+ily) return 9;
243 if(dwy < 334+ily) return 10;
244 return 11;
247 /* ECMA-262 3rd Edition 15.9.1.5 */
248 static inline DOUBLE date_from_time(DOUBLE time)
250 int dwy = day_within_year(time);
251 int ily = in_leap_year(time);
252 int mft = month_from_time(time);
254 if(isnan(time))
255 return NAN;
257 if(mft==0) return dwy+1;
258 if(mft==1) return dwy-30;
259 if(mft==2) return dwy-58-ily;
260 if(mft==3) return dwy-89-ily;
261 if(mft==4) return dwy-119-ily;
262 if(mft==5) return dwy-150-ily;
263 if(mft==6) return dwy-180-ily;
264 if(mft==7) return dwy-211-ily;
265 if(mft==8) return dwy-242-ily;
266 if(mft==9) return dwy-272-ily;
267 if(mft==10) return dwy-303-ily;
268 return dwy-333-ily;
271 /* ECMA-262 3rd Edition 15.9.1.6 */
272 static inline DOUBLE week_day(DOUBLE time)
274 DOUBLE ret;
276 if(isnan(time))
277 return NAN;
279 ret = fmod(day(time)+4, 7);
280 if(ret<0) ret += 7;
282 return ret;
285 static inline DOUBLE convert_time(int year, SYSTEMTIME st)
287 DOUBLE time;
288 int set_week_day;
290 if(st.wMonth == 0)
291 return NAN;
293 if(st.wYear != 0)
294 year = st.wYear;
296 time = time_from_year(year);
297 time += (DOUBLE)day_from_month(st.wMonth-1, in_leap_year(time)) * MS_PER_DAY;
299 if(st.wYear == 0) {
300 set_week_day = st.wDayOfWeek-week_day(time);
301 if(set_week_day < 0)
302 set_week_day += 7;
303 time += set_week_day * MS_PER_DAY;
305 time += (DOUBLE)(st.wDay-1) * 7 * MS_PER_DAY;
306 if(month_from_time(time) != st.wMonth-1)
307 time -= 7 * MS_PER_DAY;
309 else
310 time += st.wDay * MS_PER_DAY;
312 time += st.wHour * MS_PER_HOUR;
313 time += st.wMinute * MS_PER_MINUTE;
315 return time;
318 /* ECMA-262 3rd Edition 15.9.1.9 */
319 static inline DOUBLE daylight_saving_ta(DOUBLE time, DateInstance *date)
321 int year = year_from_time(time);
322 DOUBLE standardTime, daylightTime;
324 if(isnan(time))
325 return 0;
327 standardTime = convert_time(year, date->standardDate);
328 daylightTime = convert_time(year, date->daylightDate);
330 if(isnan(standardTime) || isnan(daylightTime))
331 return 0;
332 else if(standardTime > daylightTime) {
333 if(daylightTime <= time && time < standardTime)
334 return date->daylightBias;
336 return date->standardBias;
338 else {
339 if(standardTime <= time && time < daylightTime)
340 return date->standardBias;
342 return date->daylightBias;
346 /* ECMA-262 3rd Edition 15.9.1.9 */
347 static inline DOUBLE local_time(DOUBLE time, DateInstance *date)
349 return time - (daylight_saving_ta(time, date)+date->bias)*MS_PER_MINUTE;
352 /* ECMA-262 3rd Edition 15.9.1.9 */
353 static inline DOUBLE utc(DOUBLE time, DateInstance *date)
355 time += date->bias * MS_PER_MINUTE;
356 return time + daylight_saving_ta(time, date)*MS_PER_MINUTE;
359 /* ECMA-262 3rd Edition 15.9.1.10 */
360 static inline DOUBLE hour_from_time(DOUBLE time)
362 DOUBLE ret;
364 if(isnan(time))
365 return NAN;
367 ret = fmod(floor(time/MS_PER_HOUR), 24);
368 if(ret<0) ret += 24;
370 return ret;
373 /* ECMA-262 3rd Edition 15.9.1.10 */
374 static inline DOUBLE min_from_time(DOUBLE time)
376 DOUBLE ret;
378 if(isnan(time))
379 return NAN;
381 ret = fmod(floor(time/MS_PER_MINUTE), 60);
382 if(ret<0) ret += 60;
384 return ret;
387 /* ECMA-262 3rd Edition 15.9.1.10 */
388 static inline DOUBLE sec_from_time(DOUBLE time)
390 DOUBLE ret;
392 if(isnan(time))
393 return NAN;
395 ret = fmod(floor(time/1000), 60);
396 if(ret<0) ret += 60;
398 return ret;
401 /* ECMA-262 3rd Edition 15.9.1.10 */
402 static inline DOUBLE ms_from_time(DOUBLE time)
404 DOUBLE ret;
406 if(isnan(time))
407 return NAN;
409 ret = fmod(time, 1000);
410 if(ret<0) ret += 1000;
412 return ret;
415 /* ECMA-262 3rd Edition 15.9.1.11 */
416 static inline DOUBLE make_time(DOUBLE hour, DOUBLE min, DOUBLE sec, DOUBLE ms)
418 return hour*MS_PER_HOUR + min*MS_PER_MINUTE + sec*1000 + ms;
421 /* ECMA-262 3rd Edition 15.9.1.12 */
422 static inline DOUBLE make_day(DOUBLE year, DOUBLE month, DOUBLE day)
424 DOUBLE time;
426 year += floor(month/12);
428 month = fmod(month, 12);
429 if(month<0) month += 12;
431 time = time_from_year(year);
433 day += floor(time / MS_PER_DAY);
434 day += day_from_month(month, in_leap_year(time));
436 return day-1;
439 /* ECMA-262 3rd Edition 15.9.1.13 */
440 static inline DOUBLE make_date(DOUBLE day, DOUBLE time)
442 return day*MS_PER_DAY + time;
445 /* ECMA-262 3rd Edition 15.9.1.14 */
446 static inline DOUBLE time_clip(DOUBLE time)
448 if(8.64e15 < time || time < -8.64e15) {
449 return NAN;
452 return floor(time);
455 static SYSTEMTIME create_systemtime(DOUBLE time)
457 SYSTEMTIME st;
459 st.wYear = year_from_time(time);
460 st.wMonth = month_from_time(time) + 1;
461 st.wDayOfWeek = week_day(time);
462 st.wDay = date_from_time(time);
463 st.wHour = hour_from_time(time);
464 st.wMinute = min_from_time(time);
465 st.wSecond = sec_from_time(time);
466 st.wMilliseconds = ms_from_time(time);
468 return st;
471 static inline HRESULT date_to_string(DOUBLE time, BOOL show_offset, int offset, jsval_t *r)
473 static const WCHAR formatW[] = { '%','s',' ','%','s',' ','%','d',' ',
474 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
475 'U','T','C','%','c','%','0','2','d','%','0','2','d',' ','%','d','%','s',0 };
476 static const WCHAR formatUTCW[] = { '%','s',' ','%','s',' ','%','d',' ',
477 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ',
478 'U','T','C',' ','%','d','%','s',0 };
479 static const WCHAR formatNoOffsetW[] = { '%','s',' ','%','s',' ',
480 '%','d',' ','%','0','2','d',':','%','0','2','d',':',
481 '%','0','2','d',' ','%','d','%','s',0 };
482 static const WCHAR ADW[] = { 0 };
483 static const WCHAR BCW[] = { ' ','B','.','C','.',0 };
485 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
486 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
487 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
488 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
489 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
490 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
491 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
492 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
493 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
495 BOOL formatAD = TRUE;
496 WCHAR week[64], month[64];
497 WCHAR buf[192];
498 jsstr_t *date_jsstr;
499 int year, day;
500 DWORD lcid_en;
501 WCHAR sign = '-';
503 if(isnan(time)) {
504 if(r)
505 *r = jsval_string(jsstr_nan());
506 return S_OK;
509 if(r) {
510 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
512 week[0] = 0;
513 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
515 month[0] = 0;
516 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
518 year = year_from_time(time);
519 if(year<0) {
520 formatAD = FALSE;
521 year = -year+1;
524 day = date_from_time(time);
526 if(offset < 0) {
527 sign = '+';
528 offset = -offset;
531 if(!show_offset)
532 sprintfW(buf, formatNoOffsetW, week, month, day,
533 (int)hour_from_time(time), (int)min_from_time(time),
534 (int)sec_from_time(time), year, formatAD?ADW:BCW);
535 else if(offset)
536 sprintfW(buf, formatW, week, month, day,
537 (int)hour_from_time(time), (int)min_from_time(time),
538 (int)sec_from_time(time), sign, offset/60, offset%60,
539 year, formatAD?ADW:BCW);
540 else
541 sprintfW(buf, formatUTCW, week, month, day,
542 (int)hour_from_time(time), (int)min_from_time(time),
543 (int)sec_from_time(time), year, formatAD?ADW:BCW);
545 date_jsstr = jsstr_alloc(buf);
546 if(!date_jsstr)
547 return E_OUTOFMEMORY;
549 *r = jsval_string(date_jsstr);
551 return S_OK;
554 /* ECMA-262 3rd Edition 15.9.1.2 */
555 static HRESULT dateobj_to_string(DateInstance *date, jsval_t *r)
557 DOUBLE time;
558 int offset;
560 time = local_time(date->time, date);
561 offset = date->bias +
562 daylight_saving_ta(time, date);
564 return date_to_string(time, TRUE, offset, r);
567 static HRESULT Date_toString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
569 DateInstance *date;
571 TRACE("\n");
573 if(!(date = date_this(jsthis)))
574 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
576 return dateobj_to_string(date, r);
579 /* ECMA-262 3rd Edition 15.9.1.5 */
580 static HRESULT Date_toLocaleString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
581 jsval_t *r)
583 SYSTEMTIME st;
584 DateInstance *date;
585 jsstr_t *date_str;
586 int date_len, time_len;
588 TRACE("\n");
590 if(!(date = date_this(jsthis)))
591 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
593 if(isnan(date->time)) {
594 if(r)
595 *r = jsval_string(jsstr_nan());
596 return S_OK;
599 st = create_systemtime(local_time(date->time, date));
601 if(st.wYear<1601 || st.wYear>9999)
602 return dateobj_to_string(date, r);
604 if(r) {
605 WCHAR *ptr;
607 date_len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
608 time_len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
610 date_str = jsstr_alloc_buf(date_len+time_len-1, &ptr);
611 if(!date_str)
612 return E_OUTOFMEMORY;
614 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, date_len);
615 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr+date_len, time_len);
616 ptr[date_len-1] = ' ';
618 *r = jsval_string(date_str);
620 return S_OK;
623 static HRESULT Date_valueOf(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
624 jsval_t *r)
626 DateInstance *date;
628 TRACE("\n");
630 if(!(date = date_this(jsthis)))
631 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
633 if(r)
634 *r = jsval_number(date->time);
635 return S_OK;
638 static inline HRESULT create_utc_string(script_ctx_t *ctx, vdisp_t *jsthis, jsval_t *r)
640 static const WCHAR formatADW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ',
641 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
642 static const WCHAR formatBCW[] = { '%','s',',',' ','%','d',' ','%','s',' ','%','d',' ','B','.','C','.',' ',
643 '%','0','2','d',':','%','0','2','d',':','%','0','2','d',' ','U','T','C',0 };
645 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
646 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
647 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
648 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
649 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
650 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
651 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
652 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
653 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
655 BOOL formatAD = TRUE;
656 WCHAR week[64], month[64];
657 WCHAR buf[192];
658 DateInstance *date;
659 jsstr_t *date_str;
660 int year, day;
661 DWORD lcid_en;
663 if(!(date = date_this(jsthis)))
664 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
666 if(isnan(date->time)) {
667 if(r)
668 *r = jsval_string(jsstr_nan());
669 return S_OK;
672 if(r) {
673 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
675 week[0] = 0;
676 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(date->time)], week, sizeof(week)/sizeof(*week));
678 month[0] = 0;
679 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(date->time)], month, sizeof(month)/sizeof(*month));
681 year = year_from_time(date->time);
682 if(year<0) {
683 formatAD = FALSE;
684 year = -year+1;
687 day = date_from_time(date->time);
689 sprintfW(buf, formatAD ? formatADW : formatBCW, week, day, month, year,
690 (int)hour_from_time(date->time), (int)min_from_time(date->time),
691 (int)sec_from_time(date->time));
693 date_str = jsstr_alloc(buf);
694 if(!date_str)
695 return E_OUTOFMEMORY;
697 *r = jsval_string(date_str);
699 return S_OK;
702 /* ECMA-262 3rd Edition 15.9.5.42 */
703 static HRESULT Date_toUTCString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
704 jsval_t *r)
706 TRACE("\n");
707 return create_utc_string(ctx, jsthis, r);
710 static HRESULT Date_toGMTString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
711 jsval_t *r)
713 TRACE("\n");
714 return create_utc_string(ctx, jsthis, r);
717 /* ECMA-262 3rd Edition 15.9.5.3 */
718 static HRESULT dateobj_to_date_string(DateInstance *date, jsval_t *r)
720 static const WCHAR formatADW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',0 };
721 static const WCHAR formatBCW[] = { '%','s',' ','%','s',' ','%','d',' ','%','d',' ','B','.','C','.',0 };
723 static const DWORD week_ids[] = { LOCALE_SABBREVDAYNAME7, LOCALE_SABBREVDAYNAME1,
724 LOCALE_SABBREVDAYNAME2, LOCALE_SABBREVDAYNAME3, LOCALE_SABBREVDAYNAME4,
725 LOCALE_SABBREVDAYNAME5, LOCALE_SABBREVDAYNAME6 };
726 static const DWORD month_ids[] = { LOCALE_SABBREVMONTHNAME1, LOCALE_SABBREVMONTHNAME2,
727 LOCALE_SABBREVMONTHNAME3, LOCALE_SABBREVMONTHNAME4,
728 LOCALE_SABBREVMONTHNAME5, LOCALE_SABBREVMONTHNAME6,
729 LOCALE_SABBREVMONTHNAME7, LOCALE_SABBREVMONTHNAME8,
730 LOCALE_SABBREVMONTHNAME9, LOCALE_SABBREVMONTHNAME10,
731 LOCALE_SABBREVMONTHNAME11, LOCALE_SABBREVMONTHNAME12 };
733 BOOL formatAD = TRUE;
734 WCHAR week[64], month[64];
735 WCHAR buf[192];
736 jsstr_t *date_str;
737 DOUBLE time;
738 int year, day;
739 DWORD lcid_en;
741 if(isnan(date->time)) {
742 if(r)
743 *r = jsval_string(jsstr_nan());
744 return S_OK;
747 time = local_time(date->time, date);
749 if(r) {
750 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
752 week[0] = 0;
753 GetLocaleInfoW(lcid_en, week_ids[(int)week_day(time)], week, sizeof(week)/sizeof(*week));
755 month[0] = 0;
756 GetLocaleInfoW(lcid_en, month_ids[(int)month_from_time(time)], month, sizeof(month)/sizeof(*month));
758 year = year_from_time(time);
759 if(year<0) {
760 formatAD = FALSE;
761 year = -year+1;
764 day = date_from_time(time);
766 sprintfW(buf, formatAD ? formatADW : formatBCW, week, month, day, year);
768 date_str = jsstr_alloc(buf);
769 if(!date_str)
770 return E_OUTOFMEMORY;
772 *r = jsval_string(date_str);
774 return S_OK;
777 static HRESULT Date_toDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
778 jsval_t *r)
780 DateInstance *date;
782 if(!(date = date_this(jsthis)))
783 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
785 return dateobj_to_date_string(date, r);
788 /* ECMA-262 3rd Edition 15.9.5.4 */
789 static HRESULT Date_toTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
790 jsval_t *r)
792 static const WCHAR formatW[] = { '%','0','2','d',':','%','0','2','d',':','%','0','2','d',
793 ' ','U','T','C','%','c','%','0','2','d','%','0','2','d',0 };
794 static const WCHAR formatUTCW[] = { '%','0','2','d',':','%','0','2','d',
795 ':','%','0','2','d',' ','U','T','C',0 };
796 DateInstance *date;
797 jsstr_t *date_str;
798 WCHAR buf[32];
799 DOUBLE time;
800 WCHAR sign;
801 int offset;
803 TRACE("\n");
805 if(!(date = date_this(jsthis)))
806 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
808 if(isnan(date->time)) {
809 if(r)
810 *r = jsval_string(jsstr_nan());
811 return S_OK;
814 time = local_time(date->time, date);
816 if(r) {
817 offset = date->bias +
818 daylight_saving_ta(time, date);
820 if(offset < 0) {
821 sign = '+';
822 offset = -offset;
824 else sign = '-';
826 if(offset)
827 sprintfW(buf, formatW, (int)hour_from_time(time),
828 (int)min_from_time(time), (int)sec_from_time(time),
829 sign, offset/60, offset%60);
830 else
831 sprintfW(buf, formatUTCW, (int)hour_from_time(time),
832 (int)min_from_time(time), (int)sec_from_time(time));
834 date_str = jsstr_alloc(buf);
835 if(!date_str)
836 return E_OUTOFMEMORY;
838 *r = jsval_string(date_str);
840 return S_OK;
843 /* ECMA-262 3rd Edition 15.9.5.6 */
844 static HRESULT Date_toLocaleDateString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
845 jsval_t *r)
847 SYSTEMTIME st;
848 DateInstance *date;
849 jsstr_t *date_str;
850 int len;
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 st = create_systemtime(local_time(date->time, date));
865 if(st.wYear<1601 || st.wYear>9999)
866 return dateobj_to_date_string(date, r);
868 if(r) {
869 WCHAR *ptr;
871 len = GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, NULL, 0);
872 date_str = jsstr_alloc_buf(len-1, &ptr);
873 if(!date_str)
874 return E_OUTOFMEMORY;
875 GetDateFormatW(ctx->lcid, DATE_LONGDATE, &st, NULL, ptr, len);
877 *r = jsval_string(date_str);
879 return S_OK;
882 /* ECMA-262 3rd Edition 15.9.5.7 */
883 static HRESULT Date_toLocaleTimeString(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
884 jsval_t *r)
886 SYSTEMTIME st;
887 DateInstance *date;
888 jsstr_t *date_str;
889 int len;
891 TRACE("\n");
893 if(!(date = date_this(jsthis)))
894 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
896 if(isnan(date->time)) {
897 if(r)
898 *r = jsval_string(jsstr_nan());
899 return S_OK;
902 st = create_systemtime(local_time(date->time, date));
904 if(st.wYear<1601 || st.wYear>9999)
905 return Date_toTimeString(ctx, jsthis, flags, argc, argv, r);
907 if(r) {
908 WCHAR *ptr;
910 len = GetTimeFormatW(ctx->lcid, 0, &st, NULL, NULL, 0);
911 date_str = jsstr_alloc_buf(len-1, &ptr);
912 if(!date_str)
913 return E_OUTOFMEMORY;
914 GetTimeFormatW(ctx->lcid, 0, &st, NULL, ptr, len);
916 *r = jsval_string(date_str);
918 return S_OK;
921 /* ECMA-262 3rd Edition 15.9.5.9 */
922 static HRESULT Date_getTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
923 jsval_t *r)
925 DateInstance *date;
927 TRACE("\n");
929 if(!(date = date_this(jsthis)))
930 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
932 if(r)
933 *r = jsval_number(date->time);
934 return S_OK;
937 /* ECMA-262 3rd Edition 15.9.5.10 */
938 static HRESULT Date_getFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
939 jsval_t *r)
941 DateInstance *date;
943 TRACE("\n");
945 if(!(date = date_this(jsthis)))
946 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
948 if(r) {
949 DOUBLE time = local_time(date->time, date);
951 *r = jsval_number(year_from_time(time));
953 return S_OK;
956 /* ECMA-262 3rd Edition 15.9.5.11 */
957 static HRESULT Date_getUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
958 jsval_t *r)
960 DateInstance *date;
962 TRACE("\n");
964 if(!(date = date_this(jsthis)))
965 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
967 if(r)
968 *r = jsval_number(year_from_time(date->time));
969 return S_OK;
972 /* ECMA-262 3rd Edition 15.9.5.12 */
973 static HRESULT Date_getMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
975 DateInstance *date;
977 TRACE("\n");
979 if(!(date = date_this(jsthis)))
980 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
982 if(r)
983 *r = jsval_number(month_from_time(local_time(date->time, date)));
984 return S_OK;
987 /* ECMA-262 3rd Edition 15.9.5.13 */
988 static HRESULT Date_getUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
989 jsval_t *r)
991 DateInstance *date;
993 TRACE("\n");
995 if(!(date = date_this(jsthis)))
996 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
998 if(r)
999 *r = jsval_number(month_from_time(date->time));
1000 return S_OK;
1003 /* ECMA-262 3rd Edition 15.9.5.14 */
1004 static HRESULT Date_getDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1006 DateInstance *date;
1008 TRACE("\n");
1010 if(!(date = date_this(jsthis)))
1011 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1013 if(r)
1014 *r = jsval_number(date_from_time(local_time(date->time, date)));
1015 return S_OK;
1018 /* ECMA-262 3rd Edition 15.9.5.15 */
1019 static HRESULT Date_getUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1020 jsval_t *r)
1022 DateInstance *date;
1024 TRACE("\n");
1026 if(!(date = date_this(jsthis)))
1027 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1029 if(r)
1030 *r = jsval_number(date_from_time(date->time));
1031 return S_OK;
1034 /* ECMA-262 3rd Edition 15.9.5.16 */
1035 static HRESULT Date_getDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1036 jsval_t *r)
1038 DateInstance *date;
1040 TRACE("\n");
1042 if(!(date = date_this(jsthis)))
1043 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1045 if(r)
1046 *r = jsval_number(week_day(local_time(date->time, date)));
1047 return S_OK;
1050 /* ECMA-262 3rd Edition 15.9.5.17 */
1051 static HRESULT Date_getUTCDay(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1052 jsval_t *r)
1054 DateInstance *date;
1056 TRACE("\n");
1058 if(!(date = date_this(jsthis)))
1059 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1061 if(r)
1062 *r = jsval_number(week_day(date->time));
1063 return S_OK;
1066 /* ECMA-262 3rd Edition 15.9.5.18 */
1067 static HRESULT Date_getHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1068 jsval_t *r)
1070 DateInstance *date;
1072 TRACE("\n");
1074 if(!(date = date_this(jsthis)))
1075 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1077 if(r)
1078 *r = jsval_number(hour_from_time(local_time(date->time, date)));
1079 return S_OK;
1082 /* ECMA-262 3rd Edition 15.9.5.19 */
1083 static HRESULT Date_getUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1084 jsval_t *r)
1086 DateInstance *date;
1088 TRACE("\n");
1090 if(!(date = date_this(jsthis)))
1091 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1093 if(r)
1094 *r = jsval_number(hour_from_time(date->time));
1095 return S_OK;
1098 /* ECMA-262 3rd Edition 15.9.5.20 */
1099 static HRESULT Date_getMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1100 jsval_t *r)
1102 DateInstance *date;
1104 TRACE("\n");
1106 if(!(date = date_this(jsthis)))
1107 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1109 if(r)
1110 *r = jsval_number(min_from_time(local_time(date->time, date)));
1111 return S_OK;
1114 /* ECMA-262 3rd Edition 15.9.5.21 */
1115 static HRESULT Date_getUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1116 jsval_t *r)
1118 DateInstance *date;
1120 TRACE("\n");
1122 if(!(date = date_this(jsthis)))
1123 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1125 if(r)
1126 *r = jsval_number(min_from_time(date->time));
1127 return S_OK;
1130 /* ECMA-262 3rd Edition 15.9.5.22 */
1131 static HRESULT Date_getSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv, jsval_t *r)
1133 DateInstance *date;
1135 TRACE("\n");
1137 if(!(date = date_this(jsthis)))
1138 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1140 if(r)
1141 *r = jsval_number(sec_from_time(local_time(date->time, date)));
1142 return S_OK;
1145 /* ECMA-262 3rd Edition 15.9.5.23 */
1146 static HRESULT Date_getUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1147 jsval_t *r)
1149 DateInstance *date;
1151 TRACE("\n");
1153 if(!(date = date_this(jsthis)))
1154 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1156 if(r)
1157 *r = jsval_number(sec_from_time(date->time));
1158 return S_OK;
1161 /* ECMA-262 3rd Edition 15.9.5.24 */
1162 static HRESULT Date_getMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1163 jsval_t *r)
1165 DateInstance *date;
1167 TRACE("\n");
1169 if(!(date = date_this(jsthis)))
1170 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1172 if(r)
1173 *r = jsval_number(ms_from_time(local_time(date->time, date)));
1174 return S_OK;
1177 /* ECMA-262 3rd Edition 15.9.5.25 */
1178 static HRESULT Date_getUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1179 jsval_t *r)
1181 DateInstance *date;
1183 TRACE("\n");
1185 if(!(date = date_this(jsthis)))
1186 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1188 if(r)
1189 *r = jsval_number(ms_from_time(date->time));
1190 return S_OK;
1193 /* ECMA-262 3rd Edition 15.9.5.26 */
1194 static HRESULT Date_getTimezoneOffset(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1195 jsval_t *r)
1197 DateInstance *date;
1199 TRACE("\n");
1201 if(!(date = date_this(jsthis)))
1202 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1204 if(r)
1205 *r = jsval_number(floor((date->time-local_time(date->time, date))/MS_PER_MINUTE));
1206 return S_OK;
1209 /* ECMA-262 3rd Edition 15.9.5.27 */
1210 static HRESULT Date_setTime(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1211 jsval_t *r)
1213 double n;
1214 HRESULT hres;
1215 DateInstance *date;
1217 TRACE("\n");
1219 if(!(date = date_this(jsthis)))
1220 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1222 if(!argc)
1223 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1225 hres = to_number(ctx, argv[0], &n);
1226 if(FAILED(hres))
1227 return hres;
1229 date->time = time_clip(n);
1231 if(r)
1232 *r = jsval_number(date->time);
1233 return S_OK;
1236 /* ECMA-262 3rd Edition 15.9.5.28 */
1237 static HRESULT Date_setMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1238 jsval_t *r)
1240 DateInstance *date;
1241 double n, t;
1242 HRESULT hres;
1244 TRACE("\n");
1246 if(!(date = date_this(jsthis)))
1247 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1249 if(!argc)
1250 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1252 hres = to_number(ctx, argv[0], &n);
1253 if(FAILED(hres))
1254 return hres;
1256 t = local_time(date->time, date);
1257 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1258 sec_from_time(t), n));
1259 date->time = time_clip(utc(t, date));
1261 if(r)
1262 *r = jsval_number(date->time);
1263 return S_OK;
1266 /* ECMA-262 3rd Edition 15.9.5.29 */
1267 static HRESULT Date_setUTCMilliseconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1268 jsval_t *r)
1270 DateInstance *date;
1271 double n, t;
1272 HRESULT hres;
1274 TRACE("\n");
1276 if(!(date = date_this(jsthis)))
1277 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1279 if(!argc)
1280 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1282 hres = to_number(ctx, argv[0], &n);
1283 if(FAILED(hres))
1284 return hres;
1286 t = date->time;
1287 t = make_date(day(t), make_time(hour_from_time(t), min_from_time(t),
1288 sec_from_time(t), n));
1289 date->time = time_clip(t);
1291 if(r)
1292 *r = jsval_number(date->time);
1293 return S_OK;
1296 /* ECMA-262 3rd Edition 15.9.5.30 */
1297 static HRESULT Date_setSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1298 jsval_t *r)
1300 DateInstance *date;
1301 double t, sec, ms;
1302 HRESULT hres;
1304 TRACE("\n");
1306 if(!(date = date_this(jsthis)))
1307 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1309 if(!argc)
1310 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1312 t = local_time(date->time, date);
1314 hres = to_number(ctx, argv[0], &sec);
1315 if(FAILED(hres))
1316 return hres;
1318 if(argc > 1) {
1319 hres = to_number(ctx, argv[1], &ms);
1320 if(FAILED(hres))
1321 return hres;
1322 }else {
1323 ms = ms_from_time(t);
1326 t = make_date(day(t), make_time(hour_from_time(t),
1327 min_from_time(t), sec, ms));
1328 date->time = time_clip(utc(t, date));
1330 if(r)
1331 *r = jsval_number(date->time);
1332 return S_OK;
1335 /* ECMA-262 3rd Edition 15.9.5.31 */
1336 static HRESULT Date_setUTCSeconds(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1337 jsval_t *r)
1339 DateInstance *date;
1340 double t, sec, ms;
1341 HRESULT hres;
1343 TRACE("\n");
1345 if(!(date = date_this(jsthis)))
1346 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1348 if(!argc)
1349 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1351 t = date->time;
1353 hres = to_number(ctx, argv[0], &sec);
1354 if(FAILED(hres))
1355 return hres;
1357 if(argc > 1) {
1358 hres = to_number(ctx, argv[1], &ms);
1359 if(FAILED(hres))
1360 return hres;
1361 }else {
1362 ms = ms_from_time(t);
1365 t = make_date(day(t), make_time(hour_from_time(t),
1366 min_from_time(t), sec, ms));
1367 date->time = time_clip(t);
1369 if(r)
1370 *r = jsval_number(date->time);
1371 return S_OK;
1374 /* ECMA-262 3rd Edition 15.9.5.33 */
1375 static HRESULT Date_setMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1376 jsval_t *r)
1378 DateInstance *date;
1379 double t, min, sec, ms;
1380 HRESULT hres;
1382 TRACE("\n");
1384 if(!(date = date_this(jsthis)))
1385 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1387 if(!argc)
1388 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1390 t = local_time(date->time, date);
1392 hres = to_number(ctx, argv[0], &min);
1393 if(FAILED(hres))
1394 return hres;
1396 if(argc > 1) {
1397 hres = to_number(ctx, argv[1], &sec);
1398 if(FAILED(hres))
1399 return hres;
1400 }else {
1401 sec = sec_from_time(t);
1404 if(argc > 2) {
1405 hres = to_number(ctx, argv[2], &ms);
1406 if(FAILED(hres))
1407 return hres;
1408 }else {
1409 ms = ms_from_time(t);
1412 t = make_date(day(t), make_time(hour_from_time(t),
1413 min, sec, ms));
1414 date->time = time_clip(utc(t, date));
1416 if(r)
1417 *r = jsval_number(date->time);
1418 return S_OK;
1421 /* ECMA-262 3rd Edition 15.9.5.34 */
1422 static HRESULT Date_setUTCMinutes(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1423 jsval_t *r)
1425 DateInstance *date;
1426 double t, min, sec, ms;
1427 HRESULT hres;
1429 TRACE("\n");
1431 if(!(date = date_this(jsthis)))
1432 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1434 if(!argc)
1435 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1437 t = date->time;
1439 hres = to_number(ctx, argv[0], &min);
1440 if(FAILED(hres))
1441 return hres;
1443 if(argc > 1) {
1444 hres = to_number(ctx, argv[1], &sec);
1445 if(FAILED(hres))
1446 return hres;
1447 }else {
1448 sec = sec_from_time(t);
1451 if(argc > 2) {
1452 hres = to_number(ctx, argv[2], &ms);
1453 if(FAILED(hres))
1454 return hres;
1455 }else {
1456 ms = ms_from_time(t);
1459 t = make_date(day(t), make_time(hour_from_time(t),
1460 min, sec, ms));
1461 date->time = time_clip(t);
1463 if(r)
1464 *r = jsval_number(date->time);
1465 return S_OK;
1468 /* ECMA-262 3rd Edition 15.9.5.35 */
1469 static HRESULT Date_setHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1470 jsval_t *r)
1472 DateInstance *date;
1473 double t, hour, min, sec, ms;
1474 HRESULT hres;
1476 TRACE("\n");
1478 if(!(date = date_this(jsthis)))
1479 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1481 if(!argc)
1482 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1484 t = local_time(date->time, date);
1486 hres = to_number(ctx, argv[0], &hour);
1487 if(FAILED(hres))
1488 return hres;
1490 if(argc > 1) {
1491 hres = to_number(ctx, argv[1], &min);
1492 if(FAILED(hres))
1493 return hres;
1494 }else {
1495 min = min_from_time(t);
1498 if(argc > 2) {
1499 hres = to_number(ctx, argv[2], &sec);
1500 if(FAILED(hres))
1501 return hres;
1502 }else {
1503 sec = sec_from_time(t);
1506 if(argc > 3) {
1507 hres = to_number(ctx, argv[3], &ms);
1508 if(FAILED(hres))
1509 return hres;
1510 }else {
1511 ms = ms_from_time(t);
1514 t = make_date(day(t), make_time(hour, min, sec, ms));
1515 date->time = time_clip(utc(t, date));
1517 if(r)
1518 *r = jsval_number(date->time);
1519 return S_OK;
1522 /* ECMA-262 3rd Edition 15.9.5.36 */
1523 static HRESULT Date_setUTCHours(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1524 jsval_t *r)
1526 DateInstance *date;
1527 double t, hour, min, sec, ms;
1528 HRESULT hres;
1530 TRACE("\n");
1532 if(!(date = date_this(jsthis)))
1533 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1535 if(!argc)
1536 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1538 t = date->time;
1540 hres = to_number(ctx, argv[0], &hour);
1541 if(FAILED(hres))
1542 return hres;
1544 if(argc > 1) {
1545 hres = to_number(ctx, argv[1], &min);
1546 if(FAILED(hres))
1547 return hres;
1548 }else {
1549 min = min_from_time(t);
1552 if(argc > 2) {
1553 hres = to_number(ctx, argv[2], &sec);
1554 if(FAILED(hres))
1555 return hres;
1556 }else {
1557 sec = sec_from_time(t);
1560 if(argc > 3) {
1561 hres = to_number(ctx, argv[3], &ms);
1562 if(FAILED(hres))
1563 return hres;
1564 }else {
1565 ms = ms_from_time(t);
1568 t = make_date(day(t), make_time(hour, min, sec, ms));
1569 date->time = time_clip(t);
1571 if(r)
1572 *r = jsval_number(date->time);
1573 return S_OK;
1576 /* ECMA-262 3rd Edition 15.9.5.36 */
1577 static HRESULT Date_setDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1578 jsval_t *r)
1580 DateInstance *date;
1581 double t, n;
1582 HRESULT hres;
1584 TRACE("\n");
1586 if(!(date = date_this(jsthis)))
1587 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1589 if(!argc)
1590 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1592 hres = to_number(ctx, argv[0], &n);
1593 if(FAILED(hres))
1594 return hres;
1596 t = local_time(date->time, date);
1597 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1598 date->time = time_clip(utc(t, date));
1600 if(r)
1601 *r = jsval_number(date->time);
1602 return S_OK;
1605 /* ECMA-262 3rd Edition 15.9.5.37 */
1606 static HRESULT Date_setUTCDate(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1607 jsval_t *r)
1609 DateInstance *date;
1610 double t, n;
1611 HRESULT hres;
1613 TRACE("\n");
1615 if(!(date = date_this(jsthis)))
1616 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1618 if(!argc)
1619 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1621 hres = to_number(ctx, argv[0], &n);
1622 if(FAILED(hres))
1623 return hres;
1625 t = date->time;
1626 t = make_date(make_day(year_from_time(t), month_from_time(t), n), time_within_day(t));
1627 date->time = time_clip(t);
1629 if(r)
1630 *r = jsval_number(date->time);
1631 return S_OK;
1634 /* ECMA-262 3rd Edition 15.9.5.38 */
1635 static HRESULT Date_setMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1636 jsval_t *r)
1638 DateInstance *date;
1639 DOUBLE t, month, ddate;
1640 HRESULT hres;
1642 TRACE("\n");
1644 if(!(date = date_this(jsthis)))
1645 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1647 if(!argc)
1648 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1650 t = local_time(date->time, date);
1652 hres = to_number(ctx, argv[0], &month);
1653 if(FAILED(hres))
1654 return hres;
1656 if(argc > 1) {
1657 hres = to_number(ctx, argv[1], &ddate);
1658 if(FAILED(hres))
1659 return hres;
1660 }else {
1661 ddate = date_from_time(t);
1664 t = make_date(make_day(year_from_time(t), month, ddate),
1665 time_within_day(t));
1666 date->time = time_clip(utc(t, date));
1668 if(r)
1669 *r = jsval_number(date->time);
1670 return S_OK;
1673 /* ECMA-262 3rd Edition 15.9.5.39 */
1674 static HRESULT Date_setUTCMonth(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1675 jsval_t *r)
1677 DateInstance *date;
1678 double t, month, ddate;
1679 HRESULT hres;
1681 TRACE("\n");
1683 if(!(date = date_this(jsthis)))
1684 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1686 if(!argc)
1687 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1689 t = date->time;
1691 hres = to_number(ctx, argv[0], &month);
1692 if(FAILED(hres))
1693 return hres;
1695 if(argc > 1) {
1696 hres = to_number(ctx, argv[1], &ddate);
1697 if(FAILED(hres))
1698 return hres;
1699 }else {
1700 ddate = date_from_time(t);
1703 t = make_date(make_day(year_from_time(t), month, ddate),
1704 time_within_day(t));
1705 date->time = time_clip(t);
1707 if(r)
1708 *r = jsval_number(date->time);
1709 return S_OK;
1712 /* ECMA-262 3rd Edition 15.9.5.40 */
1713 static HRESULT Date_setFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1714 jsval_t *r)
1716 DateInstance *date;
1717 double t, year, month, ddate;
1718 HRESULT hres;
1720 TRACE("\n");
1722 if(!(date = date_this(jsthis)))
1723 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1725 if(!argc)
1726 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1728 t = local_time(date->time, date);
1730 hres = to_number(ctx, argv[0], &year);
1731 if(FAILED(hres))
1732 return hres;
1734 if(argc > 1) {
1735 hres = to_number(ctx, argv[1], &month);
1736 if(FAILED(hres))
1737 return hres;
1738 }else {
1739 month = month_from_time(t);
1742 if(argc > 2) {
1743 hres = to_number(ctx, argv[2], &ddate);
1744 if(FAILED(hres))
1745 return hres;
1746 }else {
1747 ddate = date_from_time(t);
1750 t = make_date(make_day(year, month, ddate), time_within_day(t));
1751 date->time = time_clip(utc(t, date));
1753 if(r)
1754 *r = jsval_number(date->time);
1755 return S_OK;
1758 /* ECMA-262 3rd Edition 15.9.5.41 */
1759 static HRESULT Date_setUTCFullYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1760 jsval_t *r)
1762 DateInstance *date;
1763 double t, year, month, ddate;
1764 HRESULT hres;
1766 TRACE("\n");
1768 if(!(date = date_this(jsthis)))
1769 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1771 if(!argc)
1772 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1774 t = date->time;
1776 hres = to_number(ctx, argv[0], &year);
1777 if(FAILED(hres))
1778 return hres;
1780 if(argc > 1) {
1781 hres = to_number(ctx, argv[1], &month);
1782 if(FAILED(hres))
1783 return hres;
1784 }else {
1785 month = month_from_time(t);
1788 if(argc > 2) {
1789 hres = to_number(ctx, argv[2], &ddate);
1790 if(FAILED(hres))
1791 return hres;
1792 }else {
1793 ddate = date_from_time(t);
1796 t = make_date(make_day(year, month, ddate), time_within_day(t));
1797 date->time = time_clip(t);
1799 if(r)
1800 *r = jsval_number(date->time);
1801 return S_OK;
1804 /* ECMA-262 3rd Edition B2.4 */
1805 static HRESULT Date_getYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1806 jsval_t *r)
1808 DateInstance *date;
1809 DOUBLE t, year;
1811 TRACE("\n");
1813 if(!(date = date_this(jsthis)))
1814 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1816 t = local_time(date->time, date);
1817 if(isnan(t)) {
1818 if(r)
1819 *r = jsval_number(NAN);
1820 return S_OK;
1823 year = year_from_time(t);
1824 if(r)
1825 *r = jsval_number((1900<=year && year<2000)?year-1900:year);
1826 return S_OK;
1829 /* ECMA-262 3rd Edition B2.5 */
1830 static HRESULT Date_setYear(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
1831 jsval_t *r)
1833 DateInstance *date;
1834 DOUBLE t, year;
1835 HRESULT hres;
1837 TRACE("\n");
1839 if(!(date = date_this(jsthis)))
1840 return throw_type_error(ctx, JS_E_DATE_EXPECTED, NULL);
1842 if(!argc)
1843 return throw_type_error(ctx, JS_E_MISSING_ARG, NULL);
1845 t = local_time(date->time, date);
1847 hres = to_number(ctx, argv[0], &year);
1848 if(FAILED(hres))
1849 return hres;
1851 if(isnan(year)) {
1852 date->time = year;
1853 if(r)
1854 *r = jsval_number(NAN);
1855 return S_OK;
1858 year = year >= 0.0 ? floor(year) : -floor(-year);
1859 if(-1.0 < year && year < 100.0)
1860 year += 1900.0;
1862 date->time = time_clip(utc(make_date(make_day(year, month_from_time(t), date_from_time(t)), time_within_day(t)), date));
1864 if(r)
1865 *r = jsval_number(date->time);
1866 return S_OK;
1869 static HRESULT Date_get_value(script_ctx_t *ctx, jsdisp_t *jsthis, jsval_t *r)
1871 TRACE("\n");
1873 return dateobj_to_string(date_from_jsdisp(jsthis), r);
1876 static const builtin_prop_t Date_props[] = {
1877 {getDateW, Date_getDate, PROPF_METHOD},
1878 {getDayW, Date_getDay, PROPF_METHOD},
1879 {getFullYearW, Date_getFullYear, PROPF_METHOD},
1880 {getHoursW, Date_getHours, PROPF_METHOD},
1881 {getMillisecondsW, Date_getMilliseconds, PROPF_METHOD},
1882 {getMinutesW, Date_getMinutes, PROPF_METHOD},
1883 {getMonthW, Date_getMonth, PROPF_METHOD},
1884 {getSecondsW, Date_getSeconds, PROPF_METHOD},
1885 {getTimeW, Date_getTime, PROPF_METHOD},
1886 {getTimezoneOffsetW, Date_getTimezoneOffset, PROPF_METHOD},
1887 {getUTCDateW, Date_getUTCDate, PROPF_METHOD},
1888 {getUTCDayW, Date_getUTCDay, PROPF_METHOD},
1889 {getUTCFullYearW, Date_getUTCFullYear, PROPF_METHOD},
1890 {getUTCHoursW, Date_getUTCHours, PROPF_METHOD},
1891 {getUTCMillisecondsW, Date_getUTCMilliseconds, PROPF_METHOD},
1892 {getUTCMinutesW, Date_getUTCMinutes, PROPF_METHOD},
1893 {getUTCMonthW, Date_getUTCMonth, PROPF_METHOD},
1894 {getUTCSecondsW, Date_getUTCSeconds, PROPF_METHOD},
1895 {getYearW, Date_getYear, PROPF_METHOD},
1896 {setDateW, Date_setDate, PROPF_METHOD|1},
1897 {setFullYearW, Date_setFullYear, PROPF_METHOD|3},
1898 {setHoursW, Date_setHours, PROPF_METHOD|4},
1899 {setMillisecondsW, Date_setMilliseconds, PROPF_METHOD|1},
1900 {setMinutesW, Date_setMinutes, PROPF_METHOD|3},
1901 {setMonthW, Date_setMonth, PROPF_METHOD|2},
1902 {setSecondsW, Date_setSeconds, PROPF_METHOD|2},
1903 {setTimeW, Date_setTime, PROPF_METHOD|1},
1904 {setUTCDateW, Date_setUTCDate, PROPF_METHOD|1},
1905 {setUTCFullYearW, Date_setUTCFullYear, PROPF_METHOD|3},
1906 {setUTCHoursW, Date_setUTCHours, PROPF_METHOD|4},
1907 {setUTCMillisecondsW, Date_setUTCMilliseconds, PROPF_METHOD|1},
1908 {setUTCMinutesW, Date_setUTCMinutes, PROPF_METHOD|3},
1909 {setUTCMonthW, Date_setUTCMonth, PROPF_METHOD|2},
1910 {setUTCSecondsW, Date_setUTCSeconds, PROPF_METHOD|2},
1911 {setYearW, Date_setYear, PROPF_METHOD|1},
1912 {toDateStringW, Date_toDateString, PROPF_METHOD},
1913 {toGMTStringW, Date_toGMTString, PROPF_METHOD},
1914 {toLocaleDateStringW, Date_toLocaleDateString, PROPF_METHOD},
1915 {toLocaleStringW, Date_toLocaleString, PROPF_METHOD},
1916 {toLocaleTimeStringW, Date_toLocaleTimeString, PROPF_METHOD},
1917 {toStringW, Date_toString, PROPF_METHOD},
1918 {toTimeStringW, Date_toTimeString, PROPF_METHOD},
1919 {toUTCStringW, Date_toUTCString, PROPF_METHOD},
1920 {valueOfW, Date_valueOf, PROPF_METHOD},
1923 static const builtin_info_t Date_info = {
1924 JSCLASS_DATE,
1925 {NULL, NULL,0, Date_get_value},
1926 sizeof(Date_props)/sizeof(*Date_props),
1927 Date_props,
1928 NULL,
1929 NULL
1932 static const builtin_info_t DateInst_info = {
1933 JSCLASS_DATE,
1934 {NULL, NULL,0, Date_get_value},
1935 0, NULL,
1936 NULL,
1937 NULL
1940 static HRESULT create_date(script_ctx_t *ctx, jsdisp_t *object_prototype, DOUBLE time, jsdisp_t **ret)
1942 DateInstance *date;
1943 HRESULT hres;
1944 TIME_ZONE_INFORMATION tzi;
1946 GetTimeZoneInformation(&tzi);
1948 date = heap_alloc_zero(sizeof(DateInstance));
1949 if(!date)
1950 return E_OUTOFMEMORY;
1952 if(object_prototype)
1953 hres = init_dispex(&date->dispex, ctx, &Date_info, object_prototype);
1954 else
1955 hres = init_dispex_from_constr(&date->dispex, ctx, &DateInst_info, ctx->date_constr);
1956 if(FAILED(hres)) {
1957 heap_free(date);
1958 return hres;
1961 date->time = time;
1962 date->bias = tzi.Bias;
1963 date->standardDate = tzi.StandardDate;
1964 date->standardBias = tzi.StandardBias;
1965 date->daylightDate = tzi.DaylightDate;
1966 date->daylightBias = tzi.DaylightBias;
1968 *ret = &date->dispex;
1969 return S_OK;
1972 static inline HRESULT date_parse(jsstr_t *input_str, double *ret) {
1973 static const DWORD string_ids[] = { LOCALE_SMONTHNAME12, LOCALE_SMONTHNAME11,
1974 LOCALE_SMONTHNAME10, LOCALE_SMONTHNAME9, LOCALE_SMONTHNAME8,
1975 LOCALE_SMONTHNAME7, LOCALE_SMONTHNAME6, LOCALE_SMONTHNAME5,
1976 LOCALE_SMONTHNAME4, LOCALE_SMONTHNAME3, LOCALE_SMONTHNAME2,
1977 LOCALE_SMONTHNAME1, LOCALE_SDAYNAME7, LOCALE_SDAYNAME1,
1978 LOCALE_SDAYNAME2, LOCALE_SDAYNAME3, LOCALE_SDAYNAME4,
1979 LOCALE_SDAYNAME5, LOCALE_SDAYNAME6 };
1980 WCHAR *strings[sizeof(string_ids)/sizeof(DWORD)];
1981 WCHAR *parse;
1982 int input_len, parse_len = 0, nest_level = 0, i, size;
1983 int year = 0, month = 0, day = 0, hour = 0, min = 0, sec = 0;
1984 int ms = 0, offset = 0, hour_adjust = 0;
1985 BOOL set_year = FALSE, set_month = FALSE, set_day = FALSE, set_hour = FALSE;
1986 BOOL set_offset = FALSE, set_era = FALSE, ad = TRUE, set_am = FALSE, am = TRUE;
1987 BOOL set_hour_adjust = TRUE;
1988 TIME_ZONE_INFORMATION tzi;
1989 const WCHAR *input;
1990 DateInstance di;
1991 DWORD lcid_en;
1993 input_len = jsstr_length(input_str);
1994 input = jsstr_flatten(input_str);
1995 if(!input)
1996 return E_OUTOFMEMORY;
1998 for(i=0; i<input_len; i++) {
1999 if(input[i] == '(') nest_level++;
2000 else if(input[i] == ')') {
2001 nest_level--;
2002 if(nest_level<0) {
2003 *ret = NAN;
2004 return S_OK;
2007 else if(!nest_level) parse_len++;
2010 parse = heap_alloc((parse_len+1)*sizeof(WCHAR));
2011 if(!parse)
2012 return E_OUTOFMEMORY;
2013 nest_level = 0;
2014 parse_len = 0;
2015 for(i=0; i<input_len; i++) {
2016 if(input[i] == '(') nest_level++;
2017 else if(input[i] == ')') nest_level--;
2018 else if(!nest_level) parse[parse_len++] = toupperW(input[i]);
2020 parse[parse_len] = 0;
2022 GetTimeZoneInformation(&tzi);
2023 di.bias = tzi.Bias;
2024 di.standardDate = tzi.StandardDate;
2025 di.standardBias = tzi.StandardBias;
2026 di.daylightDate = tzi.DaylightDate;
2027 di.daylightBias = tzi.DaylightBias;
2029 /* FIXME: Cache strings */
2030 lcid_en = MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US),SORT_DEFAULT);
2031 for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++) {
2032 size = GetLocaleInfoW(lcid_en, string_ids[i], NULL, 0);
2033 strings[i] = heap_alloc((size+1)*sizeof(WCHAR));
2034 if(!strings[i]) {
2035 i--;
2036 while(i-- >= 0)
2037 heap_free(strings[i]);
2038 heap_free(parse);
2039 return E_OUTOFMEMORY;
2041 GetLocaleInfoW(lcid_en, string_ids[i], strings[i], size);
2044 for(i=0; i<parse_len;) {
2045 while(isspaceW(parse[i])) i++;
2046 if(parse[i] == ',') {
2047 while(parse[i] == ',') i++;
2048 continue;
2051 if(parse[i]>='0' && parse[i]<='9') {
2052 int tmp = atoiW(&parse[i]);
2053 while(parse[i]>='0' && parse[i]<='9') i++;
2054 while(isspaceW(parse[i])) i++;
2056 if(parse[i] == ':') {
2057 /* Time */
2058 if(set_hour) break;
2059 set_hour = TRUE;
2061 hour = tmp;
2063 while(parse[i] == ':') i++;
2064 while(isspaceW(parse[i])) i++;
2065 if(parse[i]>='0' && parse[i]<='9') {
2066 min = atoiW(&parse[i]);
2067 while(parse[i]>='0' && parse[i]<='9') i++;
2070 while(isspaceW(parse[i])) i++;
2071 while(parse[i] == ':') i++;
2072 while(isspaceW(parse[i])) i++;
2073 if(parse[i]>='0' && parse[i]<='9') {
2074 sec = atoiW(&parse[i]);
2075 while(parse[i]>='0' && parse[i]<='9') i++;
2078 else if(parse[i]=='-' || parse[i]=='/') {
2079 /* Short or long date */
2080 if(set_day || set_month || set_year) break;
2081 set_day = TRUE;
2082 set_month = TRUE;
2083 set_year = TRUE;
2085 month = tmp-1;
2087 while(isspaceW(parse[i])) i++;
2088 while(parse[i]=='-' || parse[i]=='/') i++;
2089 while(isspaceW(parse[i])) i++;
2090 if(parse[i]<'0' || parse[i]>'9') break;
2091 day = atoiW(&parse[i]);
2092 while(parse[i]>='0' && parse[i]<='9') i++;
2094 while(parse[i]=='-' || parse[i]=='/') i++;
2095 while(isspaceW(parse[i])) i++;
2096 if(parse[i]<'0' || parse[i]>'9') break;
2097 year = atoiW(&parse[i]);
2098 while(parse[i]>='0' && parse[i]<='9') i++;
2100 if(tmp >= 70){
2101 /* long date */
2102 month = day - 1;
2103 day = year;
2104 year = tmp;
2107 else if(tmp<0) break;
2108 else if(tmp<70) {
2109 /* Day */
2110 if(set_day) break;
2111 set_day = TRUE;
2112 day = tmp;
2114 else {
2115 /* Year */
2116 if(set_year) break;
2117 set_year = TRUE;
2118 year = tmp;
2121 else if(parse[i]=='+' || parse[i]=='-') {
2122 /* Timezone offset */
2123 BOOL positive = TRUE;
2125 if(set_offset && set_hour_adjust) break;
2126 set_offset = TRUE;
2127 set_hour_adjust = FALSE;
2129 if(parse[i] == '-') positive = FALSE;
2131 i++;
2132 while(isspaceW(parse[i])) i++;
2133 if(parse[i]<'0' || parse[i]>'9') break;
2134 offset = atoiW(&parse[i]);
2135 while(parse[i]>='0' && parse[i]<='9') i++;
2137 if(offset<24) offset *= 60;
2138 else offset = (offset/100)*60 + offset%100;
2140 if(positive) offset = -offset;
2143 else {
2144 if(parse[i]<'A' || parse[i]>'Z') break;
2145 else if(parse[i]=='B' && (parse[i+1]=='C' ||
2146 (parse[i+1]=='.' && parse[i+2]=='C'))) {
2147 /* AD/BC */
2148 if(set_era) break;
2149 set_era = TRUE;
2150 ad = FALSE;
2152 i++;
2153 if(parse[i] == '.') i++;
2154 i++;
2155 if(parse[i] == '.') i++;
2157 else if(parse[i]=='A' && (parse[i+1]=='D' ||
2158 (parse[i+1]=='.' && parse[i+2]=='D'))) {
2159 /* AD/BC */
2160 if(set_era) break;
2161 set_era = TRUE;
2163 i++;
2164 if(parse[i] == '.') i++;
2165 i++;
2166 if(parse[i] == '.') i++;
2168 else if(parse[i+1]<'A' || parse[i+1]>'Z') {
2169 /* Timezone */
2170 if(set_offset) break;
2171 set_offset = TRUE;
2173 if(parse[i] <= 'I') hour_adjust = parse[i]-'A'+2;
2174 else if(parse[i] == 'J') break;
2175 else if(parse[i] <= 'M') hour_adjust = parse[i]-'K'+11;
2176 else if(parse[i] <= 'Y') hour_adjust = parse[i]-'N';
2177 else hour_adjust = 1;
2179 i++;
2180 if(parse[i] == '.') i++;
2182 else if(parse[i]=='A' && parse[i+1]=='M') {
2183 /* AM/PM */
2184 if(set_am) break;
2185 set_am = TRUE;
2186 am = TRUE;
2187 i += 2;
2189 else if(parse[i]=='P' && parse[i+1]=='M') {
2190 /* AM/PM */
2191 if(set_am) break;
2192 set_am = TRUE;
2193 am = FALSE;
2194 i += 2;
2196 else if((parse[i]=='U' && parse[i+1]=='T' && parse[i+2]=='C')
2197 || (parse[i]=='G' && parse[i+1]=='M' && parse[i+2]=='T')) {
2198 /* Timezone */
2199 if(set_offset) break;
2200 set_offset = TRUE;
2201 set_hour_adjust = FALSE;
2203 i += 3;
2205 else {
2206 /* Month or garbage */
2207 unsigned int j;
2209 for(size=i; parse[size]>='A' && parse[size]<='Z'; size++);
2210 size -= i;
2212 for(j=0; j<sizeof(string_ids)/sizeof(DWORD); j++)
2213 if(!strncmpiW(&parse[i], strings[j], size)) break;
2215 if(j < 12) {
2216 if(set_month) break;
2217 set_month = TRUE;
2218 month = 11-j;
2220 else if(j == sizeof(string_ids)/sizeof(DWORD)) break;
2222 i += size;
2227 if(i == parse_len && set_year && set_month && set_day && (!set_am || hour<13)) {
2228 if(set_am) {
2229 if(hour == 12) hour = 0;
2230 if(!am) hour += 12;
2233 if(!ad) year = -year+1;
2234 else if(year<100) year += 1900;
2236 *ret = time_clip(make_date(make_day(year, month, day),
2237 make_time(hour+hour_adjust, min, sec, ms)) + offset*MS_PER_MINUTE);
2239 if(set_hour_adjust)
2240 *ret = utc(*ret, &di);
2241 }else {
2242 *ret = NAN;
2245 for(i=0; i<sizeof(string_ids)/sizeof(DWORD); i++)
2246 heap_free(strings[i]);
2247 heap_free(parse);
2249 return S_OK;
2252 static HRESULT DateConstr_parse(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2253 jsval_t *r)
2255 jsstr_t *parse_str;
2256 double n;
2257 HRESULT hres;
2259 TRACE("\n");
2261 if(!argc) {
2262 if(r)
2263 *r = jsval_number(NAN);
2264 return S_OK;
2267 hres = to_string(ctx, argv[0], &parse_str);
2268 if(FAILED(hres))
2269 return hres;
2271 hres = date_parse(parse_str, &n);
2272 jsstr_release(parse_str);
2273 if(FAILED(hres))
2274 return hres;
2276 *r = jsval_number(n);
2277 return S_OK;
2280 static HRESULT date_utc(script_ctx_t *ctx, unsigned argc, jsval_t *argv, double *ret)
2282 double year, month, vdate, hours, minutes, seconds, ms;
2283 HRESULT hres;
2285 TRACE("\n");
2287 if(argc) {
2288 hres = to_number(ctx, argv[0], &year);
2289 if(FAILED(hres))
2290 return hres;
2291 if(0 <= year && year <= 99)
2292 year += 1900;
2293 }else {
2294 year = 1900;
2297 if(argc>1) {
2298 hres = to_number(ctx, argv[1], &month);
2299 if(FAILED(hres))
2300 return hres;
2301 }else {
2302 month = 0;
2305 if(argc>2) {
2306 hres = to_number(ctx, argv[2], &vdate);
2307 if(FAILED(hres))
2308 return hres;
2309 }else {
2310 vdate = 1;
2313 if(argc>3) {
2314 hres = to_number(ctx, argv[3], &hours);
2315 if(FAILED(hres))
2316 return hres;
2317 }else {
2318 hours = 0;
2321 if(argc>4) {
2322 hres = to_number(ctx, argv[4], &minutes);
2323 if(FAILED(hres))
2324 return hres;
2325 }else {
2326 minutes = 0;
2329 if(argc>5) {
2330 hres = to_number(ctx, argv[5], &seconds);
2331 if(FAILED(hres))
2332 return hres;
2333 }else {
2334 seconds = 0;
2337 if(argc>6) {
2338 hres = to_number(ctx, argv[6], &ms);
2339 if(FAILED(hres))
2340 return hres;
2341 } else {
2342 ms = 0;
2345 *ret = time_clip(make_date(make_day(year, month, vdate),
2346 make_time(hours, minutes,seconds, ms)));
2347 return S_OK;
2350 static HRESULT DateConstr_UTC(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2351 jsval_t *r)
2353 double n;
2354 HRESULT hres;
2356 TRACE("\n");
2358 hres = date_utc(ctx, argc, argv, &n);
2359 if(SUCCEEDED(hres) && r)
2360 *r = jsval_number(n);
2361 return hres;
2364 static HRESULT DateConstr_value(script_ctx_t *ctx, vdisp_t *jsthis, WORD flags, unsigned argc, jsval_t *argv,
2365 jsval_t *r)
2367 jsdisp_t *date;
2368 HRESULT hres;
2370 TRACE("\n");
2372 switch(flags) {
2373 case DISPATCH_CONSTRUCT:
2374 switch(argc) {
2375 /* ECMA-262 3rd Edition 15.9.3.3 */
2376 case 0: {
2377 FILETIME time;
2378 LONGLONG lltime;
2380 GetSystemTimeAsFileTime(&time);
2381 lltime = ((LONGLONG)time.dwHighDateTime<<32)
2382 + time.dwLowDateTime;
2384 hres = create_date(ctx, NULL, lltime/10000-TIME_EPOCH, &date);
2385 if(FAILED(hres))
2386 return hres;
2387 break;
2390 /* ECMA-262 3rd Edition 15.9.3.2 */
2391 case 1: {
2392 jsval_t prim;
2393 double n;
2395 hres = to_primitive(ctx, argv[0], &prim, NO_HINT);
2396 if(FAILED(hres))
2397 return hres;
2399 if(is_string(prim))
2400 hres = date_parse(get_string(prim), &n);
2401 else
2402 hres = to_number(ctx, prim, &n);
2404 jsval_release(prim);
2405 if(FAILED(hres))
2406 return hres;
2408 hres = create_date(ctx, NULL, time_clip(n), &date);
2409 if(FAILED(hres))
2410 return hres;
2411 break;
2414 /* ECMA-262 3rd Edition 15.9.3.1 */
2415 default: {
2416 double ret_date;
2417 DateInstance *di;
2419 hres = date_utc(ctx, argc, argv, &ret_date);
2420 if(FAILED(hres))
2421 return hres;
2423 hres = create_date(ctx, NULL, ret_date, &date);
2424 if(FAILED(hres))
2425 return hres;
2427 di = date_from_jsdisp(date);
2428 di->time = utc(di->time, di);
2432 *r = jsval_obj(date);
2433 return S_OK;
2435 case INVOKE_FUNC: {
2436 FILETIME system_time, local_time;
2437 LONGLONG lltime;
2439 GetSystemTimeAsFileTime(&system_time);
2440 FileTimeToLocalFileTime(&system_time, &local_time);
2441 lltime = ((LONGLONG)local_time.dwHighDateTime<<32)
2442 + local_time.dwLowDateTime;
2444 return date_to_string(lltime/10000-TIME_EPOCH, FALSE, 0, r);
2447 default:
2448 FIXME("unimplemented flags %x\n", flags);
2449 return E_NOTIMPL;
2452 return S_OK;
2455 static const builtin_prop_t DateConstr_props[] = {
2456 {UTCW, DateConstr_UTC, PROPF_METHOD},
2457 {parseW, DateConstr_parse, PROPF_METHOD}
2460 static const builtin_info_t DateConstr_info = {
2461 JSCLASS_FUNCTION,
2462 DEFAULT_FUNCTION_VALUE,
2463 sizeof(DateConstr_props)/sizeof(*DateConstr_props),
2464 DateConstr_props,
2465 NULL,
2466 NULL
2469 HRESULT create_date_constr(script_ctx_t *ctx, jsdisp_t *object_prototype, jsdisp_t **ret)
2471 jsdisp_t *date;
2472 HRESULT hres;
2474 static const WCHAR DateW[] = {'D','a','t','e',0};
2476 hres = create_date(ctx, object_prototype, 0.0, &date);
2477 if(FAILED(hres))
2478 return hres;
2480 hres = create_builtin_constructor(ctx, DateConstr_value, DateW, &DateConstr_info,
2481 PROPF_CONSTR|7, date, ret);
2483 jsdisp_release(date);
2484 return hres;