jscript: Added Date_setUTCHours and Date_setHours 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 getMillisecondsW[] = {'g','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
68 static const WCHAR getUTCMillisecondsW[] = {'g','e','t','U','T','C','M','i','l','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 setMillisecondsW[] = {'s','e','t','M','i','l','l','i','s','e','c','o','n','d','s',0};
72 static const WCHAR setUTCMillisecondsW[] = {'s','e','t','U','T','C','M','i','l','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','U','T','C','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 3th Edition    15.9.1.10 */
253 static inline DOUBLE sec_from_time(DOUBLE time)
254 {
255     DOUBLE ret;
256
257     if(isnan(time))
258         return ret_nan();
259
260     ret = fmod(floor(time/1000), 60);
261     if(ret<0) ret += 60;
262
263     return ret;
264 }
265
266 /* ECMA-262 3th Edition    15.9.1.10 */
267 static inline DOUBLE ms_from_time(DOUBLE time)
268 {
269     DOUBLE ret;
270
271     if(isnan(time))
272         return ret_nan();
273
274     ret = fmod(time, 1000);
275     if(ret<0) ret += 1000;
276
277     return ret;
278 }
279
280 /* ECMA-262 3rd Edition    15.9.1.14 */
281 static inline DOUBLE time_clip(DOUBLE time)
282 {
283     if(8.64e15 < time || time < -8.64e15) {
284         return ret_nan();
285     }
286
287     return floor(time);
288 }
289
290 static HRESULT Date_toString(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_toLocaleString(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_hasOwnProperty(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_propertyIsEnumerable(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_isPrototypeOf(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_valueOf(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_toUTCString(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 static HRESULT Date_toDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
340         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
341 {
342     FIXME("\n");
343     return E_NOTIMPL;
344 }
345
346 static HRESULT Date_toTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
347         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
348 {
349     FIXME("\n");
350     return E_NOTIMPL;
351 }
352
353 static HRESULT Date_toLocaleDateString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
354         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
355 {
356     FIXME("\n");
357     return E_NOTIMPL;
358 }
359
360 static HRESULT Date_toLocaleTimeString(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
361         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
362 {
363     FIXME("\n");
364     return E_NOTIMPL;
365 }
366
367 /* ECMA-262 3rd Edition    15.9.5.9 */
368 static HRESULT Date_getTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
369         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
370 {
371     TRACE("\n");
372
373     if(!is_class(dispex, JSCLASS_DATE)) {
374         FIXME("throw TypeError\n");
375         return E_FAIL;
376     }
377
378     if(retv) {
379         DateInstance *date = (DateInstance*)dispex;
380         num_set_val(retv, date->time);
381     }
382     return S_OK;
383 }
384
385 /* ECMA-262 3th Edition    15.9.1.3 */
386 static HRESULT Date_getFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
387         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
388 {
389     TRACE("\n");
390
391     if(!is_class(dispex, JSCLASS_DATE)) {
392         FIXME("throw TypeError\n");
393         return E_FAIL;
394     }
395
396     if(retv) {
397         DateInstance *date = (DateInstance*)dispex;
398         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
399
400         num_set_val(retv, year_from_time(time));
401     }
402     return S_OK;
403 }
404
405 /* ECMA-262 3th Edition    15.9.1.3 */
406 static HRESULT Date_getUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
407         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
408 {
409     TRACE("\n");
410
411     if(!is_class(dispex, JSCLASS_DATE)) {
412         FIXME("throw TypeError\n");
413         return E_FAIL;
414     }
415
416     if(retv) {
417         DateInstance *date = (DateInstance*)dispex;
418         num_set_val(retv, year_from_time(date->time));
419     }
420     return S_OK;
421 }
422
423 /* ECMA-262 3th Edition    15.9.1.4 */
424 static HRESULT Date_getMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
425         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
426 {
427     TRACE("\n");
428
429     if(!is_class(dispex, JSCLASS_DATE)) {
430         FIXME("throw TypeError\n");
431         return E_FAIL;
432     }
433
434     if(retv) {
435         DateInstance *date = (DateInstance*)dispex;
436         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
437
438         num_set_val(retv, month_from_time(time));
439     }
440     return S_OK;
441 }
442
443 /* ECMA-262 3th Edition    15.9.1.4 */
444 static HRESULT Date_getUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
445         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
446 {
447     TRACE("\n");
448
449     if(!is_class(dispex, JSCLASS_DATE)) {
450         FIXME("throw TypeError\n");
451         return E_FAIL;
452     }
453
454     if(retv) {
455         DateInstance *date = (DateInstance*)dispex;
456         num_set_val(retv, month_from_time(date->time));
457     }
458     return S_OK;
459 }
460
461 /* ECMA-262 3th Edition    15.9.1.5 */
462 static HRESULT Date_getDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
463         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
464 {
465     TRACE("\n");
466
467     if(!is_class(dispex, JSCLASS_DATE)) {
468         FIXME("throw TypeError\n");
469         return E_FAIL;
470     }
471
472     if(retv) {
473         DateInstance *date = (DateInstance*)dispex;
474         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
475
476         num_set_val(retv, date_from_time(time));
477     }
478     return S_OK;
479 }
480
481 /* ECMA-262 3th Edition    15.9.1.5 */
482 static HRESULT Date_getUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
483         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
484 {
485     TRACE("\n");
486
487     if(!is_class(dispex, JSCLASS_DATE)) {
488         FIXME("throw TypeError\n");
489         return E_FAIL;
490     }
491
492     if(retv) {
493         DateInstance *date = (DateInstance*)dispex;
494         num_set_val(retv, date_from_time(date->time));
495     }
496     return S_OK;
497 }
498
499 /* ECMA-262 3th Edition    15.9.1.6 */
500 static HRESULT Date_getDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
501         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
502 {
503     TRACE("\n");
504
505     if(!is_class(dispex, JSCLASS_DATE)) {
506         FIXME("throw TypeError\n");
507         return E_FAIL;
508     }
509
510     if(retv) {
511         DateInstance *date = (DateInstance*)dispex;
512         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
513
514         num_set_val(retv, week_day(time));
515     }
516     return S_OK;
517 }
518
519 /* ECMA-262 3th Edition    15.9.1.6 */
520 static HRESULT Date_getUTCDay(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
521         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
522 {
523     TRACE("\n");
524
525     if(!is_class(dispex, JSCLASS_DATE)) {
526         FIXME("throw TypeError\n");
527         return E_FAIL;
528     }
529
530     if(retv) {
531         DateInstance *date = (DateInstance*)dispex;
532         num_set_val(retv, week_day(date->time));
533     }
534     return S_OK;
535 }
536
537 /* ECMA-262 3th Edition    15.9.1.10 */
538 static HRESULT Date_getHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
539         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
540 {
541     TRACE("\n");
542
543     if(!is_class(dispex, JSCLASS_DATE)) {
544         FIXME("throw TypeError\n");
545         return E_FAIL;
546     }
547
548     if(retv) {
549         DateInstance *date = (DateInstance*)dispex;
550         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
551
552         num_set_val(retv, hour_from_time(time));
553     }
554     return S_OK;
555 }
556
557 /* ECMA-262 3th Edition    15.9.1.10 */
558 static HRESULT Date_getUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
559         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
560 {
561     TRACE("\n");
562
563     if(!is_class(dispex, JSCLASS_DATE)) {
564         FIXME("throw TypeError\n");
565         return E_FAIL;
566     }
567
568     if(retv) {
569         DateInstance *date = (DateInstance*)dispex;
570         num_set_val(retv, hour_from_time(date->time));
571     }
572     return S_OK;
573 }
574
575 /* ECMA-262 3th Edition    15.9.1.10 */
576 static HRESULT Date_getMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
577         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
578 {
579     TRACE("\n");
580
581     if(!is_class(dispex, JSCLASS_DATE)) {
582         FIXME("throw TypeError\n");
583         return E_FAIL;
584     }
585
586     if(retv) {
587         DateInstance *date = (DateInstance*)dispex;
588         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
589
590         num_set_val(retv, min_from_time(time));
591     }
592     return S_OK;
593 }
594
595 /* ECMA-262 3th Edition    15.9.1.10 */
596 static HRESULT Date_getUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
597         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
598 {
599     TRACE("\n");
600
601     if(!is_class(dispex, JSCLASS_DATE)) {
602         FIXME("throw TypeError\n");
603         return E_FAIL;
604     }
605
606     if(retv) {
607         DateInstance *date = (DateInstance*)dispex;
608         num_set_val(retv, min_from_time(date->time));
609     }
610     return S_OK;
611 }
612
613 /* ECMA-262 3th Edition    15.9.1.10 */
614 static HRESULT Date_getSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
615         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
616 {
617     TRACE("\n");
618
619     if(!is_class(dispex, JSCLASS_DATE)) {
620         FIXME("throw TypeError\n");
621         return E_FAIL;
622     }
623
624     if(retv) {
625         DateInstance *date = (DateInstance*)dispex;
626         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
627
628         num_set_val(retv, sec_from_time(time));
629     }
630     return S_OK;
631 }
632
633 /* ECMA-262 3th Edition    15.9.1.10 */
634 static HRESULT Date_getUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
635         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
636 {
637     TRACE("\n");
638
639     if(!is_class(dispex, JSCLASS_DATE)) {
640         FIXME("throw TypeError\n");
641         return E_FAIL;
642     }
643
644     if(retv) {
645         DateInstance *date = (DateInstance*)dispex;
646         num_set_val(retv, sec_from_time(date->time));
647     }
648     return S_OK;
649 }
650
651 /* ECMA-262 3th Edition    15.9.1.10 */
652 static HRESULT Date_getMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
653         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
654 {
655     TRACE("\n");
656
657     if(!is_class(dispex, JSCLASS_DATE)) {
658         FIXME("throw TypeError\n");
659         return E_FAIL;
660     }
661
662     if(retv) {
663         DateInstance *date = (DateInstance*)dispex;
664         DOUBLE time = date->time - date->bias*MS_PER_MINUTE;
665
666         num_set_val(retv, ms_from_time(time));
667     }
668     return S_OK;
669 }
670
671 /* ECMA-262 3th Edition    15.9.1.10 */
672 static HRESULT Date_getUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
673         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
674 {
675     TRACE("\n");
676
677     if(!is_class(dispex, JSCLASS_DATE)) {
678         FIXME("throw TypeError\n");
679         return E_FAIL;
680     }
681
682     if(retv) {
683         DateInstance *date = (DateInstance*)dispex;
684         num_set_val(retv, ms_from_time(date->time));
685     }
686     return S_OK;
687 }
688
689 static HRESULT Date_getTimezoneOffset(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
690         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
691 {
692     FIXME("\n");
693     return E_NOTIMPL;
694 }
695
696 static HRESULT Date_setTime(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
697         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
698 {
699     VARIANT v;
700     HRESULT hres;
701     DateInstance *date;
702
703     TRACE("\n");
704
705     if(!is_class(dispex, JSCLASS_DATE)) {
706         FIXME("throw TypeError\n");
707         return E_FAIL;
708     }
709
710     if(!arg_cnt(dp)) {
711         FIXME("throw ArgumentNotOptional\n");
712         if(retv) num_set_nan(retv);
713         return S_OK;
714     }
715
716     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
717     if(FAILED(hres))
718         return hres;
719
720     date = (DateInstance*)dispex;
721     date->time = time_clip(num_val(&v));
722
723     if(retv)
724         num_set_val(retv, date->time);
725
726     return S_OK;
727 }
728
729 static HRESULT Date_setMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
730         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
731 {
732     VARIANT v;
733     HRESULT hres;
734     DateInstance *date;
735
736     TRACE("\n");
737
738     if(!is_class(dispex, JSCLASS_DATE)) {
739         FIXME("throw TypeError\n");
740         return E_FAIL;
741     }
742
743     if(!arg_cnt(dp)) {
744         FIXME("throw ArgumentNotOptional\n");
745         if(retv) num_set_nan(retv);
746         return S_OK;
747     }
748
749     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
750     if(FAILED(hres))
751         return hres;
752
753     date = (DateInstance*)dispex;
754     date->time = time_clip(date->time - ms_from_time(date->time) + num_val(&v));
755
756     if(retv)
757         num_set_val(retv, date->time);
758
759     return S_OK;
760 }
761
762 static HRESULT Date_setUTCMilliseconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
763         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
764 {
765     return Date_setMilliseconds(dispex, lcid, flags, dp, retv, ei, caller);
766 }
767
768 static HRESULT Date_setSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
769         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
770 {
771     VARIANT v;
772     HRESULT hres;
773     DateInstance *date;
774
775     TRACE("\n");
776
777     if(!is_class(dispex, JSCLASS_DATE)) {
778         FIXME("throw TypeError\n");
779         return E_FAIL;
780     }
781
782     if(!arg_cnt(dp)) {
783         FIXME("throw ArgumentNotOptional\n");
784         if(retv) num_set_nan(retv);
785         return S_OK;
786     }
787
788     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
789     if(FAILED(hres))
790         return hres;
791
792     date = (DateInstance*)dispex;
793     date->time = time_clip(date->time - (sec_from_time(date->time) - num_val(&v))*1000.0);
794
795     if(retv)
796         num_set_val(retv, date->time);
797
798     return S_OK;
799 }
800
801 static HRESULT Date_setUTCSeconds(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
802         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
803 {
804     return Date_setSeconds(dispex, lcid, flags, dp, retv, ei, caller);
805 }
806
807 static HRESULT Date_setMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
808         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
809 {
810     VARIANT v;
811     HRESULT hres;
812     DateInstance *date;
813
814     TRACE("\n");
815
816     if(!is_class(dispex, JSCLASS_DATE)) {
817         FIXME("throw TypeError\n");
818         return E_FAIL;
819     }
820
821     if(!arg_cnt(dp)) {
822         FIXME("throw ArgumentNotOptional\n");
823         if(retv) num_set_nan(retv);
824         return S_OK;
825     }
826
827     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
828     if(FAILED(hres))
829         return hres;
830
831     date = (DateInstance*)dispex;
832     date->time = time_clip(date->time - (min_from_time(date->time) - num_val(&v))*MS_PER_MINUTE);
833
834     if(retv)
835         num_set_val(retv, date->time);
836
837     return S_OK;
838 }
839
840 static HRESULT Date_setUTCMinutes(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
841         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
842 {
843     return Date_setMinutes(dispex, lcid, flags, dp, retv, ei, caller);
844 }
845
846 static HRESULT Date_setHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
847         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
848 {
849     VARIANT v;
850     HRESULT hres;
851     DateInstance *date;
852
853     TRACE("\n");
854
855     if(!is_class(dispex, JSCLASS_DATE)) {
856         FIXME("throw TypeError\n");
857         return E_FAIL;
858     }
859
860     if(!arg_cnt(dp)) {
861         FIXME("throw ArgumentNotOptional\n");
862         if(retv) num_set_nan(retv);
863         return S_OK;
864     }
865
866     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
867     if(FAILED(hres))
868         return hres;
869
870     date = (DateInstance*)dispex;
871     date->time = time_clip(date->time
872             - (hour_from_time(date->time - date->bias*MS_PER_MINUTE)
873                 - num_val(&v))*MS_PER_HOUR);
874
875     if(retv)
876         num_set_val(retv, date->time);
877
878     return S_OK;
879 }
880
881 static HRESULT Date_setUTCHours(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
882         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
883 {
884     VARIANT v;
885     HRESULT hres;
886     DateInstance *date;
887
888     TRACE("\n");
889
890     if(!is_class(dispex, JSCLASS_DATE)) {
891         FIXME("throw TypeError\n");
892         return E_FAIL;
893     }
894
895     if(!arg_cnt(dp)) {
896         FIXME("throw ArgumentNotOptional\n");
897         if(retv) num_set_nan(retv);
898         return S_OK;
899     }
900
901     hres = to_number(dispex->ctx, get_arg(dp, 0), ei, &v);
902     if(FAILED(hres))
903         return hres;
904
905     date = (DateInstance*)dispex;
906     date->time = time_clip(date->time
907             - (hour_from_time(date->time) - num_val(&v))*MS_PER_HOUR);
908
909     if(retv)
910         num_set_val(retv, date->time);
911
912     return S_OK;
913 }
914
915 static HRESULT Date_setDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
916         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
917 {
918     FIXME("\n");
919     return E_NOTIMPL;
920 }
921
922 static HRESULT Date_setUTCDate(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
923         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
924 {
925     FIXME("\n");
926     return E_NOTIMPL;
927 }
928
929 static HRESULT Date_setMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
930         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
931 {
932     FIXME("\n");
933     return E_NOTIMPL;
934 }
935
936 static HRESULT Date_setUTCMonth(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
937         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
938 {
939     FIXME("\n");
940     return E_NOTIMPL;
941 }
942
943 static HRESULT Date_setFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
944         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
945 {
946     FIXME("\n");
947     return E_NOTIMPL;
948 }
949
950 static HRESULT Date_setUTCFullYear(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
951         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
952 {
953     FIXME("\n");
954     return E_NOTIMPL;
955 }
956
957 static HRESULT Date_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
958         VARIANT *retv, jsexcept_t *ei, IServiceProvider *caller)
959 {
960     FIXME("\n");
961     return E_NOTIMPL;
962 }
963
964 static const builtin_prop_t Date_props[] = {
965     {getDateW,               Date_getDate,               PROPF_METHOD},
966     {getDayW,                Date_getDay,                PROPF_METHOD},
967     {getFullYearW,           Date_getFullYear,           PROPF_METHOD},
968     {getHoursW,              Date_getHours,              PROPF_METHOD},
969     {getMillisecondsW,       Date_getMilliseconds,       PROPF_METHOD},
970     {getMinutesW,            Date_getMinutes,            PROPF_METHOD},
971     {getMonthW,              Date_getMonth,              PROPF_METHOD},
972     {getSecondsW,            Date_getSeconds,            PROPF_METHOD},
973     {getTimeW,               Date_getTime,               PROPF_METHOD},
974     {getTimezoneOffsetW,     Date_getTimezoneOffset,     PROPF_METHOD},
975     {getUTCDateW,            Date_getUTCDate,            PROPF_METHOD},
976     {getUTCDayW,             Date_getUTCDay,             PROPF_METHOD},
977     {getUTCFullYearW,        Date_getUTCFullYear,        PROPF_METHOD},
978     {getUTCHoursW,           Date_getUTCHours,           PROPF_METHOD},
979     {getUTCMillisecondsW,    Date_getUTCMilliseconds,    PROPF_METHOD},
980     {getUTCMinutesW,         Date_getUTCMinutes,         PROPF_METHOD},
981     {getUTCMonthW,           Date_getUTCMonth,           PROPF_METHOD},
982     {getUTCSecondsW,         Date_getUTCSeconds,         PROPF_METHOD},
983     {hasOwnPropertyW,        Date_hasOwnProperty,        PROPF_METHOD},
984     {isPrototypeOfW,         Date_isPrototypeOf,         PROPF_METHOD},
985     {propertyIsEnumerableW,  Date_propertyIsEnumerable,  PROPF_METHOD},
986     {setDateW,               Date_setDate,               PROPF_METHOD},
987     {setFullYearW,           Date_setFullYear,           PROPF_METHOD},
988     {setHoursW,              Date_setHours,              PROPF_METHOD},
989     {setMillisecondsW,       Date_setMilliseconds,       PROPF_METHOD},
990     {setMinutesW,            Date_setMinutes,            PROPF_METHOD},
991     {setMonthW,              Date_setMonth,              PROPF_METHOD},
992     {setSecondsW,            Date_setSeconds,            PROPF_METHOD},
993     {setTimeW,               Date_setTime,               PROPF_METHOD},
994     {setUTCDateW,            Date_setUTCDate,            PROPF_METHOD},
995     {setUTCFullYearW,        Date_setUTCFullYear,        PROPF_METHOD},
996     {setUTCHoursW,           Date_setUTCHours,           PROPF_METHOD},
997     {setUTCMillisecondsW,    Date_setUTCMilliseconds,    PROPF_METHOD},
998     {setUTCMinutesW,         Date_setUTCMinutes,         PROPF_METHOD},
999     {setUTCMonthW,           Date_setUTCMonth,           PROPF_METHOD},
1000     {setUTCSecondsW,         Date_setUTCSeconds,         PROPF_METHOD},
1001     {toDateStringW,          Date_toDateString,          PROPF_METHOD},
1002     {toLocaleDateStringW,    Date_toLocaleDateString,    PROPF_METHOD},
1003     {toLocaleStringW,        Date_toLocaleString,        PROPF_METHOD},
1004     {toLocaleTimeStringW,    Date_toLocaleTimeString,    PROPF_METHOD},
1005     {toStringW,              Date_toString,              PROPF_METHOD},
1006     {toTimeStringW,          Date_toTimeString,          PROPF_METHOD},
1007     {toUTCStringW,           Date_toUTCString,           PROPF_METHOD},
1008     {valueOfW,               Date_valueOf,               PROPF_METHOD},
1009 };
1010
1011 static const builtin_info_t Date_info = {
1012     JSCLASS_DATE,
1013     {NULL, Date_value, 0},
1014     sizeof(Date_props)/sizeof(*Date_props),
1015     Date_props,
1016     NULL,
1017     NULL
1018 };
1019
1020 static HRESULT create_date(script_ctx_t *ctx, BOOL use_constr, DOUBLE time, DispatchEx **ret)
1021 {
1022     DateInstance *date;
1023     HRESULT hres;
1024     TIME_ZONE_INFORMATION tzi;
1025
1026     GetTimeZoneInformation(&tzi);
1027
1028     date = heap_alloc_zero(sizeof(DateInstance));
1029     if(!date)
1030         return E_OUTOFMEMORY;
1031
1032     if(use_constr)
1033         hres = init_dispex_from_constr(&date->dispex, ctx, &Date_info, ctx->date_constr);
1034     else
1035         hres = init_dispex(&date->dispex, ctx, &Date_info, NULL);
1036     if(FAILED(hres)) {
1037         heap_free(date);
1038         return hres;
1039     }
1040
1041     date->time = time;
1042     date->bias = tzi.Bias;
1043
1044     *ret = &date->dispex;
1045     return S_OK;
1046 }
1047
1048 static HRESULT DateConstr_value(DispatchEx *dispex, LCID lcid, WORD flags, DISPPARAMS *dp,
1049         VARIANT *retv, jsexcept_t *ei, IServiceProvider *sp)
1050 {
1051     DispatchEx *date;
1052     HRESULT hres;
1053
1054     TRACE("\n");
1055
1056     switch(flags) {
1057     case DISPATCH_CONSTRUCT:
1058         switch(arg_cnt(dp)) {
1059         /* ECMA-262 3rd Edition    15.9.3.3 */
1060         case 0: {
1061             FILETIME time;
1062             LONGLONG lltime;
1063
1064             GetSystemTimeAsFileTime(&time);
1065             lltime = ((LONGLONG)time.dwHighDateTime<<32)
1066                 + time.dwLowDateTime;
1067
1068             hres = create_date(dispex->ctx, TRUE, lltime/10000-TIME_EPOCH, &date);
1069             if(FAILED(hres))
1070                 return hres;
1071             break;
1072         }
1073
1074         /* ECMA-262 3rd Edition    15.9.3.2 */
1075         case 1: {
1076             VARIANT prim, num;
1077
1078             hres = to_primitive(dispex->ctx, get_arg(dp,0), ei, &prim);
1079             if(FAILED(hres))
1080                 return hres;
1081
1082             if(V_VT(&prim) == VT_BSTR) {
1083                 FIXME("VT_BSTR not supported\n");
1084                 return E_NOTIMPL;
1085             }
1086
1087             hres = to_number(dispex->ctx, &prim, ei, &num);
1088             VariantClear(&prim);
1089             if(FAILED(hres))
1090                 return hres;
1091
1092             hres = create_date(dispex->ctx, TRUE, time_clip(num_val(&num)), &date);
1093             if(FAILED(hres))
1094                 return hres;
1095             break;
1096         }
1097
1098         default:
1099             FIXME("unimplemented argcnt %d\n", arg_cnt(dp));
1100             return E_NOTIMPL;
1101         }
1102
1103         V_VT(retv) = VT_DISPATCH;
1104         V_DISPATCH(retv) = (IDispatch*)_IDispatchEx_(date);
1105         return S_OK;
1106
1107     default:
1108         FIXME("unimplemented flags %x\n", flags);
1109         return E_NOTIMPL;
1110     }
1111
1112     return S_OK;
1113 }
1114
1115 HRESULT create_date_constr(script_ctx_t *ctx, DispatchEx **ret)
1116 {
1117     DispatchEx *date;
1118     HRESULT hres;
1119
1120     hres = create_date(ctx, FALSE, 0.0, &date);
1121     if(FAILED(hres))
1122         return hres;
1123
1124     hres = create_builtin_function(ctx, DateConstr_value, PROPF_CONSTR, date, ret);
1125
1126     jsdisp_release(date);
1127     return hres;
1128 }