1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <math.h>
17
18 #include "jcontext.h"
19 #include "ecma-function-object.h"
20 #include "ecma-alloc.h"
21 #include "ecma-builtin-helpers.h"
22 #include "ecma-conversion.h"
23 #include "ecma-exceptions.h"
24 #include "ecma-gc.h"
25 #include "ecma-globals.h"
26 #include "ecma-helpers.h"
27 #include "ecma-try-catch-macro.h"
28 #include "lit-char-helpers.h"
29
30 #if ENABLED (JERRY_BUILTIN_DATE)
31
32 #define ECMA_BUILTINS_INTERNAL
33 #include "ecma-builtins-internal.h"
34
35 #define BUILTIN_INC_HEADER_NAME "ecma-builtin-date.inc.h"
36 #define BUILTIN_UNDERSCORED_ID date
37 #include "ecma-builtin-internal-routines-template.inc.h"
38
39 /** \addtogroup ecma ECMA
40 * @{
41 *
42 * \addtogroup ecmabuiltins
43 * @{
44 *
45 * \addtogroup date ECMA Date object built-in
46 * @{
47 */
48
49 /**
50 * Helper function to try to parse a part of a date string
51 *
52 * @return NaN if cannot read from string, ToNumber() otherwise
53 */
54 static ecma_number_t
ecma_date_parse_date_chars(const lit_utf8_byte_t ** str_p,const lit_utf8_byte_t * str_end_p,uint32_t num_of_chars,uint32_t min,uint32_t max)55 ecma_date_parse_date_chars (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
56 const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */
57 uint32_t num_of_chars, /**< number of characters to read and convert */
58 uint32_t min, /**< minimum valid value */
59 uint32_t max) /**< maximum valid value */
60 {
61 JERRY_ASSERT (num_of_chars > 0);
62 const lit_utf8_byte_t *str_start_p = *str_p;
63
64 while (num_of_chars--)
65 {
66 if (*str_p >= str_end_p || !lit_char_is_decimal_digit (lit_cesu8_read_next (str_p)))
67 {
68 return ecma_number_make_nan ();
69 }
70 }
71
72 ecma_number_t parsed_number = ecma_utf8_string_to_number (str_start_p, (lit_utf8_size_t) (*str_p - str_start_p));
73
74 if (parsed_number < min || parsed_number > max)
75 {
76 return ecma_number_make_nan ();
77 }
78
79 return parsed_number;
80 } /* ecma_date_parse_date_chars */
81
82 /**
83 * Helper function to try to parse a special chracter (+,-,T,Z,:,.) in a date string
84 *
85 * @return true if the first character is same as the expected, false otherwise
86 */
87 static bool
ecma_date_parse_special_char(const lit_utf8_byte_t ** str_p,const lit_utf8_byte_t * str_end_p,const lit_utf8_byte_t expected_char)88 ecma_date_parse_special_char (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
89 const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */
90 const lit_utf8_byte_t expected_char) /**< expected character */
91 {
92 if ((*str_p < str_end_p) && (**str_p == expected_char))
93 {
94 (*str_p)++;
95 return true;
96 }
97
98 return false;
99 } /* ecma_date_parse_special_char */
100
101 /**
102 * Helper function to try to parse a 4-5-6 digit year with optional negative sign in a date string
103 *
104 * Date.prototype.toString() and Date.prototype.toUTCString() emits year
105 * in this format and Date.parse() should parse this format too.
106 *
107 * @return the parsed year or NaN.
108 */
109 static ecma_number_t
ecma_date_parse_year(const lit_utf8_byte_t ** str_p,const lit_utf8_byte_t * str_end_p)110 ecma_date_parse_year (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
111 const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */
112 {
113 bool is_year_sign_negative = ecma_date_parse_special_char (str_p, str_end_p, '-');
114 const lit_utf8_byte_t *str_start_p = *str_p;
115 int32_t parsed_year = 0;
116
117 while ((str_start_p - *str_p < 6) && (str_start_p < str_end_p) && lit_char_is_decimal_digit (*str_start_p))
118 {
119 parsed_year = 10 * parsed_year + *str_start_p - LIT_CHAR_0;
120 str_start_p++;
121 }
122
123 if (str_start_p - *str_p >=4)
124 {
125 *str_p = str_start_p;
126 if (is_year_sign_negative)
127 {
128 return -parsed_year;
129 }
130 return parsed_year;
131 }
132
133 return ecma_number_make_nan ();
134 } /* ecma_date_parse_year */
135
136 /**
137 * Helper function to try to parse a day name in a date string
138 * Valid day names: Sun, Mon, Tue, Wed, Thu, Fri, Sat
139 * See also:
140 * ECMA-262 v9, 20.3.4.41.2 Table 46
141 *
142 * @return true if the string starts with a valid day name, false otherwise
143 */
144 static bool
ecma_date_parse_day_name(const lit_utf8_byte_t ** str_p,const lit_utf8_byte_t * str_end_p)145 ecma_date_parse_day_name (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
146 const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */
147 {
148 if (*str_p + 3 < str_end_p)
149 {
150 for (uint32_t i = 0; i < 7; i++)
151 {
152 if (!memcmp (day_names_p[i], *str_p, 3))
153 {
154 (*str_p) += 3;
155 return true;
156 }
157 }
158 }
159 return false;
160 } /* ecma_date_parse_day_name */
161
162 /**
163 * Helper function to try to parse a month name in a date string
164 * Valid month names: Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec
165 * See also:
166 * ECMA-262 v9, 20.3.4.41.2 Table 47
167 *
168 * @return number of the month if the string starts with a valid month name, 0 otherwise
169 */
170 static uint32_t
ecma_date_parse_month_name(const lit_utf8_byte_t ** str_p,const lit_utf8_byte_t * str_end_p)171 ecma_date_parse_month_name (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
172 const lit_utf8_byte_t *str_end_p) /**< pointer to the end of the string */
173 {
174 if (*str_p + 3 < str_end_p)
175 {
176 for (uint32_t i = 0; i < 12; i++)
177 {
178 if (!memcmp (month_names_p[i], *str_p, 3))
179 {
180 (*str_p) += 3;
181 return (i+1);
182 }
183 }
184 }
185 return 0;
186 } /* ecma_date_parse_month_name */
187
188 /**
189 * Calculate MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) for Date constructor and UTC
190 *
191 * See also:
192 * ECMA-262 v5, 15.9.3.1
193 * ECMA-262 v5, 15.9.4.3
194 *
195 * @return result of MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli))
196 */
197 static ecma_value_t
ecma_date_construct_helper(const ecma_value_t * args,ecma_length_t args_len)198 ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to the Date constructor */
199 ecma_length_t args_len) /**< number of arguments */
200 {
201 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
202 ecma_number_t prim_value = ecma_number_make_nan ();
203
204 ECMA_TRY_CATCH (year_value, ecma_op_to_number (args[0]), ret_value);
205 ECMA_TRY_CATCH (month_value, ecma_op_to_number (args[1]), ret_value);
206
207 ecma_number_t year = ecma_get_number_from_value (year_value);
208 ecma_number_t month = ecma_get_number_from_value (month_value);
209 ecma_number_t date = ECMA_NUMBER_ONE;
210 ecma_number_t hours = ECMA_NUMBER_ZERO;
211 ecma_number_t minutes = ECMA_NUMBER_ZERO;
212 ecma_number_t seconds = ECMA_NUMBER_ZERO;
213 ecma_number_t milliseconds = ECMA_NUMBER_ZERO;
214
215 /* 3. */
216 if (args_len >= 3 && ecma_is_value_empty (ret_value))
217 {
218 ECMA_TRY_CATCH (date_value, ecma_op_to_number (args[2]), ret_value);
219 date = ecma_get_number_from_value (date_value);
220 ECMA_FINALIZE (date_value);
221 }
222
223 /* 4. */
224 if (args_len >= 4 && ecma_is_value_empty (ret_value))
225 {
226 ECMA_TRY_CATCH (hours_value, ecma_op_to_number (args[3]), ret_value);
227 hours = ecma_get_number_from_value (hours_value);
228 ECMA_FINALIZE (hours_value);
229 }
230
231 /* 5. */
232 if (args_len >= 5 && ecma_is_value_empty (ret_value))
233 {
234 ECMA_TRY_CATCH (minutes_value, ecma_op_to_number (args[4]), ret_value);
235 minutes = ecma_get_number_from_value (minutes_value);
236 ECMA_FINALIZE (minutes_value);
237 }
238
239 /* 6. */
240 if (args_len >= 6 && ecma_is_value_empty (ret_value))
241 {
242 ECMA_TRY_CATCH (seconds_value, ecma_op_to_number (args[5]), ret_value);
243 seconds = ecma_get_number_from_value (seconds_value);
244 ECMA_FINALIZE (seconds_value);
245 }
246
247 /* 7. */
248 if (args_len >= 7 && ecma_is_value_empty (ret_value))
249 {
250 ECMA_TRY_CATCH (milliseconds_value, ecma_op_to_number (args[6]), ret_value);
251 milliseconds = ecma_get_number_from_value (milliseconds_value);
252 ECMA_FINALIZE (milliseconds_value);
253 }
254
255 if (ecma_is_value_empty (ret_value))
256 {
257 if (!ecma_number_is_nan (year))
258 {
259 /* 8. */
260 ecma_number_t y = ecma_number_trunc (year);
261
262 if (y >= 0 && y <= 99)
263 {
264 year = 1900 + y;
265 }
266 }
267
268 prim_value = ecma_date_make_date (ecma_date_make_day (year,
269 month,
270 date),
271 ecma_date_make_time (hours,
272 minutes,
273 seconds,
274 milliseconds));
275 }
276
277 ECMA_FINALIZE (month_value);
278 ECMA_FINALIZE (year_value);
279
280 if (ecma_is_value_empty (ret_value))
281 {
282 ret_value = ecma_make_number_value (prim_value);
283 }
284
285 return ret_value;
286 } /* ecma_date_construct_helper */
287
288 /**
289 * Helper function used by ecma_builtin_date_parse
290 *
291 * See also:
292 * ECMA-262 v5, 15.9.4.2 Date.parse (string)
293 * ECMA-262 v5, 15.9.1.15 Date Time String Format
294 *
295 * @return the parsed date as ecma_number_t or NaN otherwise
296 */
297 static ecma_number_t
ecma_builtin_date_parse_ISO_string_format(const lit_utf8_byte_t * date_str_curr_p,const lit_utf8_byte_t * date_str_end_p)298 ecma_builtin_date_parse_ISO_string_format (const lit_utf8_byte_t *date_str_curr_p,
299 const lit_utf8_byte_t *date_str_end_p)
300 {
301 /* 1. read year */
302
303 uint32_t year_digits = 4;
304
305 bool is_year_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-');
306 if (is_year_sign_negative || ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+'))
307 {
308 year_digits = 6;
309 }
310
311 ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, year_digits,
312 0, (year_digits == 4) ? 9999 : 999999);
313 if (is_year_sign_negative)
314 {
315 year = -year;
316 }
317
318 if (!ecma_number_is_nan (year))
319 {
320 ecma_number_t month = ECMA_NUMBER_ONE;
321 ecma_number_t day = ECMA_NUMBER_ONE;
322 ecma_number_t time = ECMA_NUMBER_ZERO;
323
324 /* 2. read month if any */
325 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'))
326 {
327 month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 12);
328 }
329
330 /* 3. read day if any */
331 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'))
332 {
333 day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 31);
334 }
335
336 /* 4. read time if any */
337 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'T'))
338 {
339 ecma_number_t hours = ECMA_NUMBER_ZERO;
340 ecma_number_t minutes = ECMA_NUMBER_ZERO;
341 ecma_number_t seconds = ECMA_NUMBER_ZERO;
342 ecma_number_t milliseconds = ECMA_NUMBER_ZERO;
343
344 ecma_length_t remaining_length = lit_utf8_string_length (date_str_curr_p,
345 (lit_utf8_size_t) (date_str_end_p - date_str_curr_p));
346
347 if (remaining_length >= 5)
348 {
349 /* 4.1 read hours and minutes */
350 hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
351
352 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':'))
353 {
354 minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
355
356 /* 4.2 read seconds if any */
357 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':'))
358 {
359 seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
360
361 /* 4.3 read milliseconds if any */
362 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '.'))
363 {
364 milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3, 0, 999);
365 }
366 }
367 }
368 else
369 {
370 minutes = ecma_number_make_nan ();
371 }
372
373 if (hours == 24 && (minutes != 0 || seconds != 0 || milliseconds != 0))
374 {
375 hours = ecma_number_make_nan ();
376 }
377
378 time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
379 }
380 else
381 {
382 time = ecma_number_make_nan ();
383 }
384
385 /* 4.4 read timezone if any */
386 if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'Z') && !ecma_number_is_nan (time))
387 {
388 time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
389 }
390 else
391 {
392 bool is_timezone_sign_negative;
393 if ((lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) == 6)
394 && ((is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-'))
395 || ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+')))
396 {
397 /* read hours and minutes */
398 hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
399
400 if (hours == 24)
401 {
402 hours = ECMA_NUMBER_ZERO;
403 }
404
405 ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':');
406 minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
407 ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
408 time += is_timezone_sign_negative ? timezone_offset : -timezone_offset;
409 }
410 }
411 }
412
413 if (date_str_curr_p >= date_str_end_p)
414 {
415 ecma_number_t date = ecma_date_make_day (year, month - 1, day);
416 return ecma_date_make_date (date, time);
417 }
418 }
419 return ecma_number_make_nan ();
420 } /* ecma_builtin_date_parse_ISO_string_format */
421
422 /**
423 * Helper function used by ecma_builtin_date_parse
424 *
425 * See also:
426 * ECMA-262 v5, 15.9.4.2 Date.parse (string)
427 * ECMA-262 v9, 20.3.4.41 Date.prototype.toString ()
428 * ECMA-262 v9, 20.3.4.43 Date.prototype.toUTCString ()
429 *
430 * Used by: ecma_builtin_date_parse
431 *
432 * @return the parsed date as ecma_number_t or NaN otherwise
433 */
434 static ecma_number_t
ecma_builtin_date_parse_toString_formats(const lit_utf8_byte_t * date_str_curr_p,const lit_utf8_byte_t * date_str_end_p)435 ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p,
436 const lit_utf8_byte_t *date_str_end_p)
437 {
438 const ecma_number_t nan = ecma_number_make_nan ();
439
440 if (!ecma_date_parse_day_name (&date_str_curr_p, date_str_end_p))
441 {
442 return nan;
443 }
444
445 const bool is_toUTCString_format = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ',');
446
447 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' '))
448 {
449 return nan;
450 }
451
452 ecma_number_t month = 0;
453 ecma_number_t day = 0;
454 if (is_toUTCString_format)
455 {
456 day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 31);
457 if (ecma_number_is_nan (day))
458 {
459 return nan;
460 }
461
462 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' '))
463 {
464 return nan;
465 }
466
467 month = ecma_date_parse_month_name (&date_str_curr_p, date_str_end_p);
468 if (!(int) month)
469 {
470 return nan;
471 }
472 }
473 else
474 {
475 month = ecma_date_parse_month_name (&date_str_curr_p, date_str_end_p);
476 if (!(int) month)
477 {
478 return nan;
479 }
480
481 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' '))
482 {
483 return nan;
484 }
485
486 day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 31);
487 if (ecma_number_is_nan (day))
488 {
489 return nan;
490 }
491 }
492
493 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' '))
494 {
495 return nan;
496 }
497
498 ecma_number_t year = ecma_date_parse_year (&date_str_curr_p, date_str_end_p);
499 if (ecma_number_is_nan (year))
500 {
501 return nan;
502 }
503
504 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' '))
505 {
506 return nan;
507 }
508
509 ecma_number_t hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
510 if (ecma_number_is_nan (hours))
511 {
512 return nan;
513 }
514
515 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':'))
516 {
517 return nan;
518 }
519
520 ecma_number_t minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
521 if (ecma_number_is_nan (minutes))
522 {
523 return nan;
524 }
525
526 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ':'))
527 {
528 return nan;
529 }
530
531 ecma_number_t seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
532 if (ecma_number_is_nan (seconds))
533 {
534 return nan;
535 }
536
537 if (hours == 24 && (minutes != 0 || seconds != 0))
538 {
539 return nan;
540 }
541
542 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, ' '))
543 {
544 return nan;
545 }
546
547 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'G'))
548 {
549 return nan;
550 }
551
552 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'M'))
553 {
554 return nan;
555 }
556
557 if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, 'T'))
558 {
559 return nan;
560 }
561
562 ecma_number_t time = ecma_date_make_time (hours, minutes, seconds, 0);
563
564 if (!is_toUTCString_format)
565 {
566 bool is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '-');
567 if (!is_timezone_sign_negative && !ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, '+'))
568 {
569 return nan;
570 }
571
572 hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
573 if (ecma_number_is_nan (hours))
574 {
575 return nan;
576 }
577 if (hours == 24)
578 {
579 hours = ECMA_NUMBER_ZERO;
580 }
581
582 minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
583 if (ecma_number_is_nan (minutes))
584 {
585 return nan;
586 }
587
588 ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
589 time += is_timezone_sign_negative ? timezone_offset : -timezone_offset;
590 }
591
592 if (date_str_curr_p >= date_str_end_p)
593 {
594 ecma_number_t date = ecma_date_make_day (year, month - 1, day);
595 return ecma_date_make_date (date, time);
596 }
597
598 return nan;
599 } /* ecma_builtin_date_parse_toString_formats */
600
601 /**
602 * The Date object's 'parse' routine
603 *
604 * See also:
605 * ECMA-262 v5, 15.9.4.2 Date.parse (string)
606 * ECMA-262 v5, 15.9.1.15 Date Time String Format
607 * ECMA-262 v9, 20.3.4.41 Date.prototype.toString ()
608 * ECMA-262 v9, 20.3.4.43 Date.prototype.toUTCString ()
609 *
610 * @return ecma value
611 * Returned value must be freed with ecma_free_value.
612 */
613 static ecma_value_t
ecma_builtin_date_parse(ecma_value_t this_arg,ecma_value_t arg)614 ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */
615 ecma_value_t arg) /**< string */
616 {
617 JERRY_UNUSED (this_arg);
618
619 /* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */
620 ecma_string_t *date_str_p = ecma_op_to_string (arg);
621 if (JERRY_UNLIKELY (date_str_p == NULL))
622 {
623 return ECMA_VALUE_ERROR;
624 }
625
626 ECMA_STRING_TO_UTF8_STRING (date_str_p, date_start_p, date_start_size);
627 const lit_utf8_byte_t *date_str_curr_p = date_start_p;
628 const lit_utf8_byte_t *date_str_end_p = date_start_p + date_start_size;
629
630 // try to parse date string as ISO string - ECMA-262 v5, 15.9.1.15
631 ecma_number_t ret_value = ecma_builtin_date_parse_ISO_string_format (date_str_curr_p, date_str_end_p);
632
633 if (ecma_number_is_nan (ret_value))
634 {
635 // try to parse date string in Date.prototype.toString() or toUTCString() format
636 ret_value = ecma_builtin_date_parse_toString_formats (date_str_curr_p, date_str_end_p);
637 }
638
639 ECMA_FINALIZE_UTF8_STRING (date_start_p, date_start_size);
640 ecma_deref_ecma_string (date_str_p);
641 return ecma_make_number_value (ret_value);
642 } /* ecma_builtin_date_parse */
643
644 /**
645 * The Date object's 'UTC' routine
646 *
647 * See also:
648 * ECMA-262 v5, 15.9.4.3
649 *
650 * @return ecma value
651 * Returned value must be freed with ecma_free_value.
652 */
653 static ecma_value_t
ecma_builtin_date_utc(ecma_value_t this_arg,const ecma_value_t args[],ecma_length_t args_number)654 ecma_builtin_date_utc (ecma_value_t this_arg, /**< this argument */
655 const ecma_value_t args[], /**< arguments list */
656 ecma_length_t args_number) /**< number of arguments */
657 {
658 JERRY_UNUSED (this_arg);
659 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
660
661 if (args_number < 2)
662 {
663 /* Note:
664 * When the UTC function is called with fewer than two arguments,
665 * the behaviour is implementation-dependent, so just return NaN.
666 */
667 return ecma_make_number_value (ecma_number_make_nan ());
668 }
669
670 ECMA_TRY_CATCH (time_value, ecma_date_construct_helper (args, args_number), ret_value);
671
672 ecma_number_t time = ecma_get_number_from_value (time_value);
673 ret_value = ecma_make_number_value (ecma_date_time_clip (time));
674
675 ECMA_FINALIZE (time_value);
676
677 return ret_value;
678 } /* ecma_builtin_date_utc */
679
680 /**
681 * The Date object's 'now' routine
682 *
683 * See also:
684 * ECMA-262 v5, 15.9.4.4
685 *
686 * @return ecma value
687 * Returned value must be freed with ecma_free_value.
688 */
689 static ecma_value_t
ecma_builtin_date_now(ecma_value_t this_arg)690 ecma_builtin_date_now (ecma_value_t this_arg) /**< this argument */
691 {
692 JERRY_UNUSED (this_arg);
693 return ecma_make_number_value (floor (DOUBLE_TO_ECMA_NUMBER_T (jerry_port_get_current_time ())));
694 } /* ecma_builtin_date_now */
695
696 /**
697 * Handle calling [[Call]] of built-in Date object
698 *
699 * See also:
700 * ECMA-262 v5, 15.9.2.1
701 *
702 * @return ecma value
703 */
704 ecma_value_t
ecma_builtin_date_dispatch_call(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)705 ecma_builtin_date_dispatch_call (const ecma_value_t *arguments_list_p, /**< arguments list */
706 ecma_length_t arguments_list_len) /**< number of arguments */
707 {
708 JERRY_UNUSED (arguments_list_p);
709 JERRY_UNUSED (arguments_list_len);
710 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
711
712 ECMA_TRY_CATCH (now_val,
713 ecma_builtin_date_now (ECMA_VALUE_UNDEFINED),
714 ret_value);
715
716 ret_value = ecma_date_value_to_string (ecma_get_number_from_value (now_val));
717
718 ECMA_FINALIZE (now_val);
719
720 return ret_value;
721 } /* ecma_builtin_date_dispatch_call */
722
723 /**
724 * Handle calling [[Construct]] of built-in Date object
725 *
726 * See also:
727 * ECMA-262 v5, 15.9.3.1
728 *
729 * @return ecma value
730 */
731 ecma_value_t
ecma_builtin_date_dispatch_construct(const ecma_value_t * arguments_list_p,ecma_length_t arguments_list_len)732 ecma_builtin_date_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
733 ecma_length_t arguments_list_len) /**< number of arguments */
734 {
735 ecma_value_t ret_value = ECMA_VALUE_EMPTY;
736 ecma_number_t prim_value_num = ECMA_NUMBER_ZERO;
737
738 ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_DATE_PROTOTYPE);
739 #if ENABLED (JERRY_ES2015)
740 if (JERRY_CONTEXT (current_new_target))
741 {
742 prototype_obj_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target),
743 ECMA_BUILTIN_ID_DATE_PROTOTYPE);
744 if (JERRY_UNLIKELY (prototype_obj_p == NULL))
745 {
746 return ECMA_VALUE_ERROR;
747 }
748 }
749 #endif /* !(ENABLED (JERRY_ES2015) */
750 ecma_object_t *obj_p = ecma_create_object (prototype_obj_p,
751 sizeof (ecma_extended_object_t),
752 ECMA_OBJECT_TYPE_CLASS);
753
754 ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
755 ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED;
756
757 if (arguments_list_len == 0)
758 {
759 ECMA_TRY_CATCH (parse_res_value,
760 ecma_builtin_date_now (ecma_make_object_value (obj_p)),
761 ret_value);
762
763 prim_value_num = ecma_get_number_from_value (parse_res_value);
764
765 ECMA_FINALIZE (parse_res_value)
766 }
767 else if (arguments_list_len == 1)
768 {
769 ECMA_TRY_CATCH (prim_comp_value,
770 ecma_op_to_primitive (arguments_list_p[0], ECMA_PREFERRED_TYPE_NUMBER),
771 ret_value);
772
773 if (ecma_is_value_string (prim_comp_value))
774 {
775 ECMA_TRY_CATCH (parse_res_value,
776 ecma_builtin_date_parse (ecma_make_object_value (obj_p), prim_comp_value),
777 ret_value);
778
779 prim_value_num = ecma_get_number_from_value (parse_res_value);
780
781 ECMA_FINALIZE (parse_res_value);
782 }
783 else
784 {
785 ECMA_TRY_CATCH (prim_value, ecma_op_to_number (arguments_list_p[0]), ret_value);
786
787 prim_value_num = ecma_date_time_clip (ecma_get_number_from_value (prim_value));
788
789 ECMA_FINALIZE (prim_value);
790 }
791
792 ECMA_FINALIZE (prim_comp_value);
793 }
794 else
795 {
796 ECMA_TRY_CATCH (time_value,
797 ecma_date_construct_helper (arguments_list_p, arguments_list_len),
798 ret_value);
799
800 ecma_number_t time = ecma_get_number_from_value (time_value);
801 prim_value_num = ecma_date_time_clip (ecma_date_utc (time));
802
803 ECMA_FINALIZE (time_value);
804 }
805
806 if (ecma_is_value_empty (ret_value))
807 {
808 if (!ecma_number_is_nan (prim_value_num) && ecma_number_is_infinity (prim_value_num))
809 {
810 prim_value_num = ecma_number_make_nan ();
811 }
812
813 ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_DATE_UL;
814
815 ecma_number_t *date_num_p = ecma_alloc_number ();
816 *date_num_p = prim_value_num;
817 ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, date_num_p);
818
819 ret_value = ecma_make_object_value (obj_p);
820 }
821 else
822 {
823 JERRY_ASSERT (ECMA_IS_VALUE_ERROR (ret_value));
824 ecma_deref_object (obj_p);
825 }
826 #if ENABLED (JERRY_ES2015)
827 if (JERRY_CONTEXT (current_new_target))
828 {
829 ecma_deref_object (prototype_obj_p);
830 }
831 #endif /* !(ENABLED (JERRY_ES2015) */
832 return ret_value;
833 } /* ecma_builtin_date_dispatch_construct */
834
835 /**
836 * @}
837 * @}
838 * @}
839 */
840
841 #undef BREAK_IF_FALSE
842 #undef BREAK_IF_NAN
843
844 #endif /* ENABLED (JERRY_BUILTIN_DATE) */
845