]>
Commit | Line | Data |
---|---|---|
b37bf2e1 A |
1 | /* |
2 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | |
4 | * | |
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 of the License, or (at your option) any later version. | |
9 | * | |
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. | |
14 | * | |
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 Street, Fifth Floor, Boston, MA 02110-1301 | |
18 | * USA | |
19 | * | |
20 | */ | |
21 | ||
22 | #include "config.h" | |
23 | #include "date_object.h" | |
24 | #include "date_object.lut.h" | |
25 | #include "internal.h" | |
26 | ||
27 | #if HAVE(ERRNO_H) | |
28 | #include <errno.h> | |
29 | #endif | |
30 | ||
31 | #if HAVE(SYS_PARAM_H) | |
32 | #include <sys/param.h> | |
33 | #endif | |
34 | ||
35 | #if HAVE(SYS_TIME_H) | |
36 | #include <sys/time.h> | |
37 | #endif | |
38 | ||
39 | #if HAVE(SYS_TIMEB_H) | |
40 | #include <sys/timeb.h> | |
41 | #endif | |
42 | ||
43 | #include <float.h> | |
44 | #include <limits.h> | |
45 | #include <locale.h> | |
46 | #include <math.h> | |
47 | #include <stdio.h> | |
48 | #include <stdlib.h> | |
49 | #include <string.h> | |
50 | #include <time.h> | |
51 | ||
52 | #include "error_object.h" | |
53 | #include "operations.h" | |
54 | #include "DateMath.h" | |
55 | ||
56 | #include <wtf/ASCIICType.h> | |
57 | #include <wtf/Assertions.h> | |
58 | #include <wtf/MathExtras.h> | |
59 | #include <wtf/StringExtras.h> | |
60 | #include <wtf/UnusedParam.h> | |
61 | ||
62 | #include <CoreFoundation/CoreFoundation.h> | |
63 | ||
64 | using namespace WTF; | |
65 | ||
66 | namespace KJS { | |
67 | ||
68 | static double parseDate(const UString&); | |
69 | static double timeClip(double); | |
70 | ||
71 | inline int gmtoffset(const GregorianDateTime& t) | |
72 | { | |
73 | return t.utcOffset; | |
74 | } | |
75 | ||
76 | ||
77 | /** | |
78 | * @internal | |
79 | * | |
80 | * Class to implement all methods that are properties of the | |
81 | * Date object | |
82 | */ | |
83 | class DateObjectFuncImp : public InternalFunctionImp { | |
84 | public: | |
85 | DateObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier& ); | |
86 | ||
87 | virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args); | |
88 | ||
89 | enum { Parse, UTC }; | |
90 | ||
91 | private: | |
92 | int id; | |
93 | }; | |
94 | ||
95 | ||
96 | static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle) | |
97 | { | |
98 | if (string == "short") | |
99 | return kCFDateFormatterShortStyle; | |
100 | if (string == "medium") | |
101 | return kCFDateFormatterMediumStyle; | |
102 | if (string == "long") | |
103 | return kCFDateFormatterLongStyle; | |
104 | if (string == "full") | |
105 | return kCFDateFormatterFullStyle; | |
106 | return defaultStyle; | |
107 | } | |
108 | ||
109 | static UString formatLocaleDate(ExecState *exec, double time, bool includeDate, bool includeTime, const List &args) | |
110 | { | |
111 | CFDateFormatterStyle dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); | |
112 | CFDateFormatterStyle timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle); | |
113 | ||
114 | bool useCustomFormat = false; | |
115 | UString customFormatString; | |
116 | ||
117 | UString arg0String = args[0]->toString(exec); | |
118 | if (arg0String == "custom" && !args[1]->isUndefined()) { | |
119 | useCustomFormat = true; | |
120 | customFormatString = args[1]->toString(exec); | |
121 | } else if (includeDate && includeTime && !args[1]->isUndefined()) { | |
122 | dateStyle = styleFromArgString(arg0String, dateStyle); | |
123 | timeStyle = styleFromArgString(args[1]->toString(exec), timeStyle); | |
124 | } else if (includeDate && !args[0]->isUndefined()) { | |
125 | dateStyle = styleFromArgString(arg0String, dateStyle); | |
126 | } else if (includeTime && !args[0]->isUndefined()) { | |
127 | timeStyle = styleFromArgString(arg0String, timeStyle); | |
128 | } | |
129 | ||
130 | CFLocaleRef locale = CFLocaleCopyCurrent(); | |
131 | CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle); | |
132 | CFRelease(locale); | |
133 | ||
134 | if (useCustomFormat) { | |
135 | CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, (UniChar *)customFormatString.data(), customFormatString.size()); | |
136 | CFDateFormatterSetFormat(formatter, customFormatCFString); | |
137 | CFRelease(customFormatCFString); | |
138 | } | |
139 | ||
140 | CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - kCFAbsoluteTimeIntervalSince1970); | |
141 | ||
142 | CFRelease(formatter); | |
143 | ||
144 | // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters). | |
145 | // That's not great error handling, but it just won't happen so it doesn't matter. | |
146 | UChar buffer[200]; | |
147 | const size_t bufferLength = sizeof(buffer) / sizeof(buffer[0]); | |
148 | size_t length = CFStringGetLength(string); | |
149 | ASSERT(length <= bufferLength); | |
150 | if (length > bufferLength) | |
151 | length = bufferLength; | |
152 | CFStringGetCharacters(string, CFRangeMake(0, length), reinterpret_cast<UniChar *>(buffer)); | |
153 | ||
154 | CFRelease(string); | |
155 | ||
156 | return UString(buffer, length); | |
157 | } | |
158 | ||
159 | ||
160 | static UString formatDate(const GregorianDateTime &t) | |
161 | { | |
162 | char buffer[100]; | |
163 | snprintf(buffer, sizeof(buffer), "%s %s %02d %04d", | |
164 | weekdayName[(t.weekDay + 6) % 7], | |
165 | monthName[t.month], t.monthDay, t.year + 1900); | |
166 | return buffer; | |
167 | } | |
168 | ||
169 | static UString formatDateUTCVariant(const GregorianDateTime &t) | |
170 | { | |
171 | char buffer[100]; | |
172 | snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d", | |
173 | weekdayName[(t.weekDay + 6) % 7], | |
174 | t.monthDay, monthName[t.month], t.year + 1900); | |
175 | return buffer; | |
176 | } | |
177 | ||
178 | static UString formatTime(const GregorianDateTime &t, bool utc) | |
179 | { | |
180 | char buffer[100]; | |
181 | if (utc) { | |
182 | snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); | |
183 | } else { | |
184 | int offset = abs(gmtoffset(t)); | |
185 | char tzname[70]; | |
186 | struct tm gtm = t; | |
187 | strftime(tzname, sizeof(tzname), "%Z", >m); | |
188 | ||
189 | if (tzname[0]) { | |
190 | snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", | |
191 | t.hour, t.minute, t.second, | |
192 | gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, tzname); | |
193 | } else { | |
194 | snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", | |
195 | t.hour, t.minute, t.second, | |
196 | gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60); | |
197 | } | |
198 | } | |
199 | return UString(buffer); | |
200 | } | |
201 | ||
202 | // Converts a list of arguments sent to a Date member function into milliseconds, updating | |
203 | // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. | |
204 | // | |
205 | // Format of member function: f([hour,] [min,] [sec,] [ms]) | |
206 | static void fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int maxArgs, double* ms, GregorianDateTime* t) | |
207 | { | |
208 | double milliseconds = 0; | |
209 | int idx = 0; | |
210 | int numArgs = args.size(); | |
211 | ||
212 | // JS allows extra trailing arguments -- ignore them | |
213 | if (numArgs > maxArgs) | |
214 | numArgs = maxArgs; | |
215 | ||
216 | // hours | |
217 | if (maxArgs >= 4 && idx < numArgs) { | |
218 | t->hour = 0; | |
219 | milliseconds += args[idx++]->toInt32(exec) * msPerHour; | |
220 | } | |
221 | ||
222 | // minutes | |
223 | if (maxArgs >= 3 && idx < numArgs) { | |
224 | t->minute = 0; | |
225 | milliseconds += args[idx++]->toInt32(exec) * msPerMinute; | |
226 | } | |
227 | ||
228 | // seconds | |
229 | if (maxArgs >= 2 && idx < numArgs) { | |
230 | t->second = 0; | |
231 | milliseconds += args[idx++]->toInt32(exec) * msPerSecond; | |
232 | } | |
233 | ||
234 | // milliseconds | |
235 | if (idx < numArgs) | |
236 | milliseconds += args[idx]->toNumber(exec); | |
237 | else | |
238 | milliseconds += *ms; | |
239 | ||
240 | *ms = milliseconds; | |
241 | } | |
242 | ||
243 | // Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating | |
244 | // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately. | |
245 | // | |
246 | // Format of member function: f([years,] [months,] [days]) | |
247 | static void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t) | |
248 | { | |
249 | int idx = 0; | |
250 | int numArgs = args.size(); | |
251 | ||
252 | // JS allows extra trailing arguments -- ignore them | |
253 | if (numArgs > maxArgs) | |
254 | numArgs = maxArgs; | |
255 | ||
256 | // years | |
257 | if (maxArgs >= 3 && idx < numArgs) | |
258 | t->year = args[idx++]->toInt32(exec) - 1900; | |
259 | ||
260 | // months | |
261 | if (maxArgs >= 2 && idx < numArgs) | |
262 | t->month = args[idx++]->toInt32(exec); | |
263 | ||
264 | // days | |
265 | if (idx < numArgs) { | |
266 | t->monthDay = 0; | |
267 | *ms += args[idx]->toInt32(exec) * msPerDay; | |
268 | } | |
269 | } | |
270 | ||
271 | // ------------------------------ DateInstance ------------------------------ | |
272 | ||
273 | const ClassInfo DateInstance::info = {"Date", 0, 0}; | |
274 | ||
275 | DateInstance::DateInstance(JSObject *proto) | |
276 | : JSWrapperObject(proto) | |
277 | { | |
278 | } | |
279 | ||
280 | bool DateInstance::getTime(GregorianDateTime &t, int &offset) const | |
281 | { | |
282 | double milli = internalValue()->getNumber(); | |
283 | if (isnan(milli)) | |
284 | return false; | |
285 | ||
286 | msToGregorianDateTime(milli, false, t); | |
287 | offset = gmtoffset(t); | |
288 | return true; | |
289 | } | |
290 | ||
291 | bool DateInstance::getUTCTime(GregorianDateTime &t) const | |
292 | { | |
293 | double milli = internalValue()->getNumber(); | |
294 | if (isnan(milli)) | |
295 | return false; | |
296 | ||
297 | msToGregorianDateTime(milli, true, t); | |
298 | return true; | |
299 | } | |
300 | ||
301 | bool DateInstance::getTime(double &milli, int &offset) const | |
302 | { | |
303 | milli = internalValue()->getNumber(); | |
304 | if (isnan(milli)) | |
305 | return false; | |
306 | ||
307 | GregorianDateTime t; | |
308 | msToGregorianDateTime(milli, false, t); | |
309 | offset = gmtoffset(t); | |
310 | return true; | |
311 | } | |
312 | ||
313 | bool DateInstance::getUTCTime(double &milli) const | |
314 | { | |
315 | milli = internalValue()->getNumber(); | |
316 | if (isnan(milli)) | |
317 | return false; | |
318 | ||
319 | return true; | |
320 | } | |
321 | ||
322 | static inline bool isTime_tSigned() | |
323 | { | |
324 | time_t minusOne = (time_t)(-1); | |
325 | return minusOne < 0; | |
326 | } | |
327 | ||
328 | // ------------------------------ DatePrototype ----------------------------- | |
329 | ||
330 | const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, &dateTable}; | |
331 | ||
332 | /* Source for date_object.lut.h | |
333 | FIXMEL We could use templates to simplify the UTC variants. | |
334 | @begin dateTable 61 | |
335 | toString dateProtoFuncToString DontEnum|Function 0 | |
336 | toUTCString dateProtoFuncToUTCString DontEnum|Function 0 | |
337 | toDateString dateProtoFuncToDateString DontEnum|Function 0 | |
338 | toTimeString dateProtoFuncToTimeString DontEnum|Function 0 | |
339 | toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0 | |
340 | toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0 | |
341 | toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0 | |
342 | valueOf dateProtoFuncValueOf DontEnum|Function 0 | |
343 | getTime dateProtoFuncGetTime DontEnum|Function 0 | |
344 | getFullYear dateProtoFuncGetFullYear DontEnum|Function 0 | |
345 | getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0 | |
346 | toGMTString dateProtoFuncToGMTString DontEnum|Function 0 | |
347 | getMonth dateProtoFuncGetMonth DontEnum|Function 0 | |
348 | getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0 | |
349 | getDate dateProtoFuncGetDate DontEnum|Function 0 | |
350 | getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0 | |
351 | getDay dateProtoFuncGetDay DontEnum|Function 0 | |
352 | getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0 | |
353 | getHours dateProtoFuncGetHours DontEnum|Function 0 | |
354 | getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0 | |
355 | getMinutes dateProtoFuncGetMinutes DontEnum|Function 0 | |
356 | getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0 | |
357 | getSeconds dateProtoFuncGetSeconds DontEnum|Function 0 | |
358 | getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0 | |
359 | getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0 | |
360 | getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0 | |
361 | getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0 | |
362 | setTime dateProtoFuncSetTime DontEnum|Function 1 | |
363 | setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1 | |
364 | setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1 | |
365 | setSeconds dateProtoFuncSetSeconds DontEnum|Function 2 | |
366 | setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2 | |
367 | setMinutes dateProtoFuncSetMinutes DontEnum|Function 3 | |
368 | setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3 | |
369 | setHours dateProtoFuncSetHours DontEnum|Function 4 | |
370 | setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4 | |
371 | setDate dateProtoFuncSetDate DontEnum|Function 1 | |
372 | setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1 | |
373 | setMonth dateProtoFuncSetMonth DontEnum|Function 2 | |
374 | setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2 | |
375 | setFullYear dateProtoFuncSetFullYear DontEnum|Function 3 | |
376 | setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3 | |
377 | setYear dateProtoFuncSetYear DontEnum|Function 1 | |
378 | getYear dateProtoFuncGetYear DontEnum|Function 0 | |
379 | @end | |
380 | */ | |
381 | // ECMA 15.9.4 | |
382 | ||
383 | DatePrototype::DatePrototype(ExecState *, ObjectPrototype *objectProto) | |
384 | : DateInstance(objectProto) | |
385 | { | |
386 | setInternalValue(jsNaN()); | |
387 | // The constructor will be added later, after DateObjectImp has been built. | |
388 | } | |
389 | ||
390 | bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) | |
391 | { | |
392 | return getStaticFunctionSlot<JSObject>(exec, &dateTable, this, propertyName, slot); | |
393 | } | |
394 | ||
395 | // ------------------------------ DateObjectImp -------------------------------- | |
396 | ||
397 | // TODO: MakeTime (15.9.11.1) etc. ? | |
398 | ||
399 | DateObjectImp::DateObjectImp(ExecState* exec, FunctionPrototype* funcProto, DatePrototype* dateProto) | |
400 | : InternalFunctionImp(funcProto, dateProto->classInfo()->className) | |
401 | { | |
402 | static const Identifier* parsePropertyName = new Identifier("parse"); | |
403 | static const Identifier* UTCPropertyName = new Identifier("UTC"); | |
404 | ||
405 | putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly); | |
406 | putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::Parse, 1, *parsePropertyName), DontEnum); | |
407 | putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::UTC, 7, *UTCPropertyName), DontEnum); | |
408 | putDirect(exec->propertyNames().length, 7, ReadOnly|DontDelete|DontEnum); | |
409 | } | |
410 | ||
411 | bool DateObjectImp::implementsConstruct() const | |
412 | { | |
413 | return true; | |
414 | } | |
415 | ||
416 | // ECMA 15.9.3 | |
417 | JSObject *DateObjectImp::construct(ExecState *exec, const List &args) | |
418 | { | |
419 | int numArgs = args.size(); | |
420 | ||
421 | double value; | |
422 | ||
423 | if (numArgs == 0) { // new Date() ECMA 15.9.3.3 | |
424 | value = getCurrentUTCTime(); | |
425 | } else if (numArgs == 1) { | |
426 | if (args[0]->isObject(&DateInstance::info)) | |
427 | value = static_cast<DateInstance*>(args[0])->internalValue()->toNumber(exec); | |
428 | else { | |
429 | JSValue* primitive = args[0]->toPrimitive(exec); | |
430 | if (primitive->isString()) | |
431 | value = parseDate(primitive->getString()); | |
432 | else | |
433 | value = primitive->toNumber(exec); | |
434 | } | |
435 | } else { | |
436 | if (isnan(args[0]->toNumber(exec)) | |
437 | || isnan(args[1]->toNumber(exec)) | |
438 | || (numArgs >= 3 && isnan(args[2]->toNumber(exec))) | |
439 | || (numArgs >= 4 && isnan(args[3]->toNumber(exec))) | |
440 | || (numArgs >= 5 && isnan(args[4]->toNumber(exec))) | |
441 | || (numArgs >= 6 && isnan(args[5]->toNumber(exec))) | |
442 | || (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) { | |
443 | value = NaN; | |
444 | } else { | |
445 | GregorianDateTime t; | |
446 | int year = args[0]->toInt32(exec); | |
447 | t.year = (year >= 0 && year <= 99) ? year : year - 1900; | |
448 | t.month = args[1]->toInt32(exec); | |
449 | t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1; | |
450 | t.hour = args[3]->toInt32(exec); | |
451 | t.minute = args[4]->toInt32(exec); | |
452 | t.second = args[5]->toInt32(exec); | |
453 | t.isDST = -1; | |
454 | double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0; | |
455 | value = gregorianDateTimeToMS(t, ms, false); | |
456 | } | |
457 | } | |
458 | ||
459 | DateInstance *ret = new DateInstance(exec->lexicalGlobalObject()->datePrototype()); | |
460 | ret->setInternalValue(jsNumber(timeClip(value))); | |
461 | return ret; | |
462 | } | |
463 | ||
464 | // ECMA 15.9.2 | |
465 | JSValue *DateObjectImp::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/) | |
466 | { | |
467 | time_t t = time(0); | |
468 | GregorianDateTime ts(*localtime(&t)); | |
469 | return jsString(formatDate(ts) + " " + formatTime(ts, false)); | |
470 | } | |
471 | ||
472 | // ------------------------------ DateObjectFuncImp ---------------------------- | |
473 | ||
474 | DateObjectFuncImp::DateObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name) | |
475 | : InternalFunctionImp(funcProto, name), id(i) | |
476 | { | |
477 | putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum); | |
478 | } | |
479 | ||
480 | // ECMA 15.9.4.2 - 3 | |
481 | JSValue *DateObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const List& args) | |
482 | { | |
483 | if (id == Parse) { | |
484 | return jsNumber(parseDate(args[0]->toString(exec))); | |
485 | } | |
486 | else { // UTC | |
487 | int n = args.size(); | |
488 | if (isnan(args[0]->toNumber(exec)) | |
489 | || isnan(args[1]->toNumber(exec)) | |
490 | || (n >= 3 && isnan(args[2]->toNumber(exec))) | |
491 | || (n >= 4 && isnan(args[3]->toNumber(exec))) | |
492 | || (n >= 5 && isnan(args[4]->toNumber(exec))) | |
493 | || (n >= 6 && isnan(args[5]->toNumber(exec))) | |
494 | || (n >= 7 && isnan(args[6]->toNumber(exec)))) { | |
495 | return jsNaN(); | |
496 | } | |
497 | ||
498 | GregorianDateTime t; | |
499 | memset(&t, 0, sizeof(t)); | |
500 | int year = args[0]->toInt32(exec); | |
501 | t.year = (year >= 0 && year <= 99) ? year : year - 1900; | |
502 | t.month = args[1]->toInt32(exec); | |
503 | t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1; | |
504 | t.hour = args[3]->toInt32(exec); | |
505 | t.minute = args[4]->toInt32(exec); | |
506 | t.second = args[5]->toInt32(exec); | |
507 | double ms = (n >= 7) ? args[6]->toNumber(exec) : 0; | |
508 | return jsNumber(gregorianDateTimeToMS(t, ms, true)); | |
509 | } | |
510 | } | |
511 | ||
512 | // ----------------------------------------------------------------------------- | |
513 | ||
514 | // Code originally from krfcdate.cpp, but we don't want to use kdecore, and we want double range. | |
515 | ||
516 | static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second) | |
517 | { | |
518 | double days = (day - 32075) | |
519 | + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4) | |
520 | + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12 | |
521 | - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4) | |
522 | - 2440588; | |
523 | return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second; | |
524 | } | |
525 | ||
526 | // We follow the recommendation of RFC 2822 to consider all | |
527 | // obsolete time zones not listed here equivalent to "-0000". | |
528 | static const struct KnownZone { | |
529 | #if !PLATFORM(WIN_OS) | |
530 | const | |
531 | #endif | |
532 | char tzName[4]; | |
533 | int tzOffset; | |
534 | } known_zones[] = { | |
535 | { "UT", 0 }, | |
536 | { "GMT", 0 }, | |
537 | { "EST", -300 }, | |
538 | { "EDT", -240 }, | |
539 | { "CST", -360 }, | |
540 | { "CDT", -300 }, | |
541 | { "MST", -420 }, | |
542 | { "MDT", -360 }, | |
543 | { "PST", -480 }, | |
544 | { "PDT", -420 } | |
545 | }; | |
546 | ||
547 | inline static void skipSpacesAndComments(const char*& s) | |
548 | { | |
549 | int nesting = 0; | |
550 | char ch; | |
551 | while ((ch = *s)) { | |
552 | if (!isASCIISpace(ch)) { | |
553 | if (ch == '(') | |
554 | nesting++; | |
555 | else if (ch == ')' && nesting > 0) | |
556 | nesting--; | |
557 | else if (nesting == 0) | |
558 | break; | |
559 | } | |
560 | s++; | |
561 | } | |
562 | } | |
563 | ||
564 | // returns 0-11 (Jan-Dec); -1 on failure | |
565 | static int findMonth(const char* monthStr) | |
566 | { | |
567 | ASSERT(monthStr); | |
568 | char needle[4]; | |
569 | for (int i = 0; i < 3; ++i) { | |
570 | if (!*monthStr) | |
571 | return -1; | |
572 | needle[i] = static_cast<char>(toASCIILower(*monthStr++)); | |
573 | } | |
574 | needle[3] = '\0'; | |
575 | const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec"; | |
576 | const char *str = strstr(haystack, needle); | |
577 | if (str) { | |
578 | int position = static_cast<int>(str - haystack); | |
579 | if (position % 3 == 0) | |
580 | return position / 3; | |
581 | } | |
582 | return -1; | |
583 | } | |
584 | ||
585 | static double parseDate(const UString &date) | |
586 | { | |
587 | // This parses a date in the form: | |
588 | // Tuesday, 09-Nov-99 23:12:40 GMT | |
589 | // or | |
590 | // Sat, 01-Jan-2000 08:00:00 GMT | |
591 | // or | |
592 | // Sat, 01 Jan 2000 08:00:00 GMT | |
593 | // or | |
594 | // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822) | |
595 | // ### non RFC formats, added for Javascript: | |
596 | // [Wednesday] January 09 1999 23:12:40 GMT | |
597 | // [Wednesday] January 09 23:12:40 GMT 1999 | |
598 | // | |
599 | // We ignore the weekday. | |
600 | ||
601 | CString dateCString = date.UTF8String(); | |
602 | const char *dateString = dateCString.c_str(); | |
603 | ||
604 | // Skip leading space | |
605 | skipSpacesAndComments(dateString); | |
606 | ||
607 | long month = -1; | |
608 | const char *wordStart = dateString; | |
609 | // Check contents of first words if not number | |
610 | while (*dateString && !isASCIIDigit(*dateString)) { | |
611 | if (isASCIISpace(*dateString) || *dateString == '(') { | |
612 | if (dateString - wordStart >= 3) | |
613 | month = findMonth(wordStart); | |
614 | skipSpacesAndComments(dateString); | |
615 | wordStart = dateString; | |
616 | } else | |
617 | dateString++; | |
618 | } | |
619 | ||
620 | // Missing delimiter between month and day (like "January29")? | |
621 | if (month == -1 && wordStart != dateString) | |
622 | month = findMonth(wordStart); | |
623 | ||
624 | skipSpacesAndComments(dateString); | |
625 | ||
626 | if (!*dateString) | |
627 | return NaN; | |
628 | ||
629 | // ' 09-Nov-99 23:12:40 GMT' | |
630 | char *newPosStr; | |
631 | errno = 0; | |
632 | long day = strtol(dateString, &newPosStr, 10); | |
633 | if (errno) | |
634 | return NaN; | |
635 | dateString = newPosStr; | |
636 | ||
637 | if (!*dateString) | |
638 | return NaN; | |
639 | ||
640 | if (day < 0) | |
641 | return NaN; | |
642 | ||
643 | long year = 0; | |
644 | if (day > 31) { | |
645 | // ### where is the boundary and what happens below? | |
646 | if (*dateString != '/') | |
647 | return NaN; | |
648 | // looks like a YYYY/MM/DD date | |
649 | if (!*++dateString) | |
650 | return NaN; | |
651 | year = day; | |
652 | month = strtol(dateString, &newPosStr, 10) - 1; | |
653 | if (errno) | |
654 | return NaN; | |
655 | dateString = newPosStr; | |
656 | if (*dateString++ != '/' || !*dateString) | |
657 | return NaN; | |
658 | day = strtol(dateString, &newPosStr, 10); | |
659 | if (errno) | |
660 | return NaN; | |
661 | dateString = newPosStr; | |
662 | } else if (*dateString == '/' && month == -1) { | |
663 | dateString++; | |
664 | // This looks like a MM/DD/YYYY date, not an RFC date. | |
665 | month = day - 1; // 0-based | |
666 | day = strtol(dateString, &newPosStr, 10); | |
667 | if (errno) | |
668 | return NaN; | |
669 | if (day < 1 || day > 31) | |
670 | return NaN; | |
671 | dateString = newPosStr; | |
672 | if (*dateString == '/') | |
673 | dateString++; | |
674 | if (!*dateString) | |
675 | return NaN; | |
676 | } else { | |
677 | if (*dateString == '-') | |
678 | dateString++; | |
679 | ||
680 | skipSpacesAndComments(dateString); | |
681 | ||
682 | if (*dateString == ',') | |
683 | dateString++; | |
684 | ||
685 | if (month == -1) { // not found yet | |
686 | month = findMonth(dateString); | |
687 | if (month == -1) | |
688 | return NaN; | |
689 | ||
690 | while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString)) | |
691 | dateString++; | |
692 | ||
693 | if (!*dateString) | |
694 | return NaN; | |
695 | ||
696 | // '-99 23:12:40 GMT' | |
697 | if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString)) | |
698 | return NaN; | |
699 | dateString++; | |
700 | } | |
701 | } | |
702 | ||
703 | if (month < 0 || month > 11) | |
704 | return NaN; | |
705 | ||
706 | // '99 23:12:40 GMT' | |
707 | if (year <= 0 && *dateString) { | |
708 | year = strtol(dateString, &newPosStr, 10); | |
709 | if (errno) | |
710 | return NaN; | |
711 | } | |
712 | ||
713 | // Don't fail if the time is missing. | |
714 | long hour = 0; | |
715 | long minute = 0; | |
716 | long second = 0; | |
717 | if (!*newPosStr) | |
718 | dateString = newPosStr; | |
719 | else { | |
720 | // ' 23:12:40 GMT' | |
721 | if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) { | |
722 | if (*newPosStr != ':') | |
723 | return NaN; | |
724 | // There was no year; the number was the hour. | |
725 | year = -1; | |
726 | } else { | |
727 | // in the normal case (we parsed the year), advance to the next number | |
728 | dateString = ++newPosStr; | |
729 | skipSpacesAndComments(dateString); | |
730 | } | |
731 | ||
732 | hour = strtol(dateString, &newPosStr, 10); | |
733 | // Do not check for errno here since we want to continue | |
734 | // even if errno was set becasue we are still looking | |
735 | // for the timezone! | |
736 | ||
737 | // Read a number? If not, this might be a timezone name. | |
738 | if (newPosStr != dateString) { | |
739 | dateString = newPosStr; | |
740 | ||
741 | if (hour < 0 || hour > 23) | |
742 | return NaN; | |
743 | ||
744 | if (!*dateString) | |
745 | return NaN; | |
746 | ||
747 | // ':12:40 GMT' | |
748 | if (*dateString++ != ':') | |
749 | return NaN; | |
750 | ||
751 | minute = strtol(dateString, &newPosStr, 10); | |
752 | if (errno) | |
753 | return NaN; | |
754 | dateString = newPosStr; | |
755 | ||
756 | if (minute < 0 || minute > 59) | |
757 | return NaN; | |
758 | ||
759 | // ':40 GMT' | |
760 | if (*dateString && *dateString != ':' && !isASCIISpace(*dateString)) | |
761 | return NaN; | |
762 | ||
763 | // seconds are optional in rfc822 + rfc2822 | |
764 | if (*dateString ==':') { | |
765 | dateString++; | |
766 | ||
767 | second = strtol(dateString, &newPosStr, 10); | |
768 | if (errno) | |
769 | return NaN; | |
770 | dateString = newPosStr; | |
771 | ||
772 | if (second < 0 || second > 59) | |
773 | return NaN; | |
774 | } | |
775 | ||
776 | skipSpacesAndComments(dateString); | |
777 | ||
778 | if (strncasecmp(dateString, "AM", 2) == 0) { | |
779 | if (hour > 12) | |
780 | return NaN; | |
781 | if (hour == 12) | |
782 | hour = 0; | |
783 | dateString += 2; | |
784 | skipSpacesAndComments(dateString); | |
785 | } else if (strncasecmp(dateString, "PM", 2) == 0) { | |
786 | if (hour > 12) | |
787 | return NaN; | |
788 | if (hour != 12) | |
789 | hour += 12; | |
790 | dateString += 2; | |
791 | skipSpacesAndComments(dateString); | |
792 | } | |
793 | } | |
794 | } | |
795 | ||
796 | bool haveTZ = false; | |
797 | int offset = 0; | |
798 | ||
799 | // Don't fail if the time zone is missing. | |
800 | // Some websites omit the time zone (4275206). | |
801 | if (*dateString) { | |
802 | if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) { | |
803 | dateString += 3; | |
804 | haveTZ = true; | |
805 | } | |
806 | ||
807 | if (*dateString == '+' || *dateString == '-') { | |
808 | long o = strtol(dateString, &newPosStr, 10); | |
809 | if (errno) | |
810 | return NaN; | |
811 | dateString = newPosStr; | |
812 | ||
813 | if (o < -9959 || o > 9959) | |
814 | return NaN; | |
815 | ||
816 | int sgn = (o < 0) ? -1 : 1; | |
817 | o = abs(o); | |
818 | if (*dateString != ':') { | |
819 | offset = ((o / 100) * 60 + (o % 100)) * sgn; | |
820 | } else { // GMT+05:00 | |
821 | long o2 = strtol(dateString, &newPosStr, 10); | |
822 | if (errno) | |
823 | return NaN; | |
824 | dateString = newPosStr; | |
825 | offset = (o * 60 + o2) * sgn; | |
826 | } | |
827 | haveTZ = true; | |
828 | } else { | |
829 | for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) { | |
830 | if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) { | |
831 | offset = known_zones[i].tzOffset; | |
832 | dateString += strlen(known_zones[i].tzName); | |
833 | haveTZ = true; | |
834 | break; | |
835 | } | |
836 | } | |
837 | } | |
838 | } | |
839 | ||
840 | skipSpacesAndComments(dateString); | |
841 | ||
842 | if (*dateString && year == -1) { | |
843 | year = strtol(dateString, &newPosStr, 10); | |
844 | if (errno) | |
845 | return NaN; | |
846 | dateString = newPosStr; | |
847 | } | |
848 | ||
849 | skipSpacesAndComments(dateString); | |
850 | ||
851 | // Trailing garbage | |
852 | if (*dateString) | |
853 | return NaN; | |
854 | ||
855 | // Y2K: Handle 2 digit years. | |
856 | if (year >= 0 && year < 100) { | |
857 | if (year < 50) | |
858 | year += 2000; | |
859 | else | |
860 | year += 1900; | |
861 | } | |
862 | ||
863 | // fall back to local timezone | |
864 | if (!haveTZ) { | |
865 | GregorianDateTime t; | |
866 | memset(&t, 0, sizeof(tm)); | |
867 | t.monthDay = day; | |
868 | t.month = month; | |
869 | t.year = year - 1900; | |
870 | t.isDST = -1; | |
871 | t.second = second; | |
872 | t.minute = minute; | |
873 | t.hour = hour; | |
874 | ||
875 | // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range. | |
876 | return gregorianDateTimeToMS(t, 0, false); | |
877 | } | |
878 | ||
879 | return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond; | |
880 | } | |
881 | ||
882 | double timeClip(double t) | |
883 | { | |
884 | if (!isfinite(t)) | |
885 | return NaN; | |
886 | if (fabs(t) > 8.64E15) | |
887 | return NaN; | |
888 | return trunc(t); | |
889 | } | |
890 | ||
891 | // Functions | |
892 | ||
893 | JSValue* dateProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&) | |
894 | { | |
895 | if (!thisObj->inherits(&DateInstance::info)) | |
896 | return throwError(exec, TypeError); | |
897 | ||
898 | const bool utc = false; | |
899 | ||
900 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
901 | JSValue* v = thisDateObj->internalValue(); | |
902 | double milli = v->toNumber(exec); | |
903 | if (isnan(milli)) | |
904 | return jsString("Invalid Date"); | |
905 | ||
906 | GregorianDateTime t; | |
907 | msToGregorianDateTime(milli, utc, t); | |
908 | return jsString(formatDate(t) + " " + formatTime(t, utc)); | |
909 | } | |
910 | ||
911 | JSValue* dateProtoFuncToUTCString(ExecState* exec, JSObject* thisObj, const List&) | |
912 | { | |
913 | if (!thisObj->inherits(&DateInstance::info)) | |
914 | return throwError(exec, TypeError); | |
915 | ||
916 | const bool utc = true; | |
917 | ||
918 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
919 | JSValue* v = thisDateObj->internalValue(); | |
920 | double milli = v->toNumber(exec); | |
921 | if (isnan(milli)) | |
922 | return jsString("Invalid Date"); | |
923 | ||
924 | GregorianDateTime t; | |
925 | msToGregorianDateTime(milli, utc, t); | |
926 | return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc)); | |
927 | } | |
928 | ||
929 | JSValue* dateProtoFuncToDateString(ExecState* exec, JSObject* thisObj, const List&) | |
930 | { | |
931 | if (!thisObj->inherits(&DateInstance::info)) | |
932 | return throwError(exec, TypeError); | |
933 | ||
934 | const bool utc = false; | |
935 | ||
936 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
937 | JSValue* v = thisDateObj->internalValue(); | |
938 | double milli = v->toNumber(exec); | |
939 | if (isnan(milli)) | |
940 | return jsString("Invalid Date"); | |
941 | ||
942 | GregorianDateTime t; | |
943 | msToGregorianDateTime(milli, utc, t); | |
944 | return jsString(formatDate(t)); | |
945 | } | |
946 | ||
947 | JSValue* dateProtoFuncToTimeString(ExecState* exec, JSObject* thisObj, const List&) | |
948 | { | |
949 | if (!thisObj->inherits(&DateInstance::info)) | |
950 | return throwError(exec, TypeError); | |
951 | ||
952 | const bool utc = false; | |
953 | ||
954 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
955 | JSValue* v = thisDateObj->internalValue(); | |
956 | double milli = v->toNumber(exec); | |
957 | if (isnan(milli)) | |
958 | return jsString("Invalid Date"); | |
959 | ||
960 | GregorianDateTime t; | |
961 | msToGregorianDateTime(milli, utc, t); | |
962 | return jsString(formatTime(t, utc)); | |
963 | } | |
964 | ||
965 | JSValue* dateProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List& args) | |
966 | { | |
967 | if (!thisObj->inherits(&DateInstance::info)) | |
968 | return throwError(exec, TypeError); | |
969 | ||
970 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
971 | JSValue* v = thisDateObj->internalValue(); | |
972 | double milli = v->toNumber(exec); | |
973 | if (isnan(milli)) | |
974 | return jsString("Invalid Date"); | |
975 | ||
976 | double secs = floor(milli / msPerSecond); | |
977 | return jsString(formatLocaleDate(exec, secs, true, true, args)); | |
978 | } | |
979 | ||
980 | JSValue* dateProtoFuncToLocaleDateString(ExecState* exec, JSObject* thisObj, const List& args) | |
981 | { | |
982 | if (!thisObj->inherits(&DateInstance::info)) | |
983 | return throwError(exec, TypeError); | |
984 | ||
985 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
986 | JSValue* v = thisDateObj->internalValue(); | |
987 | double milli = v->toNumber(exec); | |
988 | if (isnan(milli)) | |
989 | return jsString("Invalid Date"); | |
990 | ||
991 | double secs = floor(milli / msPerSecond); | |
992 | return jsString(formatLocaleDate(exec, secs, true, false, args)); | |
993 | } | |
994 | ||
995 | JSValue* dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject* thisObj, const List& args) | |
996 | { | |
997 | if (!thisObj->inherits(&DateInstance::info)) | |
998 | return throwError(exec, TypeError); | |
999 | ||
1000 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1001 | JSValue* v = thisDateObj->internalValue(); | |
1002 | double milli = v->toNumber(exec); | |
1003 | if (isnan(milli)) | |
1004 | return jsString("Invalid Date"); | |
1005 | ||
1006 | double secs = floor(milli / msPerSecond); | |
1007 | return jsString(formatLocaleDate(exec, secs, false, true, args)); | |
1008 | } | |
1009 | ||
1010 | JSValue* dateProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&) | |
1011 | { | |
1012 | if (!thisObj->inherits(&DateInstance::info)) | |
1013 | return throwError(exec, TypeError); | |
1014 | ||
1015 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1016 | JSValue* v = thisDateObj->internalValue(); | |
1017 | double milli = v->toNumber(exec); | |
1018 | if (isnan(milli)) | |
1019 | return jsNaN(); | |
1020 | ||
1021 | return jsNumber(milli); | |
1022 | } | |
1023 | ||
1024 | JSValue* dateProtoFuncGetTime(ExecState* exec, JSObject* thisObj, const List&) | |
1025 | { | |
1026 | if (!thisObj->inherits(&DateInstance::info)) | |
1027 | return throwError(exec, TypeError); | |
1028 | ||
1029 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1030 | JSValue* v = thisDateObj->internalValue(); | |
1031 | double milli = v->toNumber(exec); | |
1032 | if (isnan(milli)) | |
1033 | return jsNaN(); | |
1034 | ||
1035 | return jsNumber(milli); | |
1036 | } | |
1037 | ||
1038 | JSValue* dateProtoFuncGetFullYear(ExecState* exec, JSObject* thisObj, const List&) | |
1039 | { | |
1040 | if (!thisObj->inherits(&DateInstance::info)) | |
1041 | return throwError(exec, TypeError); | |
1042 | ||
1043 | const bool utc = false; | |
1044 | ||
1045 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1046 | JSValue* v = thisDateObj->internalValue(); | |
1047 | double milli = v->toNumber(exec); | |
1048 | if (isnan(milli)) | |
1049 | return jsNaN(); | |
1050 | ||
1051 | GregorianDateTime t; | |
1052 | msToGregorianDateTime(milli, utc, t); | |
1053 | return jsNumber(1900 + t.year); | |
1054 | } | |
1055 | ||
1056 | JSValue* dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject* thisObj, const List&) | |
1057 | { | |
1058 | if (!thisObj->inherits(&DateInstance::info)) | |
1059 | return throwError(exec, TypeError); | |
1060 | ||
1061 | const bool utc = true; | |
1062 | ||
1063 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1064 | JSValue* v = thisDateObj->internalValue(); | |
1065 | double milli = v->toNumber(exec); | |
1066 | if (isnan(milli)) | |
1067 | return jsNaN(); | |
1068 | ||
1069 | GregorianDateTime t; | |
1070 | msToGregorianDateTime(milli, utc, t); | |
1071 | return jsNumber(1900 + t.year); | |
1072 | } | |
1073 | ||
1074 | JSValue* dateProtoFuncToGMTString(ExecState* exec, JSObject* thisObj, const List&) | |
1075 | { | |
1076 | if (!thisObj->inherits(&DateInstance::info)) | |
1077 | return throwError(exec, TypeError); | |
1078 | ||
1079 | const bool utc = true; | |
1080 | ||
1081 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1082 | JSValue* v = thisDateObj->internalValue(); | |
1083 | double milli = v->toNumber(exec); | |
1084 | if (isnan(milli)) | |
1085 | return jsString("Invalid Date"); | |
1086 | ||
1087 | GregorianDateTime t; | |
1088 | msToGregorianDateTime(milli, utc, t); | |
1089 | return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc)); | |
1090 | } | |
1091 | ||
1092 | JSValue* dateProtoFuncGetMonth(ExecState* exec, JSObject* thisObj, const List&) | |
1093 | { | |
1094 | if (!thisObj->inherits(&DateInstance::info)) | |
1095 | return throwError(exec, TypeError); | |
1096 | ||
1097 | const bool utc = false; | |
1098 | ||
1099 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1100 | JSValue* v = thisDateObj->internalValue(); | |
1101 | double milli = v->toNumber(exec); | |
1102 | if (isnan(milli)) | |
1103 | return jsNaN(); | |
1104 | ||
1105 | GregorianDateTime t; | |
1106 | msToGregorianDateTime(milli, utc, t); | |
1107 | return jsNumber(t.month); | |
1108 | } | |
1109 | ||
1110 | JSValue* dateProtoFuncGetUTCMonth(ExecState* exec, JSObject* thisObj, const List&) | |
1111 | { | |
1112 | if (!thisObj->inherits(&DateInstance::info)) | |
1113 | return throwError(exec, TypeError); | |
1114 | ||
1115 | const bool utc = true; | |
1116 | ||
1117 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1118 | JSValue* v = thisDateObj->internalValue(); | |
1119 | double milli = v->toNumber(exec); | |
1120 | if (isnan(milli)) | |
1121 | return jsNaN(); | |
1122 | ||
1123 | GregorianDateTime t; | |
1124 | msToGregorianDateTime(milli, utc, t); | |
1125 | return jsNumber(t.month); | |
1126 | } | |
1127 | ||
1128 | JSValue* dateProtoFuncGetDate(ExecState* exec, JSObject* thisObj, const List&) | |
1129 | { | |
1130 | if (!thisObj->inherits(&DateInstance::info)) | |
1131 | return throwError(exec, TypeError); | |
1132 | ||
1133 | const bool utc = false; | |
1134 | ||
1135 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1136 | JSValue* v = thisDateObj->internalValue(); | |
1137 | double milli = v->toNumber(exec); | |
1138 | if (isnan(milli)) | |
1139 | return jsNaN(); | |
1140 | ||
1141 | GregorianDateTime t; | |
1142 | msToGregorianDateTime(milli, utc, t); | |
1143 | return jsNumber(t.monthDay); | |
1144 | } | |
1145 | ||
1146 | JSValue* dateProtoFuncGetUTCDate(ExecState* exec, JSObject* thisObj, const List&) | |
1147 | { | |
1148 | if (!thisObj->inherits(&DateInstance::info)) | |
1149 | return throwError(exec, TypeError); | |
1150 | ||
1151 | const bool utc = true; | |
1152 | ||
1153 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1154 | JSValue* v = thisDateObj->internalValue(); | |
1155 | double milli = v->toNumber(exec); | |
1156 | if (isnan(milli)) | |
1157 | return jsNaN(); | |
1158 | ||
1159 | GregorianDateTime t; | |
1160 | msToGregorianDateTime(milli, utc, t); | |
1161 | return jsNumber(t.monthDay); | |
1162 | } | |
1163 | ||
1164 | JSValue* dateProtoFuncGetDay(ExecState* exec, JSObject* thisObj, const List&) | |
1165 | { | |
1166 | if (!thisObj->inherits(&DateInstance::info)) | |
1167 | return throwError(exec, TypeError); | |
1168 | ||
1169 | const bool utc = false; | |
1170 | ||
1171 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1172 | JSValue* v = thisDateObj->internalValue(); | |
1173 | double milli = v->toNumber(exec); | |
1174 | if (isnan(milli)) | |
1175 | return jsNaN(); | |
1176 | ||
1177 | GregorianDateTime t; | |
1178 | msToGregorianDateTime(milli, utc, t); | |
1179 | return jsNumber(t.weekDay); | |
1180 | } | |
1181 | ||
1182 | JSValue* dateProtoFuncGetUTCDay(ExecState* exec, JSObject* thisObj, const List&) | |
1183 | { | |
1184 | if (!thisObj->inherits(&DateInstance::info)) | |
1185 | return throwError(exec, TypeError); | |
1186 | ||
1187 | const bool utc = true; | |
1188 | ||
1189 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1190 | JSValue* v = thisDateObj->internalValue(); | |
1191 | double milli = v->toNumber(exec); | |
1192 | if (isnan(milli)) | |
1193 | return jsNaN(); | |
1194 | ||
1195 | GregorianDateTime t; | |
1196 | msToGregorianDateTime(milli, utc, t); | |
1197 | return jsNumber(t.weekDay); | |
1198 | } | |
1199 | ||
1200 | JSValue* dateProtoFuncGetHours(ExecState* exec, JSObject* thisObj, const List&) | |
1201 | { | |
1202 | if (!thisObj->inherits(&DateInstance::info)) | |
1203 | return throwError(exec, TypeError); | |
1204 | ||
1205 | const bool utc = false; | |
1206 | ||
1207 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1208 | JSValue* v = thisDateObj->internalValue(); | |
1209 | double milli = v->toNumber(exec); | |
1210 | if (isnan(milli)) | |
1211 | return jsNaN(); | |
1212 | ||
1213 | GregorianDateTime t; | |
1214 | msToGregorianDateTime(milli, utc, t); | |
1215 | return jsNumber(t.hour); | |
1216 | } | |
1217 | ||
1218 | JSValue* dateProtoFuncGetUTCHours(ExecState* exec, JSObject* thisObj, const List&) | |
1219 | { | |
1220 | if (!thisObj->inherits(&DateInstance::info)) | |
1221 | return throwError(exec, TypeError); | |
1222 | ||
1223 | const bool utc = true; | |
1224 | ||
1225 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1226 | JSValue* v = thisDateObj->internalValue(); | |
1227 | double milli = v->toNumber(exec); | |
1228 | if (isnan(milli)) | |
1229 | return jsNaN(); | |
1230 | ||
1231 | GregorianDateTime t; | |
1232 | msToGregorianDateTime(milli, utc, t); | |
1233 | return jsNumber(t.hour); | |
1234 | } | |
1235 | ||
1236 | JSValue* dateProtoFuncGetMinutes(ExecState* exec, JSObject* thisObj, const List&) | |
1237 | { | |
1238 | if (!thisObj->inherits(&DateInstance::info)) | |
1239 | return throwError(exec, TypeError); | |
1240 | ||
1241 | const bool utc = false; | |
1242 | ||
1243 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1244 | JSValue* v = thisDateObj->internalValue(); | |
1245 | double milli = v->toNumber(exec); | |
1246 | if (isnan(milli)) | |
1247 | return jsNaN(); | |
1248 | ||
1249 | GregorianDateTime t; | |
1250 | msToGregorianDateTime(milli, utc, t); | |
1251 | return jsNumber(t.minute); | |
1252 | } | |
1253 | ||
1254 | JSValue* dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject* thisObj, const List&) | |
1255 | { | |
1256 | if (!thisObj->inherits(&DateInstance::info)) | |
1257 | return throwError(exec, TypeError); | |
1258 | ||
1259 | const bool utc = true; | |
1260 | ||
1261 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1262 | JSValue* v = thisDateObj->internalValue(); | |
1263 | double milli = v->toNumber(exec); | |
1264 | if (isnan(milli)) | |
1265 | return jsNaN(); | |
1266 | ||
1267 | GregorianDateTime t; | |
1268 | msToGregorianDateTime(milli, utc, t); | |
1269 | return jsNumber(t.minute); | |
1270 | } | |
1271 | ||
1272 | JSValue* dateProtoFuncGetSeconds(ExecState* exec, JSObject* thisObj, const List&) | |
1273 | { | |
1274 | if (!thisObj->inherits(&DateInstance::info)) | |
1275 | return throwError(exec, TypeError); | |
1276 | ||
1277 | const bool utc = false; | |
1278 | ||
1279 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1280 | JSValue* v = thisDateObj->internalValue(); | |
1281 | double milli = v->toNumber(exec); | |
1282 | if (isnan(milli)) | |
1283 | return jsNaN(); | |
1284 | ||
1285 | GregorianDateTime t; | |
1286 | msToGregorianDateTime(milli, utc, t); | |
1287 | return jsNumber(t.second); | |
1288 | } | |
1289 | ||
1290 | JSValue* dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject* thisObj, const List&) | |
1291 | { | |
1292 | if (!thisObj->inherits(&DateInstance::info)) | |
1293 | return throwError(exec, TypeError); | |
1294 | ||
1295 | const bool utc = true; | |
1296 | ||
1297 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1298 | JSValue* v = thisDateObj->internalValue(); | |
1299 | double milli = v->toNumber(exec); | |
1300 | if (isnan(milli)) | |
1301 | return jsNaN(); | |
1302 | ||
1303 | GregorianDateTime t; | |
1304 | msToGregorianDateTime(milli, utc, t); | |
1305 | return jsNumber(t.second); | |
1306 | } | |
1307 | ||
1308 | JSValue* dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject* thisObj, const List&) | |
1309 | { | |
1310 | if (!thisObj->inherits(&DateInstance::info)) | |
1311 | return throwError(exec, TypeError); | |
1312 | ||
1313 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1314 | JSValue* v = thisDateObj->internalValue(); | |
1315 | double milli = v->toNumber(exec); | |
1316 | if (isnan(milli)) | |
1317 | return jsNaN(); | |
1318 | ||
1319 | double secs = floor(milli / msPerSecond); | |
1320 | double ms = milli - secs * msPerSecond; | |
1321 | return jsNumber(ms); | |
1322 | } | |
1323 | ||
1324 | JSValue* dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List&) | |
1325 | { | |
1326 | if (!thisObj->inherits(&DateInstance::info)) | |
1327 | return throwError(exec, TypeError); | |
1328 | ||
1329 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1330 | JSValue* v = thisDateObj->internalValue(); | |
1331 | double milli = v->toNumber(exec); | |
1332 | if (isnan(milli)) | |
1333 | return jsNaN(); | |
1334 | ||
1335 | double secs = floor(milli / msPerSecond); | |
1336 | double ms = milli - secs * msPerSecond; | |
1337 | return jsNumber(ms); | |
1338 | } | |
1339 | ||
1340 | JSValue* dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject* thisObj, const List&) | |
1341 | { | |
1342 | if (!thisObj->inherits(&DateInstance::info)) | |
1343 | return throwError(exec, TypeError); | |
1344 | ||
1345 | const bool utc = false; | |
1346 | ||
1347 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1348 | JSValue* v = thisDateObj->internalValue(); | |
1349 | double milli = v->toNumber(exec); | |
1350 | if (isnan(milli)) | |
1351 | return jsNaN(); | |
1352 | ||
1353 | GregorianDateTime t; | |
1354 | msToGregorianDateTime(milli, utc, t); | |
1355 | return jsNumber(-gmtoffset(t) / minutesPerHour); | |
1356 | } | |
1357 | ||
1358 | JSValue* dateProtoFuncSetTime(ExecState* exec, JSObject* thisObj, const List& args) | |
1359 | { | |
1360 | if (!thisObj->inherits(&DateInstance::info)) | |
1361 | return throwError(exec, TypeError); | |
1362 | ||
1363 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1364 | ||
1365 | double milli = timeClip(args[0]->toNumber(exec)); | |
1366 | JSValue* result = jsNumber(milli); | |
1367 | thisDateObj->setInternalValue(result); | |
1368 | return result; | |
1369 | } | |
1370 | ||
1371 | static JSValue* setNewValueFromTimeArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC) | |
1372 | { | |
1373 | if (!thisObj->inherits(&DateInstance::info)) | |
1374 | return throwError(exec, TypeError); | |
1375 | ||
1376 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1377 | JSValue* v = thisDateObj->internalValue(); | |
1378 | double milli = v->toNumber(exec); | |
1379 | double secs = floor(milli / msPerSecond); | |
1380 | double ms = milli - secs * msPerSecond; | |
1381 | ||
1382 | GregorianDateTime t; | |
1383 | msToGregorianDateTime(milli, inputIsUTC, t); | |
1384 | ||
1385 | fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t); | |
1386 | ||
1387 | JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC)); | |
1388 | thisDateObj->setInternalValue(result); | |
1389 | return result; | |
1390 | } | |
1391 | ||
1392 | static JSValue* setNewValueFromDateArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC) | |
1393 | { | |
1394 | if (!thisObj->inherits(&DateInstance::info)) | |
1395 | return throwError(exec, TypeError); | |
1396 | ||
1397 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1398 | JSValue* v = thisDateObj->internalValue(); | |
1399 | double milli = v->toNumber(exec); | |
1400 | double secs = floor(milli / msPerSecond); | |
1401 | double ms = milli - secs * msPerSecond; | |
1402 | ||
1403 | GregorianDateTime t; | |
1404 | msToGregorianDateTime(milli, inputIsUTC, t); | |
1405 | ||
1406 | fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t); | |
1407 | ||
1408 | JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC)); | |
1409 | thisDateObj->setInternalValue(result); | |
1410 | return result; | |
1411 | } | |
1412 | ||
1413 | JSValue* dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject* thisObj, const List& args) | |
1414 | { | |
1415 | const bool inputIsUTC = false; | |
1416 | return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC); | |
1417 | } | |
1418 | ||
1419 | JSValue* dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List& args) | |
1420 | { | |
1421 | const bool inputIsUTC = true; | |
1422 | return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC); | |
1423 | } | |
1424 | ||
1425 | JSValue* dateProtoFuncSetSeconds(ExecState* exec, JSObject* thisObj, const List& args) | |
1426 | { | |
1427 | const bool inputIsUTC = false; | |
1428 | return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC); | |
1429 | } | |
1430 | ||
1431 | JSValue* dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject* thisObj, const List& args) | |
1432 | { | |
1433 | const bool inputIsUTC = true; | |
1434 | return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC); | |
1435 | } | |
1436 | ||
1437 | JSValue* dateProtoFuncSetMinutes(ExecState* exec, JSObject* thisObj, const List& args) | |
1438 | { | |
1439 | const bool inputIsUTC = false; | |
1440 | return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC); | |
1441 | } | |
1442 | ||
1443 | JSValue* dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject* thisObj, const List& args) | |
1444 | { | |
1445 | const bool inputIsUTC = true; | |
1446 | return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC); | |
1447 | } | |
1448 | ||
1449 | JSValue* dateProtoFuncSetHours(ExecState* exec, JSObject* thisObj, const List& args) | |
1450 | { | |
1451 | const bool inputIsUTC = false; | |
1452 | return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC); | |
1453 | } | |
1454 | ||
1455 | JSValue* dateProtoFuncSetUTCHours(ExecState* exec, JSObject* thisObj, const List& args) | |
1456 | { | |
1457 | const bool inputIsUTC = true; | |
1458 | return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC); | |
1459 | } | |
1460 | ||
1461 | JSValue* dateProtoFuncSetDate(ExecState* exec, JSObject* thisObj, const List& args) | |
1462 | { | |
1463 | const bool inputIsUTC = false; | |
1464 | return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC); | |
1465 | } | |
1466 | ||
1467 | JSValue* dateProtoFuncSetUTCDate(ExecState* exec, JSObject* thisObj, const List& args) | |
1468 | { | |
1469 | const bool inputIsUTC = true; | |
1470 | return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC); | |
1471 | } | |
1472 | ||
1473 | JSValue* dateProtoFuncSetMonth(ExecState* exec, JSObject* thisObj, const List& args) | |
1474 | { | |
1475 | const bool inputIsUTC = false; | |
1476 | return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC); | |
1477 | } | |
1478 | ||
1479 | JSValue* dateProtoFuncSetUTCMonth(ExecState* exec, JSObject* thisObj, const List& args) | |
1480 | { | |
1481 | const bool inputIsUTC = true; | |
1482 | return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC); | |
1483 | } | |
1484 | ||
1485 | JSValue* dateProtoFuncSetFullYear(ExecState* exec, JSObject* thisObj, const List& args) | |
1486 | { | |
1487 | const bool inputIsUTC = false; | |
1488 | return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC); | |
1489 | } | |
1490 | ||
1491 | JSValue* dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject* thisObj, const List& args) | |
1492 | { | |
1493 | const bool inputIsUTC = true; | |
1494 | return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC); | |
1495 | } | |
1496 | ||
1497 | JSValue* dateProtoFuncSetYear(ExecState* exec, JSObject* thisObj, const List& args) | |
1498 | { | |
1499 | if (!thisObj->inherits(&DateInstance::info)) | |
1500 | return throwError(exec, TypeError); | |
1501 | ||
1502 | const bool utc = false; | |
1503 | ||
1504 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1505 | JSValue* v = thisDateObj->internalValue(); | |
1506 | double milli = v->toNumber(exec); | |
1507 | double secs = floor(milli / msPerSecond); | |
1508 | double ms = milli - secs * msPerSecond; | |
1509 | ||
1510 | GregorianDateTime t; | |
1511 | msToGregorianDateTime(milli, utc, t); | |
1512 | ||
1513 | t.year = (args[0]->toInt32(exec) > 99 || args[0]->toInt32(exec) < 0) ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec); | |
1514 | ||
1515 | JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc)); | |
1516 | thisDateObj->setInternalValue(result); | |
1517 | return result; | |
1518 | } | |
1519 | ||
1520 | JSValue* dateProtoFuncGetYear(ExecState* exec, JSObject* thisObj, const List&) | |
1521 | { | |
1522 | if (!thisObj->inherits(&DateInstance::info)) | |
1523 | return throwError(exec, TypeError); | |
1524 | ||
1525 | const bool utc = false; | |
1526 | ||
1527 | DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj); | |
1528 | JSValue* v = thisDateObj->internalValue(); | |
1529 | double milli = v->toNumber(exec); | |
1530 | if (isnan(milli)) | |
1531 | return jsNaN(); | |
1532 | ||
1533 | GregorianDateTime t; | |
1534 | msToGregorianDateTime(milli, utc, t); | |
1535 | ||
1536 | // IE returns the full year even in getYear. | |
1537 | if (exec->dynamicGlobalObject()->compatMode() == IECompat) | |
1538 | return jsNumber(1900 + t.year); | |
1539 | return jsNumber(t.year); | |
1540 | } | |
1541 | ||
1542 | } // namespace KJS |