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 */
54static ecma_number_t
55ecma_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 */
87static bool
88ecma_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 */
109static ecma_number_t
110ecma_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 */
144static bool
145ecma_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 */
170static uint32_t
171ecma_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  */
197static ecma_value_t
198ecma_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 */
297static ecma_number_t
298ecma_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 */
434static ecma_number_t
435ecma_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 */
613static ecma_value_t
614ecma_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 */
653static ecma_value_t
654ecma_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 */
689static ecma_value_t
690ecma_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 */
704ecma_value_t
705ecma_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 */
731ecma_value_t
732ecma_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