jscript: Added Date_getUTCMinutes and Date_getMinutes implementation.
[wine] / dlls / jscript / date.c
1 /*
2  * Copyright 2008 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <limits.h>
20 #include <math.h>
21
22 #include "jscript.h"
23
24 #include "wine/debug.h"
25
26 WINE_DEFAULT_DEBUG_CHANNEL(jscript);
27
28 /* 1601 to 1970 is 369 years plus 89 leap days */
29 #define TIME_EPOCH  ((ULONGLONG)(369 * 365 + 89) * 86400 * 1000)
30
31 typedef struct {
32     DispatchEx dispex;
33
34     /* ECMA-262 3rd Edition    15.9.1.1 */
35     DOUBLE time;
36
37     LONG bias;
38 } DateInstance;
39
40 static const WCHAR toStringW[] = {'t','o','S','t','r','i','n','g',0};
41 static const WCHAR toLocaleStringW[] = {'t','o','L','o','c','a','l','e','S','t','r','i','n','g',0};
42 static const WCHAR hasOwnPropertyW[] = {'h','a','s','O','w','n','P','r','o','p','e','r','t','y',0};
43 static const WCHAR propertyIsEnumerableW[] =
44     {'p','r','o','p','e','r','t','y','I','s','E','n','u','m','e','r','a','b','l','e',0};
45 static const WCHAR isPrototypeOfW[] = {'i','s','P','r','o','t','o','t','y','p','e','O','f',0};
46 static const WCHAR valueOfW[] = {'v','a','l','u','e','O','f',0};
47 static const WCHAR toUTCStringW[] = {'t','o','U','T','C','S','t','r','i','n','g',0};
48 static const WCHAR toDateStringW[] = {'t','o','D','a','t','e','S','t','r','i','n','g',0};
49 static const WCHAR toTimeStringW[] = {'t','o','T','i','m','e','S','t','r','i','n','g',0};
50 static const WCHAR toLocaleDateStringW[] = {'t','o','L','o','c','a','l','e','D','a','t','e','S','t','r','i','n','g',0};
51 static const WCHAR toLocaleTimeStringW[] = {'t','o','L','o','c','a','l','e','T','i','m','e','S','t','r','i','n','g',0};
52 static const WCHAR getTimeW[] = {'g','e','t','T','i','m','e',0};
53 static const WCHAR getFullYearW[] = {'g','e','t','F','u','l','l','Y','e','a','r',0};
54 static const WCHAR getUTCFullYearW[] = {'g','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
55 static const WCHAR getMonthW[] = {'g','e','t','M','o','n','t','h',0};
56 static const WCHAR getUTCMonthW[] = {'g','e','t','U','T','C','M','o','n','t','h',0};
57 static const WCHAR getDateW[] = {'g','e','t','D','a','t','e',0};
58 static const WCHAR getUTCDateW[] = {'g','e','t','U','T','C','D','a','t','e',0};
59 static const WCHAR getDayW[] = {'g','e','t','D','a','y',0};
60 static const WCHAR getUTCDayW[] = {'g','e','t','U','T','C','D','a','y',0};
61 static const WCHAR getHoursW[] = {'g','e','t','H','o','u','r','s',0};
62 static const WCHAR getUTCHoursW[] = {'g','e','t','U','T','C','H','o','u','r','s',0};
63 static const WCHAR getMinutesW[] = {'g','e','t','M','i','n','u','t','e','s',0};
64 static const WCHAR getUTCMinutesW[] = {'g','e','t','U','T','C','M','i','n','u','t','e','s',0};
65 static const WCHAR getSecondsW[] = {'g','e','t','S','e','c','o','n','d','s',0};
66 static const WCHAR getUTCSecondsW[] = {'g','e','t','U','T','C','S','e','c','o','n','d','s',0};
67 static const WCHAR getMilisecondsW[] = {'g','e','t','M','i','l','i','s','e','c','o','n','d','s',0};
68 static const WCHAR getUTCMilisecondsW[] = {'g','e','t','U','T','C','M','i','l','i','s','e','c','o','n','d','s',0};
69 static const WCHAR getTimezoneOffsetW[] = {'g','e','t','T','i','m','e','z','o','n','e','O','f','f','s','e','t',0};
70 static const WCHAR setTimeW[] = {'s','e','t','T','i','m','e',0};
71 static const WCHAR setMilisecondsW[] = {'s','e','t','M','i','l','i','s','e','c','o','n','d','s',0};
72 static const WCHAR setUTCMilisecondsW[] = {'s','e','t','U','T','C','M','i','l','i','s','e','c','o','n','d','s',0};
73 static const WCHAR setSecondsW[] = {'s','e','t','S','e','c','o','n','d','s',0};
74 static const WCHAR setUTCSecondsW[] = {'s','e','t','U','T','C','S','e','c','o','n','d','s',0};
75 static const WCHAR setMinutesW[] = {'s','e','t','M','i','n','u','t','e','s',0};
76 static const WCHAR setUTCMinutesW[] = {'s','e','t','U','T','C','M','i','n','u','t','e','s',0};
77 static const WCHAR setHoursW[] = {'s','e','t','H','o','u','r','s',0};
78 static const WCHAR setUTCHoursW[] = {'s','e','t','H','o','u','r','s',0};
79 static const WCHAR setDateW[] = {'s','e','t','D','a','t','e',0};
80 static const WCHAR setUTCDateW[] = {'s','e','t','U','T','C','D','a','t','e',0};
81 static const WCHAR setMonthW[] = {'s','e','t','M','o','n','t','h',0};
82 static const WCHAR setUTCMonthW[] = {'s','e','t','U','T','C','M','o','n','t','h',0};
83 static const WCHAR setFullYearW[] = {'s','e','t','F','u','l','l','Y','e','a','r',0};
84 static const WCHAR setUTCFullYearW[] = {'s','e','t','U','T','C','F','u','l','l','Y','e','a','r',0};
85
86 /*ECMA-262 3th Edition    15.9.1.2 */
87 #define MS_PER_DAY 86400000
88 #define MS_PER_HOUR 3600000
89 #define MS_PER_MINUTE 60000
90
91 /* ECMA-262 3th Edition    15.9.1.2 */
92 static inline DOUBLE day(DOUBLE time)
93 {
94     return floor(time / MS_PER_DAY);
95 }
96
97 /* ECMA-262 3th Edition    15.9.1.3 */
98 static inline DOUBLE days_in_year(DOUBLE year)
99 {
100     int y;
101
102     if(year != (int)year)
103         return ret_nan();
104
105     y = year;
106     if(y%4 != 0) return 365;
107     if(y%100 != 0) return 366;
108     if(y%400 != 0) return 365;
109     return 366;
110 }
111
112 /* ECMA-262 3th Edition    15.9.1.3 */
113 static inline DOUBLE day_from_year(DOUBLE year)
114 {
115     int y;
116
117     if(year != (int)year)
118         return ret_nan();
119
120     y = year;
121     return 365*(y-1970) + floor((y-1969)/4)
122         - floor((y-1901)/100) + floor((y-1601)/400);
123 }
124
125 /* ECMA-262 3th Edition    15.9.1.3 */
126 static inline DOUBLE time_from_year(DOUBLE year)
127 {
128     return MS_PER_DAY*day_from_year(year);
129 }
130
131 /* ECMA-262 3th Edition    15.9.1.3 */
132 static inline DOUBLE year_from_time(DOUBLE time)
133 {
134     int y;
135
136     if(isnan(time))
137         return ret_nan();
138
139     y = 1970 + time/365.25/MS_PER_DAY;
140
141     if(time_from_year(y) > time)
142         while(time_from_year(y) > time) y--;
143     else
144         while(time_from_year(y+1)<=time) y++;
145
146     return y;
147 }
148
149 /* ECMA-262 3th Edition    15.9.1.3 */
150 static inline int in_leap_year(DOUBLE time)
151 {
152     if(days_in_year(year_from_time(time))==366)
153         return 1;
154     return 0;
155 }
156
157 /* ECMA-262 3th Edition    15.9.1.4 */
158 static inline int day_within_year(DOUBLE time)
159 {
160     return day(time) - day_from_year(year_from_time(time));
161 }
162
163 /* ECMA-262 3th Edition    15.9.1.4 */
164 static inline DOUBLE month_from_time(DOUBLE time)
165 {
166     int ily = in_leap_year(time);
167     int dwy = day_within_year(time);
168
169     if(isnan(time))
170         return ret_nan();
171
172     if(0<=dwy && dwy<31) return 0;
173     if(dwy < 59+ily) return 1;
174     if(dwy < 90+ily) return 2;
175     if(dwy < 120+ily) return 3;
176     if(dwy < 151+ily) return 4;
177     if(dwy < 181+ily) return 5;
178     if(dwy < 212+ily) return 6;
179     if(dwy < 243+ily) return 7;
180     if(dwy < 273+ily) return 8;
181     if(dwy < 304+ily) return  9;
182     if(dwy < 334+ily) return  10;
183     return  11;
184 }
185
186 /* ECMA-262 3th Edition    15.9.1.5 */
187 static inline DOUBLE date_from_time(DOUBLE time)
188 {
189     int dwy = day_within_year(time);
190     int ily = in_leap_year(time);
191     int mft = month_from_time(time);
192
193     if(isnan(time))
194         return ret_nan();
195
196     if(mft==0) return dwy+1;
197     if(mft==1) return dwy-30;
198     if(mft==2) return dwy-58-ily;
199     if(mft==3) return dwy-89-ily;
200     if(mft==4) return dwy-119-ily;
201     if(mft==5) return dwy-150-ily;
202     if(mft==6) return dwy-180-ily;
203     if(mft==7) return dwy-211-ily;
204     if(mft==8) return dwy-242-ily;
205     if(mft==9) return dwy-272-ily;
206     if(mft==10) return dwy-303-ily;
207     return dwy-333-ily;
208 }
209
210 /* ECMA-262 3th Edition    15.9.1.6 */
211 static inline DOUBLE week_day(DOUBLE time)
212 {
213     DOUBLE ret;
214
215     if(isnan(time))
216         return ret_nan();
217
218     ret = fmod(day(time)+4, 7);
219     if(ret<0) ret += 7;
220
221     return ret;
222 }
223
224 /* ECMA-262 3th Edition    15.9.1.10 */
225 static inline DOUBLE hour_from_time(DOUBLE time)
226 {
227     DOUBLE ret;
228
229     if(isnan(time))
230         return ret_nan();
231
232     ret = fmod(floor(time/MS_PER_HOUR), 24);
233     if(ret<0) ret += 24;
234
235     return ret;
236 }
237
238 /* ECMA-262 3th Edition    15.9.1.10 */
239 static inline DOUBLE min_from_time(DOUBLE time)
240 {
241     DOUBLE ret;
242
243     if(isnan(time))
244         return ret_nan();
245
246     ret = fmod(floor(time/MS_PER_MINUTE), 60);
247     if(ret<0) ret += 60;
248
249     return ret;
250 }
251
252 /* ECMA-262 3rd Edition    15.9.1.14 */
253 static inline DOUBLE time_clip(DOUBLE time)
254 {
255     if(8.64e15 < time || time < -8.64e15) {
256         return ret_nan();
257     }
258
259     return floor(time);
260 }
261
262 static HRESULT Date_toString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
263         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
264 {
265     FIXME("\n");
266     return E_NOTIMPL;
267 }
268
269 static HRESULT Date_toLocaleString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
270         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
271 {
272     FIXME("\n");
273     return E_NOTIMPL;
274 }
275
276 static HRESULT Date_hasOwnProperty(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
277         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
278 {
279     FIXME("\n");
280     return E_NOTIMPL;
281 }
282
283 static HRESULT Date_propertyIsEnumerable(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
284         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
285 {
286     FIXME("\n");
287     return E_NOTIMPL;
288 }
289
290 static HRESULT Date_isPrototypeOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
291         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
292 {
293     FIXME("\n");
294     return E_NOTIMPL;
295 }
296
297 static HRESULT Date_valueOf(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
298         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
299 {
300     FIXME("\n");
301     return E_NOTIMPL;
302 }
303
304 static HRESULT Date_toUTCString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
305         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
306 {
307     FIXME("\n");
308     return E_NOTIMPL;
309 }
310
311 static HRESULT Date_toDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
312         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
313 {
314     FIXME("\n");
315     return E_NOTIMPL;
316 }
317
318 static HRESULT Date_toTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
319         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
320 {
321     FIXME("\n");
322     return E_NOTIMPL;
323 }
324
325 static HRESULT Date_toLocaleDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
326         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
327 {
328     FIXME("\n");
329     return E_NOTIMPL;
330 }
331
332 static HRESULT Date_toLocaleTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
333         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
334 {
335     FIXME("\n");
336     return E_NOTIMPL;
337 }
338
339 /* ECMA-262 3rd Edition    15.9.5.9 */
340 static HRESULT Date_getTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
341         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
342 {
343     TRACE("\n");
344
345     if(!is_class(dispex, JSCLASS_DATE)) {
346         FIXME("throw TypeError\n");
347         return E_FAIL;
348     }
349
350     if(retv) {
351         DateInstance *date = (DateInstance*)dispex;
352         num_set_val(retv, date->time);
353     }
354     return S_OK;
355 }
356
357 /* ECMA-262 3th Edition    15.9.1.3 */
358 static HRESULT Date_getFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
359         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
360 {
361     TRACE("\n");
362
363     if(!is_class(dispex, JSCLASS_DATE)) {
364         FIXME("throw TypeError\n");
365         return E_FAIL;
366     }
367
368     if(retv) {
369         DateInstance *date = (DateInstance*)dispex;
370         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
371
372         num_set_val(retv, year_from_time(time));
373     }
374     return S_OK;
375 }
376
377 /* ECMA-262 3th Edition    15.9.1.3 */
378 static HRESULT Date_getUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
379         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
380 {
381     TRACE("\n");
382
383     if(!is_class(dispex, JSCLASS_DATE)) {
384         FIXME("throw TypeError\n");
385         return E_FAIL;
386     }
387
388     if(retv) {
389         DateInstance *date = (DateInstance*)dispex;
390         num_set_val(retv, year_from_time(date->time));
391     }
392     return S_OK;
393 }
394
395 /* ECMA-262 3th Edition    15.9.1.4 */
396 static HRESULT Date_getMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
397         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
398 {
399     TRACE("\n");
400
401     if(!is_class(dispex, JSCLASS_DATE)) {
402         FIXME("throw TypeError\n");
403         return E_FAIL;
404     }
405
406     if(retv) {
407         DateInstance *date = (DateInstance*)dispex;
408         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
409
410         num_set_val(retv, month_from_time(time));
411     }
412     return S_OK;
413 }
414
415 /* ECMA-262 3th Edition    15.9.1.4 */
416 static HRESULT Date_getUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
417         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
418 {
419     TRACE("\n");
420
421     if(!is_class(dispex, JSCLASS_DATE)) {
422         FIXME("throw TypeError\n");
423         return E_FAIL;
424     }
425
426     if(retv) {
427         DateInstance *date = (DateInstance*)dispex;
428         num_set_val(retv, month_from_time(date->time));
429     }
430     return S_OK;
431 }
432
433 /* ECMA-262 3th Edition    15.9.1.5 */
434 static HRESULT Date_getDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
435         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
436 {
437     TRACE("\n");
438
439     if(!is_class(dispex, JSCLASS_DATE)) {
440         FIXME("throw TypeError\n");
441         return E_FAIL;
442     }
443
444     if(retv) {
445         DateInstance *date = (DateInstance*)dispex;
446         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
447
448         num_set_val(retv, date_from_time(time));
449     }
450     return S_OK;
451 }
452
453 /* ECMA-262 3th Edition    15.9.1.5 */
454 static HRESULT Date_getUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
455         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
456 {
457     TRACE("\n");
458
459     if(!is_class(dispex, JSCLASS_DATE)) {
460         FIXME("throw TypeError\n");
461         return E_FAIL;
462     }
463
464     if(retv) {
465         DateInstance *date = (DateInstance*)dispex;
466         num_set_val(retv, date_from_time(date->time));
467     }
468     return S_OK;
469 }
470
471 /* ECMA-262 3th Edition    15.9.1.6 */
472 static HRESULT Date_getDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
473         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
474 {
475     TRACE("\n");
476
477     if(!is_class(dispex, JSCLASS_DATE)) {
478         FIXME("throw TypeError\n");
479         return E_FAIL;
480     }
481
482     if(retv) {
483         DateInstance *date = (DateInstance*)dispex;
484         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
485
486         num_set_val(retv, week_day(time));
487     }
488     return S_OK;
489 }
490
491 /* ECMA-262 3th Edition    15.9.1.6 */
492 static HRESULT Date_getUTCDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
493         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
494 {
495     TRACE("\n");
496
497     if(!is_class(dispex, JSCLASS_DATE)) {
498         FIXME("throw TypeError\n");
499         return E_FAIL;
500     }
501
502     if(retv) {
503         DateInstance *date = (DateInstance*)dispex;
504         num_set_val(retv, week_day(date->time));
505     }
506     return S_OK;
507 }
508
509 /* ECMA-262 3th Edition    15.9.1.10 */
510 static HRESULT Date_getHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
511         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
512 {
513     TRACE("\n");
514
515     if(!is_class(dispex, JSCLASS_DATE)) {
516         FIXME("throw TypeError\n");
517         return E_FAIL;
518     }
519
520     if(retv) {
521         DateInstance *date = (DateInstance*)dispex;
522         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
523
524         num_set_val(retv, hour_from_time(time));
525     }
526     return S_OK;
527 }
528
529 /* ECMA-262 3th Edition    15.9.1.10 */
530 static HRESULT Date_getUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
531         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
532 {
533     TRACE("\n");
534
535     if(!is_class(dispex, JSCLASS_DATE)) {
536         FIXME("throw TypeError\n");
537         return E_FAIL;
538     }
539
540     if(retv) {
541         DateInstance *date = (DateInstance*)dispex;
542         num_set_val(retv, hour_from_time(date->time));
543     }
544     return S_OK;
545 }
546
547 /* ECMA-262 3th Edition    15.9.1.10 */
548 static HRESULT Date_getMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
549         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
550 {
551     TRACE("\n");
552
553     if(!is_class(dispex, JSCLASS_DATE)) {
554         FIXME("throw TypeError\n");
555         return E_FAIL;
556     }
557
558     if(retv) {
559         DateInstance *date = (DateInstance*)dispex;
560         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
561
562         num_set_val(retv, min_from_time(time));
563     }
564     return S_OK;
565 }
566
567 /* ECMA-262 3th Edition    15.9.1.10 */
568 static HRESULT Date_getUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
569         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
570 {
571     TRACE("\n");
572
573     if(!is_class(dispex, JSCLASS_DATE)) {
574         FIXME("throw TypeError\n");
575         return E_FAIL;
576     }
577
578     if(retv) {
579         DateInstance *date = (DateInstance*)dispex;
580         num_set_val(retv, min_from_time(date->time));
581     }
582     return S_OK;
583 }
584
585 static HRESULT Date_getSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
586         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
587 {
588     FIXME("\n");
589     return E_NOTIMPL;
590 }
591
592 static HRESULT Date_getUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
593         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
594 {
595     FIXME("\n");
596     return E_NOTIMPL;
597 }
598
599 static HRESULT Date_getMiliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
600         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
601 {
602     FIXME("\n");
603     return E_NOTIMPL;
604 }
605
606 static HRESULT Date_getUTCMiliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
607         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
608 {
609     FIXME("\n");
610     return E_NOTIMPL;
611 }
612
613 static HRESULT Date_getTimezoneOffset(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
614         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
615 {
616     FIXME("\n");
617     return E_NOTIMPL;
618 }
619
620 static HRESULT Date_setTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
621         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
622 {
623     VARIANT v;
624     HRESULT hres;
625     DateInstance *date;
626
627     TRACE("\n");
628
629     if(!is_class(dispex, JSCLASS_DATE)) {
630         FIXME("throw TypeError\n");
631         return E_FAIL;
632     }
633
634     if(!arg_cnt(dp)) {
635         if(retv) num_set_nan(retv);
636         return S_OK;
637     }
638
639     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
640     if(FAILED(hres))
641         return hres;
642
643     date = (DateInstance*)dispex;
644     date->time = time_clip(num_val(&v));
645
646     if(retv)
647         num_set_val(retv, date->time);
648
649     return S_OK;
650 }
651
652 static HRESULT Date_setMiliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
653         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
654 {
655     FIXME("\n");
656     return E_NOTIMPL;
657 }
658
659 static HRESULT Date_setUTCMiliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
660         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
661 {
662     FIXME("\n");
663     return E_NOTIMPL;
664 }
665
666 static HRESULT Date_setSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
667         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
668 {
669     FIXME("\n");
670     return E_NOTIMPL;
671 }
672
673 static HRESULT Date_setUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
674         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
675 {
676     FIXME("\n");
677     return E_NOTIMPL;
678 }
679
680 static HRESULT Date_setMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
681         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
682 {
683     FIXME("\n");
684     return E_NOTIMPL;
685 }
686
687 static HRESULT Date_setUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
688         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
689 {
690     FIXME("\n");
691     return E_NOTIMPL;
692 }
693
694 static HRESULT Date_setHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
695         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
696 {
697     FIXME("\n");
698     return E_NOTIMPL;
699 }
700
701 static HRESULT Date_setUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
702         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
703 {
704     FIXME("\n");
705     return E_NOTIMPL;
706 }
707
708 static HRESULT Date_setDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
709         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
710 {
711     FIXME("\n");
712     return E_NOTIMPL;
713 }
714
715 static HRESULT Date_setUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
716         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
717 {
718     FIXME("\n");
719     return E_NOTIMPL;
720 }
721
722 static HRESULT Date_setMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
723         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
724 {
725     FIXME("\n");
726     return E_NOTIMPL;
727 }
728
729 static HRESULT Date_setUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
730         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
731 {
732     FIXME("\n");
733     return E_NOTIMPL;
734 }
735
736 static HRESULT Date_setFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
737         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
738 {
739     FIXME("\n");
740     return E_NOTIMPL;
741 }
742
743 static HRESULT Date_setUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
744         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
745 {
746     FIXME("\n");
747     return E_NOTIMPL;
748 }
749
750 static HRESULT Date_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
751         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
752 {
753     FIXME("\n");
754     return E_NOTIMPL;
755 }
756
757 static const builtin_prop_t Date_props[] = {
758     {getDateW,               Date_getDate,               PROPF_METHOD},
759     {getDayW,                Date_getDay,                PROPF_METHOD},
760     {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
761     {getHoursW,              Date_getHours,              PROPF_METHOD},
762     {getMilisecondsW,        Date_getMiliseconds,        PROPF_METHOD},
763     {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
764     {getMonthW,              Date_getMonth,              PROPF_METHOD},
765     {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
766     {getTimeW,               Date_getTime,               PROPF_METHOD},
767     {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
768     {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
769     {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
770     {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
771     {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
772     {getUTCMilisecondsW,     Date_getUTCMiliseconds,     PROPF_METHOD},
773     {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
774     {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
775     {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
776     {hasOwnPropertyW,        Date_hasOwnProperty,        PROPF_METHOD},
777     {isPrototypeOfW,         Date_isPrototypeOf,         PROPF_METHOD},
778     {propertyIsEnumerableW,  Date_propertyIsEnumerable,  PROPF_METHOD},
779     {setDateW,               Date_setDate,               PROPF_METHOD},
780     {setFullYearW,           Date_setFullYear,           PROPF_METHOD},
781     {setHoursW,              Date_setHours,              PROPF_METHOD},
782     {setMilisecondsW,        Date_setMiliseconds,        PROPF_METHOD},
783     {setMinutesW,            Date_setMinutes,            PROPF_METHOD},
784     {setMonthW,              Date_setMonth,              PROPF_METHOD},
785     {setSecondsW,            Date_setSeconds,            PROPF_METHOD},
786     {setTimeW,               Date_setTime,               PROPF_METHOD},
787     {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD},
788     {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD},
789     {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD},
790     {setUTCMilisecondsW,     Date_setUTCMiliseconds,     PROPF_METHOD},
791     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD},
792     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD},
793     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD},
794     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
795     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
796     {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
797     {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
798     {toStringW,              Date_toString,              PROPF_METHOD},
799     {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
800     {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
801     {valueOfW,               Date_valueOf,               PROPF_METHOD},
802 };
803
804 static const builtin_info_t Date_info = {
805     JSCLASS_DATE,
806     {NULL, Date_value, 0},
807     sizeof(Date_props)/sizeof(*Date_props),
808     Date_props,
809     NULL,
810     NULL
811 };
812
813 static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, DispatchEx **ret)
814 {
815     DateInstance *date;
816     HRESULT hres;
817     TIME_ZONE_INFORMATION tzi;
818
819     GetTimeZoneInformation(&tzi);
820
821     date = heap_alloc_zero(sizeof(DateInstance));
822     if(!date)
823         return E_OUTOFMEMORY;
824
825     if(use_constr)
826         hres = init_dispex_from_constr(&date->dispex, ctx, &Date_info, ctx->date_constr);
827     else
828         hres = init_dispex(&date->dispex, ctx, &Date_info, NULL);
829     if(FAILED(hres)) {
830         heap_free(date);
831         return hres;
832     }
833
834     date->time = time;
835     date->bias = tzi.Bias;
836
837     *ret = &date->dispex;
838     return S_OK;
839 }
840
841 static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
842         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
843 {
844     DispatchEx *date;
845     HRESULT hres;
846
847     TRACE("\n");
848
849     switch(flags) {
850     case DISPATCH_CONSTRUCT:
851         switch(arg_cnt(dp)) {
852         /* ECMA-262 3rd Edition    15.9.3.3 */
853         case 0: {
854             FILETIME time;
855             LONGLONG lltime;
856
857             GetSystemTimeAsFileTime(&time);
858             lltime = ((LONGLONG)time.dwHighDateTime<<32)
859                 + time.dwLowDateTime;
860
861             hres = create_date(dispex->ctx, TRUE, lltime/10000-TIME_EPOCH, &date);
862             if(FAILED(hres))
863                 return hres;
864             break;
865         }
866
867         /* ECMA-262 3rd Edition    15.9.3.2 */
868         case 1: {
869             VARIANT prim, num;
870
871             hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim);
872             if(FAILED(hres))
873                 return hres;
874
875             if(V_VT(&prim) == VT_BSTR) {
876                 FIXME("VT_BSTR not supported\n");
877                 return E_NOTIMPL;
878             }
879
880             hres = to_number(dispex->ctx, &prim, ei, &num);
881             VariantClear(&prim);
882             if(FAILED(hres))
883                 return hres;
884
885             hres = create_date(dispex->ctx, TRUE, time_clip(num_val(&num)), &date);
886             if(FAILED(hres))
887                 return hres;
888             break;
889         }
890
891         default:
892             FIXME("unimplemented argcnt %d\n", arg_cnt(dp));
893             return E_NOTIMPL;
894         }
895
896         V_VT(retv) = VT_DISPATCH;
897         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(date);
898         return S_OK;
899
900     default:
901         FIXME("unimplemented flags %x\n", flags);
902         return E_NOTIMPL;
903     }
904
905     return S_OK;
906 }
907
908 HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx **ret)
909 {
910     DispatchEx *date;
911     HRESULT hres;
912
913     hres = create_date(ctx, FALSE, 0.0, &date);
914     if(FAILED(hres))
915         return hres;
916
917     hres = create_builtin_function(ctx, DateConstr_value, PROPF_CONSTR, date, ret);
918
919     jsdisp_release(date);
920     return hres;
921 }