Improve date internals (#4593)

- Optimize year from time calculation
- Force arithmetic operations to int32_t/int64_t whenever possible
- Optimize number conversion in date parse
- Cache local TZA of the date object
- Fix a bug in Date.parse timezone parsing

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik robert.fancsik@h-lab.eu
This commit is contained in:
Robert Fancsik 2021-02-17 16:07:54 +01:00 committed by GitHub
parent 67e7e89c8e
commit 488a0bf7e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 810 additions and 785 deletions

View File

@ -1577,9 +1577,12 @@ ecma_gc_free_object (ecma_object_t *object_p) /**< object to free */
case LIT_MAGIC_STRING_DATE_UL:
{
ecma_number_t *num_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t,
ext_object_p->u.class_prop.u.value);
#if JERRY_ESNEXT
ext_object_size = sizeof (ecma_date_object_t);
#else /* !JERRY_ESNEXT */
ecma_number_t *num_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.date);
ecma_dealloc_number (num_p);
#endif /* JERRY_ESNEXT */
break;
}
case LIT_MAGIC_STRING_REGEXP_UL:

View File

@ -945,6 +945,8 @@ typedef struct
union
{
ecma_value_t value; /**< value of the object (e.g. boolean, number, string, etc.) */
ecma_value_t date; /**< Date object [[DateValue]] internal property */
int32_t tza; /**< TimeZone adjustment for date objects */
uint32_t length; /**< length related property (e.g. length of ArrayBuffer) */
ecma_value_t target; /**< [[ProxyTarget]] internal property */
ecma_value_t head; /**< points to the async generator task queue head item */
@ -2313,6 +2315,28 @@ typedef struct
} u;
} ecma_mapped_arguments_t;
#if JERRY_ESNEXT
/**
* Date object descriptor flags
*/
typedef enum
{
ECMA_DATE_TZA_NONE = 0,
ECMA_DATE_TZA_SET = 1 << 0,
} ecma_date_object_flags_t;
/**
* Definition of date object
*/
typedef struct
{
ecma_extended_object_t header; /**< object header */
ecma_number_t date_value; /**< [[DateValue]] internal property */
} ecma_date_object_t;
#endif /* JERRY_ESNEXT */
/**
* @}
* @}

View File

@ -227,84 +227,82 @@ ecma_builtin_date_prototype_to_primitive (ecma_value_t this_arg, /**< this argum
static ecma_value_t
ecma_builtin_date_prototype_dispatch_get (uint16_t builtin_routine_id, /**< built-in wide routine
* identifier */
ecma_number_t date_num) /**< date converted to number */
ecma_number_t date_value) /**< date converted to number */
{
if (ecma_number_is_nan (date_num))
if (ecma_number_is_nan (date_value))
{
return ecma_make_nan_value ();
}
int32_t result;
switch (builtin_routine_id)
{
case ECMA_DATE_PROTOTYPE_GET_FULL_YEAR:
case ECMA_DATE_PROTOTYPE_GET_UTC_FULL_YEAR:
#if JERRY_BUILTIN_ANNEXB
case ECMA_DATE_PROTOTYPE_GET_YEAR:
#endif /* JERRY_BUILTIN_ANNEXB */
{
date_num = ecma_date_year_from_time (date_num);
#if JERRY_BUILTIN_ANNEXB
if (builtin_routine_id == ECMA_DATE_PROTOTYPE_GET_YEAR)
{
date_num -= 1900;
}
#endif /* JERRY_BUILTIN_ANNEXB */
result = ecma_date_year_from_time (date_value);
break;
}
#if JERRY_BUILTIN_ANNEXB
case ECMA_DATE_PROTOTYPE_GET_YEAR:
{
result = (ecma_date_year_from_time (date_value) - 1900);
break;
}
#endif /* JERRY_BUILTIN_ANNEXB */
case ECMA_DATE_PROTOTYPE_GET_MONTH:
case ECMA_DATE_PROTOTYPE_GET_UTC_MONTH:
{
date_num = ecma_date_month_from_time (date_num);
result = ecma_date_month_from_time (date_value);
break;
}
case ECMA_DATE_PROTOTYPE_GET_DATE:
case ECMA_DATE_PROTOTYPE_GET_UTC_DATE:
{
date_num = ecma_date_date_from_time (date_num);
result = ecma_date_date_from_time (date_value);
break;
}
case ECMA_DATE_PROTOTYPE_GET_DAY:
case ECMA_DATE_PROTOTYPE_GET_UTC_DAY:
{
date_num = ecma_date_week_day (date_num);
result = ecma_date_week_day (date_value);
break;
}
case ECMA_DATE_PROTOTYPE_GET_HOURS:
case ECMA_DATE_PROTOTYPE_GET_UTC_HOURS:
{
date_num = ecma_date_hour_from_time (date_num);
result = ecma_date_hour_from_time (date_value);
break;
}
case ECMA_DATE_PROTOTYPE_GET_MINUTES:
case ECMA_DATE_PROTOTYPE_GET_UTC_MINUTES:
{
date_num = ecma_date_min_from_time (date_num);
result = ecma_date_min_from_time (date_value);
break;
}
case ECMA_DATE_PROTOTYPE_GET_SECONDS:
case ECMA_DATE_PROTOTYPE_GET_UTC_SECONDS:
{
date_num = ecma_date_sec_from_time (date_num);
result = ecma_date_sec_from_time (date_value);
break;
}
case ECMA_DATE_PROTOTYPE_GET_MILLISECONDS:
case ECMA_DATE_PROTOTYPE_GET_UTC_MILLISECONDS:
{
date_num = ecma_date_ms_from_time (date_num);
result = ecma_date_ms_from_time (date_value);
break;
}
default:
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_GET_UTC_TIMEZONE_OFFSET);
date_num = ecma_date_timezone_offset (date_num);
result = (int32_t) ((-ecma_date_local_time_zone_adjustment (date_value)) / ECMA_DATE_MS_PER_MINUTE);
break;
}
}
return ecma_make_number_value (date_num);
return ecma_make_int32_value (result);
} /* ecma_builtin_date_prototype_dispatch_get */
#if JERRY_BUILTIN_ANNEXB
@ -337,8 +335,7 @@ ecma_builtin_date_prototype_dispatch_get (uint16_t builtin_routine_id, /**< buil
static ecma_value_t
ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< built-in wide routine
* identifier */
ecma_extended_object_t *ext_object_p, /**< date extended object */
ecma_number_t date_num, /**< date converted to number */
ecma_object_t *object_p, /**< date object */
const ecma_value_t arguments_list[], /**< list of arguments
* passed to routine */
uint32_t arguments_number) /**< length of arguments' list */
@ -403,28 +400,55 @@ ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< buil
}
}
#if JERRY_ESNEXT
ecma_date_object_t *date_object_p = (ecma_date_object_t *) object_p;
ecma_number_t *date_value_p = &date_object_p->date_value;
#else /* !JERRY_ESNEXT */
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p;
ecma_number_t *date_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.date);
#endif /* JERRY_ESNEXT */
ecma_number_t date_value = *date_value_p;
if (!BUILTIN_DATE_FUNCTION_IS_UTC (builtin_routine_id))
{
ecma_number_t local_tza;
#if JERRY_ESNEXT
if (date_object_p->header.u.class_prop.extra_info & ECMA_DATE_TZA_SET)
{
local_tza = date_object_p->header.u.class_prop.u.tza;
JERRY_ASSERT (local_tza == ecma_date_local_time_zone_adjustment (date_value));
}
else
#endif /* JERRY_ESNEXT */
{
local_tza = ecma_date_local_time_zone_adjustment (date_value);
}
date_value += local_tza;
}
ecma_number_t day_part;
ecma_number_t time_part;
if (builtin_routine_id <= ECMA_DATE_PROTOTYPE_SET_UTC_DATE)
{
if (ecma_number_is_nan (date_num))
if (ecma_number_is_nan (date_value))
{
if (ECMA_DATE_PROTOTYPE_IS_SET_YEAR_ROUTINE (builtin_routine_id))
if (!ECMA_DATE_PROTOTYPE_IS_SET_YEAR_ROUTINE (builtin_routine_id))
{
date_num = ECMA_NUMBER_ZERO;
}
else
{
return ecma_make_number_value (date_num);
return ecma_make_number_value (date_value);
}
date_value = ECMA_NUMBER_ZERO;
}
time_part = ecma_date_time_within_day (date_num);
time_part = ecma_date_time_in_day_from_time (date_value);
ecma_number_t year = ecma_date_year_from_time (date_num);
ecma_number_t month = ecma_date_month_from_time (date_num);
ecma_number_t day = ecma_date_date_from_time (date_num);
ecma_number_t year = ecma_date_year_from_time (date_value);
ecma_number_t month = ecma_date_month_from_time (date_value);
ecma_number_t day = ecma_date_date_from_time (date_value);
switch (builtin_routine_id)
{
@ -447,7 +471,7 @@ ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< buil
{
if (ecma_number_is_nan (converted_number[0]))
{
*ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.value) = converted_number[0];
*date_value_p = converted_number[0];
return ecma_make_number_value (converted_number[0]);
}
@ -494,17 +518,17 @@ ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< buil
}
else
{
if (ecma_number_is_nan (date_num))
if (ecma_number_is_nan (date_value))
{
return ecma_make_number_value (date_num);
return ecma_make_number_value (date_value);
}
day_part = ecma_date_day (date_num);
day_part = ecma_date_day_from_time (date_value) * (ecma_number_t) ECMA_DATE_MS_PER_DAY;
ecma_number_t hour = ecma_date_hour_from_time (date_num);
ecma_number_t min = ecma_date_min_from_time (date_num);
ecma_number_t sec = ecma_date_sec_from_time (date_num);
ecma_number_t ms = ecma_date_ms_from_time (date_num);
ecma_number_t hour = ecma_date_hour_from_time (date_value);
ecma_number_t min = ecma_date_min_from_time (date_value);
ecma_number_t sec = ecma_date_sec_from_time (date_value);
ecma_number_t ms = ecma_date_ms_from_time (date_value);
switch (builtin_routine_id)
{
@ -574,7 +598,11 @@ ecma_builtin_date_prototype_dispatch_set (uint16_t builtin_routine_id, /**< buil
full_date = ecma_date_time_clip (full_date);
*ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.value) = full_date;
*date_value_p = full_date;
#if JERRY_ESNEXT
date_object_p->header.u.class_prop.extra_info &= (uint16_t) ~ECMA_DATE_TZA_SET;
#endif /* JERRY_ESNEXT */
return ecma_make_number_value (full_date);
} /* ecma_builtin_date_prototype_dispatch_set */
@ -614,13 +642,22 @@ ecma_builtin_date_prototype_dispatch_routine (uint8_t builtin_routine_id, /**< b
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a Date object"));
}
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg);
ecma_number_t *prim_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t,
ext_object_p->u.class_prop.u.value);
ecma_object_t *this_obj_p = ecma_get_object_from_value (this_arg);
#if JERRY_ESNEXT
ecma_date_object_t *date_object_p = (ecma_date_object_t *) this_obj_p;
ecma_number_t *date_value_p = &date_object_p->date_value;
#else
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) this_obj_p;
ecma_number_t *date_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t,
ext_object_p->u.class_prop.u.date);
#endif
ecma_number_t date_value = *date_value_p;
if (builtin_routine_id == ECMA_DATE_PROTOTYPE_GET_TIME)
{
return ecma_make_number_value (*prim_value_p);
return ecma_make_number_value (date_value);
}
if (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_TIME)
@ -632,43 +669,59 @@ ecma_builtin_date_prototype_dispatch_routine (uint8_t builtin_routine_id, /**< b
return ECMA_VALUE_ERROR;
}
*prim_value_p = ecma_date_time_clip (time_num);
*date_value_p = ecma_date_time_clip (time_num);
return ecma_make_number_value (*prim_value_p);
return ecma_make_number_value (*date_value_p);
}
if (builtin_routine_id <= ECMA_DATE_PROTOTYPE_SET_UTC_MILLISECONDS)
{
ecma_number_t this_num = *prim_value_p;
if (!BUILTIN_DATE_FUNCTION_IS_UTC (builtin_routine_id))
{
this_num += ecma_date_local_time_zone_adjustment (this_num);
}
if (builtin_routine_id <= ECMA_DATE_PROTOTYPE_GET_UTC_TIMEZONE_OFFSET)
{
return ecma_builtin_date_prototype_dispatch_get (builtin_routine_id, this_num);
if (!BUILTIN_DATE_FUNCTION_IS_UTC (builtin_routine_id))
{
ecma_number_t local_tza;
#if JERRY_ESNEXT
if (date_object_p->header.u.class_prop.extra_info & ECMA_DATE_TZA_SET)
{
local_tza = date_object_p->header.u.class_prop.u.tza;
JERRY_ASSERT (local_tza == ecma_date_local_time_zone_adjustment (date_value));
}
else
{
#endif /* JERRY_ESNEXT */
local_tza = ecma_date_local_time_zone_adjustment (date_value);
#if JERRY_ESNEXT
JERRY_ASSERT (local_tza <= INT32_MAX && local_tza >= INT32_MIN);
date_object_p->header.u.class_prop.u.tza = (int32_t) local_tza;
date_object_p->header.u.class_prop.extra_info |= ECMA_DATE_TZA_SET;
}
#endif /* JERRY_ESNEXT */
date_value += local_tza;
}
return ecma_builtin_date_prototype_dispatch_get (builtin_routine_id, date_value);
}
return ecma_builtin_date_prototype_dispatch_set (builtin_routine_id,
ext_object_p,
this_num,
this_obj_p,
arguments_list,
arguments_number);
}
if (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_ISO_STRING)
{
if (ecma_number_is_nan (*prim_value_p) || ecma_number_is_infinity (*prim_value_p))
if (ecma_number_is_nan (date_value))
{
return ecma_raise_range_error (ECMA_ERR_MSG ("Date must be a finite number"));
}
return ecma_date_value_to_iso_string (*prim_value_p);
return ecma_date_value_to_iso_string (date_value);
}
if (ecma_number_is_nan (*prim_value_p))
if (ecma_number_is_nan (date_value))
{
return ecma_make_magic_string_value (LIT_MAGIC_STRING_INVALID_DATE_UL);
}
@ -677,23 +730,23 @@ ecma_builtin_date_prototype_dispatch_routine (uint8_t builtin_routine_id, /**< b
{
case ECMA_DATE_PROTOTYPE_TO_STRING:
{
return ecma_date_value_to_string (*prim_value_p);
return ecma_date_value_to_string (date_value);
}
case ECMA_DATE_PROTOTYPE_TO_DATE_STRING:
{
return ecma_date_value_to_date_string (*prim_value_p);
return ecma_date_value_to_date_string (date_value);
}
#if !JERRY_ESNEXT
case ECMA_DATE_PROTOTYPE_TO_UTC_STRING:
{
return ecma_date_value_to_utc_string (*prim_value_p);
return ecma_date_value_to_utc_string (date_value);
}
#endif /* JERRY_ESNEXT */
default:
{
JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_TIME_STRING);
return ecma_date_value_to_time_string (*prim_value_p);
return ecma_date_value_to_time_string (date_value);
}
}
} /* ecma_builtin_date_prototype_dispatch_routine */

View File

@ -31,6 +31,22 @@
#define ECMA_BUILTINS_INTERNAL
#include "ecma-builtins-internal.h"
/**
* This object has a custom dispatch function.
*/
#define BUILTIN_CUSTOM_DISPATCH
/**
* List of built-in routine identifiers.
*/
enum
{
ECMA_DATE_ROUTINE_START = 0,
ECMA_DATE_ROUTINE_PARSE,
ECMA_DATE_ROUTINE_UTC,
ECMA_DATE_ROUTINE_NOW,
};
#define BUILTIN_INC_HEADER_NAME "ecma-builtin-date.inc.h"
#define BUILTIN_UNDERSCORED_ID date
#include "ecma-builtin-internal-routines-template.inc.h"
@ -45,6 +61,26 @@
* @{
*/
/**
* Encode minimum/maximum limits
*
* See: ecma_date_parse_date_chars
*
* @param min: 8 bits unsigned number
* @param max: 24 bits unsigned number
*/
#define ECMA_DATE_LIMIT(min, max) (min << 24 | max)
/**
* Decode the minimum value from the encoded limit
*/
#define ECMA_DATE_LIMIT_MIN(limit) (limit >> 24)
/**
* Decode the maximum value from the encoded limit
*/
#define ECMA_DATE_LIMIT_MAX(limit) (limit & ((1 << 24) - 1))
/**
* Helper function to try to parse a part of a date string
*
@ -54,28 +90,37 @@ static ecma_number_t
ecma_date_parse_date_chars (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 string */
const lit_utf8_byte_t *str_end_p, /**< pointer to the end of the string */
uint32_t num_of_chars, /**< number of characters to read and convert */
uint32_t min, /**< minimum valid value */
uint32_t max) /**< maximum valid value */
uint32_t limit) /**< minimum/maximum valid value */
{
JERRY_ASSERT (num_of_chars > 0);
const lit_utf8_byte_t *str_start_p = *str_p;
JERRY_ASSERT (num_of_chars > 0 && num_of_chars <= 6);
while (num_of_chars--)
{
if (*str_p >= str_end_p || !lit_char_is_decimal_digit (lit_cesu8_read_next (str_p)))
{
return ecma_number_make_nan ();
}
}
ecma_number_t parsed_number = ecma_utf8_string_to_number (str_start_p, (lit_utf8_size_t) (*str_p - str_start_p), 0);
if (parsed_number < min || parsed_number > max)
if (*str_p + num_of_chars > str_end_p)
{
return ecma_number_make_nan ();
}
return parsed_number;
str_end_p = *str_p + num_of_chars;
uint32_t num = 0;
while (num_of_chars--)
{
lit_utf8_byte_t c = **str_p;
if (!lit_char_is_decimal_digit (c))
{
return ecma_number_make_nan ();
}
num = (num * 10) + (uint32_t) ((c - LIT_CHAR_0));
(*str_p)++;
}
if (num >= ECMA_DATE_LIMIT_MIN (limit) && num <= ECMA_DATE_LIMIT_MAX (limit))
{
return (ecma_number_t) num;
}
return ecma_number_make_nan ();
} /* ecma_date_parse_date_chars */
/**
@ -129,14 +174,10 @@ ecma_date_parse_year (const lit_utf8_byte_t **str_p, /**< pointer to the cesu8 s
str_start_p++;
}
if (str_start_p - *str_p >=4)
if (str_start_p - *str_p >= 4)
{
*str_p = str_start_p;
if (is_year_sign_negative)
{
return -parsed_year;
}
return parsed_year;
return is_year_sign_negative ? -parsed_year : parsed_year;
}
return ecma_number_make_nan ();
@ -187,7 +228,7 @@ ecma_date_parse_month_name (const lit_utf8_byte_t **str_p, /**< pointer to the c
if (!memcmp (month_names_p[i], *str_p, 3))
{
(*str_p) += 3;
return (i+1);
return (i + 1);
}
}
}
@ -198,14 +239,15 @@ ecma_date_parse_month_name (const lit_utf8_byte_t **str_p, /**< pointer to the c
* Calculate MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)) for Date constructor and UTC
*
* See also:
* ECMA-262 v5, 15.9.3.1
* ECMA-262 v5, 15.9.4.3
* ECMA-262 v11, 20.4.3.4
*
* @return result of MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli))
* @return false - if the operation fails
* true - otherwise
*/
static ecma_value_t
static bool
ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to the Date constructor */
uint32_t args_len) /**< number of arguments */
uint32_t args_len, /**< number of arguments */
ecma_number_t *tv_p) /**< [out] time value */
{
ecma_number_t date_nums[7] =
{
@ -227,32 +269,32 @@ ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to t
if (ECMA_IS_VALUE_ERROR (status))
{
return status;
return false;
}
}
ecma_number_t prim_value = ecma_number_make_nan ();
/* 8. */
if (!ecma_number_is_nan (date_nums[0]))
{
/* 8. */
ecma_number_t y = ecma_number_trunc (date_nums[0]);
/* 9.a */
ecma_number_t yi = ecma_number_trunc (date_nums[0]);
if (y >= 0 && y <= 99)
/* 9.b */
if (yi >= 0 && yi <= 99)
{
date_nums[0] = 1900 + y;
date_nums[0] = 1900 + yi;
}
}
prim_value = ecma_date_make_date (ecma_date_make_day (date_nums[0],
date_nums[1],
date_nums[2]),
ecma_date_make_time (date_nums[3],
date_nums[4],
date_nums[5],
date_nums[6]));
return ecma_make_number_value (prim_value);
/* 10. */
*tv_p = ecma_date_make_date (ecma_date_make_day (date_nums[0],
date_nums[1],
date_nums[2]),
ecma_date_make_time (date_nums[3],
date_nums[4],
date_nums[5],
date_nums[6]));
return true;
} /* ecma_date_construct_helper */
/**
@ -265,12 +307,13 @@ ecma_date_construct_helper (const ecma_value_t *args, /**< arguments passed to t
* @return the parsed date as ecma_number_t or NaN otherwise
*/
static ecma_number_t
ecma_builtin_date_parse_basic (const lit_utf8_byte_t *date_str_curr_p,
const lit_utf8_byte_t *date_str_end_p)
ecma_builtin_date_parse_basic (const lit_utf8_byte_t *date_str_curr_p, /**< date string start */
const lit_utf8_byte_t *date_str_end_p) /**< date string end */
{
/* 1. read year */
uint32_t year_digits = 4;
uint32_t year_limit = 9999;
bool is_year_sign_negative = false;
@ -278,132 +321,136 @@ ecma_builtin_date_parse_basic (const lit_utf8_byte_t *date_str_curr_p,
{
is_year_sign_negative = (*date_str_curr_p++ == LIT_CHAR_MINUS);
year_digits = 6;
year_limit = 999999;
}
ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, year_digits,
0, (year_digits == 4) ? 9999 : 999999);
ecma_number_t year = ecma_date_parse_date_chars (&date_str_curr_p,
date_str_end_p,
year_digits,
ECMA_DATE_LIMIT (0, year_limit));
if (is_year_sign_negative)
{
year = -year;
}
if (!ecma_number_is_nan (year))
if (ecma_number_is_nan (year))
{
ecma_number_t month = ECMA_NUMBER_ONE;
ecma_number_t day = ECMA_NUMBER_ONE;
ecma_number_t time = ECMA_NUMBER_ZERO;
return year;
}
/* 2. read month if any */
if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_SLASH))
ecma_number_t month = ECMA_NUMBER_ONE;
ecma_number_t day = ECMA_NUMBER_ONE;
ecma_number_t time = ECMA_NUMBER_ZERO;
/* 2. read month if any */
if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_SLASH))
{
lit_utf8_byte_t separator = *date_str_curr_p++;
month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (1, 12));
/* 3. read day if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, separator))
{
lit_utf8_byte_t separator = *date_str_curr_p++;
month = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 12);
/* 3. read day if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, separator))
{
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 1, 31);
}
}
bool is_utc = true;
/* 4. read time if any */
if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_T, LIT_CHAR_SP))
{
date_str_curr_p++;
ecma_number_t hours = ECMA_NUMBER_ZERO;
ecma_number_t minutes = ECMA_NUMBER_ZERO;
ecma_number_t seconds = ECMA_NUMBER_ZERO;
ecma_number_t milliseconds = ECMA_NUMBER_ZERO;
lit_utf8_size_t remaining_length = lit_utf8_string_length (date_str_curr_p,
(lit_utf8_size_t) (date_str_end_p - date_str_curr_p));
if (remaining_length >= 5)
{
/* 4.1 read hours and minutes */
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
/* 4.2 read seconds if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{
seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
/* 4.3 read milliseconds if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_DOT))
{
milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3, 0, 999);
}
}
}
else
{
minutes = ecma_number_make_nan ();
}
if (hours == 24 && (minutes != 0 || seconds != 0 || milliseconds != 0))
{
hours = ecma_number_make_nan ();
}
time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
}
else
{
time = ecma_number_make_nan ();
}
/* 4.4 read timezone if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_Z)
&& !ecma_number_is_nan (time))
{
time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
}
else
{
if (lit_utf8_string_length (date_str_curr_p, (lit_utf8_size_t) (date_str_end_p - date_str_curr_p)) == 6
&& ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_PLUS))
{
bool is_timezone_sign_negative = (*date_str_curr_p++ == LIT_CHAR_MINUS);
/* read hours and minutes */
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
if (hours == 24)
{
hours = ECMA_NUMBER_ZERO;
}
ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON);
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
time += is_timezone_sign_negative ? timezone_offset : -timezone_offset;
}
else
{
is_utc = false;
}
}
}
if (date_str_curr_p >= date_str_end_p)
{
ecma_number_t date = ecma_date_make_day (year, month - 1, day);
ecma_number_t result_date = ecma_date_make_date (date, time);
if (!is_utc)
{
result_date = ecma_date_utc (result_date);
}
return result_date;
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (1, 31));
}
}
return ecma_number_make_nan ();
bool is_utc = true;
/* 4. read time if any */
if (ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_T, LIT_CHAR_SP))
{
date_str_curr_p++;
ecma_number_t hours = ECMA_NUMBER_ZERO;
ecma_number_t minutes = ECMA_NUMBER_ZERO;
ecma_number_t seconds = ECMA_NUMBER_ZERO;
ecma_number_t milliseconds = ECMA_NUMBER_ZERO;
/* 'HH:mm' must present */
if (date_str_end_p - date_str_curr_p < 5)
{
return ecma_number_make_nan ();
}
/* 4.1 read hours and minutes */
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 24));
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{
return ecma_number_make_nan ();
}
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 59));
/* 4.2 read seconds if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{
seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 59));
/* 4.3 read milliseconds if any */
if (ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_DOT))
{
milliseconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 3, ECMA_DATE_LIMIT (0, 999));
}
}
if (hours == 24 && (minutes != 0 || seconds != 0 || milliseconds != 0))
{
return ecma_number_make_nan ();
}
time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
if (ecma_number_is_nan (time))
{
return time;
}
/* 4.4 read timezone if any */
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_Z))
{
if ((date_str_end_p - date_str_curr_p) == 6
&& (*date_str_curr_p == LIT_CHAR_MINUS || *date_str_curr_p == LIT_CHAR_PLUS))
{
bool is_timezone_sign_negative = (*date_str_curr_p++ == LIT_CHAR_MINUS);
/* read hours and minutes */
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 24));
if (hours == 24)
{
hours = ECMA_NUMBER_ZERO;
}
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_COLON))
{
return ecma_number_make_nan ();
}
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 59));
ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
time += is_timezone_sign_negative ? timezone_offset : -timezone_offset;
}
else
{
is_utc = false;
}
}
}
if (date_str_curr_p < date_str_end_p)
{
return ecma_number_make_nan ();
}
ecma_number_t date = ecma_date_make_day (year, month - 1, day);
ecma_number_t result_date = ecma_date_make_date (date, time);
if (!is_utc)
{
result_date = ecma_date_utc (result_date);
}
return result_date;
} /* ecma_builtin_date_parse_basic */
/**
@ -440,7 +487,8 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
ecma_number_t day = 0;
if (is_toUTCString_format)
{
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 31);
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 31));
if (ecma_number_is_nan (day))
{
return nan;
@ -452,15 +500,17 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
}
month = ecma_date_parse_month_name (&date_str_curr_p, date_str_end_p);
if (!(int) month)
if (month == 0)
{
return nan;
return ecma_number_make_nan ();
}
}
else
{
month = ecma_date_parse_month_name (&date_str_curr_p, date_str_end_p);
if (!(int) month)
if (month == 0)
{
return nan;
}
@ -470,7 +520,8 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan;
}
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 31);
day = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 31));
if (ecma_number_is_nan (day))
{
return nan;
@ -483,6 +534,7 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
}
ecma_number_t year = ecma_date_parse_year (&date_str_curr_p, date_str_end_p);
if (ecma_number_is_nan (year))
{
return nan;
@ -493,7 +545,8 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan;
}
ecma_number_t hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
ecma_number_t hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 24));
if (ecma_number_is_nan (hours))
{
return nan;
@ -504,7 +557,8 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan;
}
ecma_number_t minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
ecma_number_t minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 59));
if (ecma_number_is_nan (minutes))
{
return nan;
@ -515,7 +569,8 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan;
}
ecma_number_t seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
ecma_number_t seconds = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 59));
if (ecma_number_is_nan (seconds))
{
return nan;
@ -526,63 +581,57 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
return nan;
}
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_SP))
const char gmt_p[] = " GMT";
if (date_str_end_p - date_str_curr_p < 4
|| memcmp (date_str_curr_p, gmt_p, 4) != 0)
{
return nan;
}
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_G))
{
return nan;
}
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_M))
{
return nan;
}
if (!ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_UPPERCASE_T))
{
return nan;
}
date_str_curr_p += 4;
ecma_number_t time = ecma_date_make_time (hours, minutes, seconds, 0);
if (!is_toUTCString_format)
{
bool is_timezone_sign_negative = ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS);
if (!is_timezone_sign_negative && !ecma_date_parse_special_char (&date_str_curr_p, date_str_end_p, LIT_CHAR_PLUS))
if (!ecma_date_check_two_chars (date_str_curr_p, date_str_end_p, LIT_CHAR_MINUS, LIT_CHAR_PLUS))
{
return nan;
}
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 24);
bool is_timezone_sign_negative = (*date_str_curr_p++ == LIT_CHAR_MINUS);
hours = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 24));
if (ecma_number_is_nan (hours))
{
return nan;
}
if (hours == 24)
{
hours = ECMA_NUMBER_ZERO;
}
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, 0, 59);
minutes = ecma_date_parse_date_chars (&date_str_curr_p, date_str_end_p, 2, ECMA_DATE_LIMIT (0, 59));
if (ecma_number_is_nan (minutes))
{
return nan;
}
ecma_number_t timezone_offset = ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
time += is_timezone_sign_negative ? timezone_offset : -timezone_offset;
}
if (date_str_curr_p >= date_str_end_p)
if (date_str_curr_p < date_str_end_p)
{
ecma_number_t date = ecma_date_make_day (year, month - 1, day);
return ecma_date_make_date (date, time);
return nan;
}
return nan;
ecma_number_t date = ecma_date_make_day (year, month - 1, day);
return ecma_date_make_date (date, time);
} /* ecma_builtin_date_parse_toString_formats */
/**
@ -594,38 +643,27 @@ ecma_builtin_date_parse_toString_formats (const lit_utf8_byte_t *date_str_curr_p
* ECMA-262 v9, 20.3.4.41 Date.prototype.toString ()
* ECMA-262 v9, 20.3.4.43 Date.prototype.toUTCString ()
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
* @return parsed time
*/
static ecma_value_t
ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */
ecma_value_t arg) /**< string */
static ecma_number_t
ecma_builtin_date_parse (ecma_string_t *string_p) /**< string */
{
JERRY_UNUSED (this_arg);
ECMA_STRING_TO_UTF8_STRING (string_p, str_p, str_size);
const lit_utf8_byte_t *date_str_curr_p = str_p;
const lit_utf8_byte_t *date_str_end_p = str_p + str_size;
/* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */
ecma_string_t *date_str_p = ecma_op_to_string (arg);
if (JERRY_UNLIKELY (date_str_p == NULL))
/* try to parse date string as ISO string - ECMA-262 v5, 15.9.1.15 */
ecma_number_t tv = ecma_builtin_date_parse_basic (date_str_curr_p, date_str_end_p);
if (ecma_number_is_nan (tv))
{
return ECMA_VALUE_ERROR;
/* try to parse date string in Date.prototype.toString() or toUTCString() format */
tv = ecma_builtin_date_parse_toString_formats (date_str_curr_p, date_str_end_p);
}
ECMA_STRING_TO_UTF8_STRING (date_str_p, date_start_p, date_start_size);
const lit_utf8_byte_t *date_str_curr_p = date_start_p;
const lit_utf8_byte_t *date_str_end_p = date_start_p + date_start_size;
ECMA_FINALIZE_UTF8_STRING (str_p, str_size);
// try to parse date string as ISO string and allow some variants - ECMA-262 v5, 15.9.1.15
ecma_number_t ret_value = ecma_builtin_date_parse_basic (date_str_curr_p, date_str_end_p);
if (ecma_number_is_nan (ret_value))
{
// try to parse date string in Date.prototype.toString() or toUTCString() format
ret_value = ecma_builtin_date_parse_toString_formats (date_str_curr_p, date_str_end_p);
}
ECMA_FINALIZE_UTF8_STRING (date_start_p, date_start_size);
ecma_deref_ecma_string (date_str_p);
return ecma_make_number_value (ecma_date_time_clip (ret_value));
return tv;
} /* ecma_builtin_date_parse */
/**
@ -638,12 +676,9 @@ ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */
* Returned value must be freed with ecma_free_value.
*/
static ecma_value_t
ecma_builtin_date_utc (ecma_value_t this_arg, /**< this argument */
const ecma_value_t args[], /**< arguments list */
ecma_builtin_date_utc (const ecma_value_t args[], /**< arguments list */
uint32_t args_number) /**< number of arguments */
{
JERRY_UNUSED (this_arg);
#if JERRY_ESNEXT
const uint32_t required_args_number = 1;
#else /* !JERRY_ESNEXT */
@ -652,25 +687,17 @@ ecma_builtin_date_utc (ecma_value_t this_arg, /**< this argument */
if (args_number < required_args_number)
{
/* Note:
* When the UTC function is called with fewer than two arguments,
* the behaviour is implementation-dependent, so just return NaN.
*/
return ecma_make_number_value (ecma_number_make_nan ());
}
ecma_value_t time_value = ecma_date_construct_helper (args, args_number);
ecma_number_t tv;
if (ECMA_IS_VALUE_ERROR (time_value))
if (!ecma_date_construct_helper (args, args_number, &tv))
{
return time_value;
return ECMA_VALUE_ERROR;
}
ecma_number_t time = ecma_get_number_from_value (time_value);
ecma_free_value (time_value);
return ecma_make_number_value (ecma_date_time_clip (time));
return ecma_make_number_value ((ecma_number_t) ecma_date_time_clip (tv));
} /* ecma_builtin_date_utc */
/**
@ -685,20 +712,49 @@ ecma_builtin_date_now_helper (void)
} /* ecma_builtin_date_now_helper */
/**
* The Date object's 'now' routine
* Construct a date object with the given [[DateValue]]
*
* See also:
* ECMA-262 v5, 15.9.4.4
* Note: New target must be a valid object
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
* @return ECMA_VALUE_ERROR - if the operation fails
* constructed date object - otherwise
*/
static ecma_value_t
ecma_builtin_date_now (ecma_value_t this_arg) /**< this argument */
ecma_builtin_date_create (ecma_number_t tv)
{
JERRY_UNUSED (this_arg);
return ecma_make_number_value (ecma_builtin_date_now_helper ());
} /* ecma_builtin_date_now */
#if JERRY_ESNEXT
JERRY_ASSERT (JERRY_CONTEXT (current_new_target_p) != NULL);
ecma_object_t *prototype_obj_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target_p),
ECMA_BUILTIN_ID_DATE_PROTOTYPE);
if (JERRY_UNLIKELY (prototype_obj_p == NULL))
{
return ECMA_VALUE_ERROR;
}
ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, sizeof (ecma_date_object_t), ECMA_OBJECT_TYPE_CLASS);
ecma_deref_object (prototype_obj_p);
ecma_date_object_t *date_object_p = (ecma_date_object_t *) obj_p;
date_object_p->header.u.class_prop.class_id = LIT_MAGIC_STRING_DATE_UL;
date_object_p->header.u.class_prop.u.tza = 0;
date_object_p->header.u.class_prop.extra_info = ECMA_DATE_TZA_NONE;
date_object_p->date_value = tv;
#else /* !JERRY_ESNEXT */
ecma_number_t *date_value_p = ecma_alloc_number ();
*date_value_p = tv;
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_DATE_PROTOTYPE);
ecma_object_t *obj_p = ecma_create_object (prototype_obj_p, sizeof (ecma_extended_object_t), ECMA_OBJECT_TYPE_CLASS);
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_DATE_UL;
ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.date, date_value_p);
#endif /* JERRY_ESNEXT */
return ecma_make_object_value (obj_p);
} /* ecma_builtin_date_create */
/**
* Handle calling [[Call]] of built-in Date object
@ -715,9 +771,7 @@ ecma_builtin_date_dispatch_call (const ecma_value_t *arguments_list_p, /**< argu
JERRY_UNUSED (arguments_list_p);
JERRY_UNUSED (arguments_list_len);
ecma_number_t now_val_num = ecma_builtin_date_now_helper ();
return ecma_date_value_to_string (now_val_num);
return ecma_date_value_to_string (ecma_builtin_date_now_helper ());
} /* ecma_builtin_date_dispatch_call */
/**
@ -733,137 +787,125 @@ ecma_value_t
ecma_builtin_date_dispatch_construct (const ecma_value_t *arguments_list_p, /**< arguments list */
uint32_t arguments_list_len) /**< number of arguments */
{
#if JERRY_ESNEXT
JERRY_ASSERT (JERRY_CONTEXT (current_new_target_p));
ecma_object_t *prototype_obj_p = ecma_op_get_prototype_from_constructor (JERRY_CONTEXT (current_new_target_p),
ECMA_BUILTIN_ID_DATE_PROTOTYPE);
if (JERRY_UNLIKELY (prototype_obj_p == NULL))
{
return ECMA_VALUE_ERROR;
}
#else /* !JERRY_ESNEXT */
ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_DATE_PROTOTYPE);
#endif /* (JERRY_ESNEXT */
ecma_object_t *obj_p = ecma_create_object (prototype_obj_p,
sizeof (ecma_extended_object_t),
ECMA_OBJECT_TYPE_CLASS);
#if JERRY_ESNEXT
ecma_deref_object (prototype_obj_p);
#endif /* JERRY_ESNEXT */
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) obj_p;
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_UNDEFINED;
ecma_number_t prim_value_num = ECMA_NUMBER_ZERO;
/* 20.4.2.3 */
if (arguments_list_len == 0)
{
prim_value_num = ecma_builtin_date_now_helper ();
return ecma_builtin_date_create (ecma_builtin_date_now_helper ());
}
ecma_number_t tv;
/* 20.4.2.2 */
else if (arguments_list_len == 1)
if (arguments_list_len == 1)
{
ecma_value_t argument = arguments_list_p[0];
ecma_object_t *arg_obj = NULL;
/* 4.a */
if (ecma_is_value_object (argument))
if (ecma_is_value_object (argument)
&& ecma_object_class_is (ecma_get_object_from_value (argument), LIT_MAGIC_STRING_DATE_UL))
{
arg_obj = ecma_get_object_from_value (argument);
}
if (arg_obj && ecma_object_class_is (arg_obj, LIT_MAGIC_STRING_DATE_UL))
{
ecma_extended_object_t *arg_ext_object_p = (ecma_extended_object_t *) arg_obj;
prim_value_num = *ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, arg_ext_object_p->u.class_prop.u.value);
#if JERRY_ESNEXT
tv = ((ecma_date_object_t *) ecma_get_object_from_value (argument))->date_value;
#else /* !JERRY_ESNEXT */
ecma_extended_object_t *arg_ext_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (argument);
tv = *ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, arg_ext_object_p->u.class_prop.u.date);
#endif /* JERRY_ESNEXT */
return ecma_builtin_date_create (tv);
}
/* 4.b */
ecma_value_t primitive = ecma_op_to_primitive (argument, ECMA_PREFERRED_TYPE_NO);
if (ECMA_IS_VALUE_ERROR (primitive))
{
return primitive;
}
if (ecma_is_value_string (primitive))
{
ecma_string_t *prim_str_p = ecma_get_string_from_value (primitive);
tv = ecma_builtin_date_parse (prim_str_p);
ecma_deref_ecma_string (prim_str_p);
}
else
{
ecma_value_t prim_comp_value = ecma_op_to_primitive (argument, ECMA_PREFERRED_TYPE_NO);
ecma_value_t prim_value = ecma_op_to_number (primitive, &tv);
ecma_free_value (primitive);
if (ECMA_IS_VALUE_ERROR (prim_comp_value))
if (ECMA_IS_VALUE_ERROR (prim_value))
{
ecma_deref_object (obj_p);
return prim_comp_value;
return prim_value;
}
if (ecma_is_value_string (prim_comp_value))
{
ecma_value_t parse_res_value = ecma_builtin_date_parse (ecma_make_object_value (obj_p), prim_comp_value);
if (ECMA_IS_VALUE_ERROR (parse_res_value))
{
ecma_deref_object (obj_p);
ecma_free_value (prim_comp_value);
return parse_res_value;
}
prim_value_num = ecma_get_number_from_value (parse_res_value);
ecma_free_value (parse_res_value);
}
else
{
ecma_number_t arg;
ecma_value_t prim_value = ecma_op_to_number (prim_comp_value, &arg);
if (ECMA_IS_VALUE_ERROR (prim_value))
{
ecma_deref_object (obj_p);
ecma_free_value (prim_comp_value);
return prim_value;
}
prim_value_num = ecma_date_time_clip (arg);
}
ecma_free_value (prim_comp_value);
}
}
/* 20.4.2.1 */
else if (ecma_date_construct_helper (arguments_list_p, arguments_list_len, &tv))
{
tv = ecma_date_utc (tv);
}
else
{
ecma_value_t time_value = ecma_date_construct_helper (arguments_list_p, arguments_list_len);
if (ECMA_IS_VALUE_ERROR (time_value))
{
ecma_deref_object (obj_p);
return time_value;
}
ecma_number_t time = ecma_get_number_from_value (time_value);
prim_value_num = ecma_date_time_clip (ecma_date_utc (time));
ecma_free_value (time_value);
return ECMA_VALUE_ERROR;
}
if (!ecma_number_is_nan (prim_value_num) && ecma_number_is_infinity (prim_value_num))
{
prim_value_num = ecma_number_make_nan ();
}
ext_object_p->u.class_prop.class_id = LIT_MAGIC_STRING_DATE_UL;
ecma_number_t *date_num_p = ecma_alloc_number ();
*date_num_p = prim_value_num;
ECMA_SET_INTERNAL_VALUE_POINTER (ext_object_p->u.class_prop.u.value, date_num_p);
return ecma_make_object_value (obj_p);
return ecma_builtin_date_create (ecma_date_time_clip (tv));
} /* ecma_builtin_date_dispatch_construct */
/**
* Dispatcher of the built-in's routines
*
* @return ecma value
* Returned value must be freed with ecma_free_value.
*/
ecma_value_t
ecma_builtin_date_dispatch_routine (uint8_t builtin_routine_id, /**< built-in wide routine identifier */
ecma_value_t this_arg, /**< 'this' argument value */
const ecma_value_t arguments_list_p[], /**< list of arguments passed to routine */
uint32_t arguments_number) /**< length of arguments' list */
{
JERRY_UNUSED (this_arg);
switch (builtin_routine_id)
{
case ECMA_DATE_ROUTINE_NOW:
{
return ecma_make_number_value (ecma_builtin_date_now_helper ());
}
case ECMA_DATE_ROUTINE_UTC:
{
return ecma_builtin_date_utc (arguments_list_p, arguments_number);
}
case ECMA_DATE_ROUTINE_PARSE:
{
if (arguments_number < 1)
{
return ecma_make_number_value (ecma_number_make_nan ());
}
ecma_string_t *str_p = ecma_op_to_string (arguments_list_p[0]);
if (JERRY_UNLIKELY (str_p == NULL))
{
return ECMA_VALUE_ERROR;
}
ecma_value_t result = ecma_make_number_value (ecma_date_time_clip (ecma_builtin_date_parse (str_p)));
ecma_deref_ecma_string (str_p);
return result;
}
default:
{
JERRY_UNREACHABLE ();
}
}
} /* ecma_builtin_date_dispatch_routine */
/**
* @}
* @}
* @}
*/
#undef BREAK_IF_FALSE
#undef BREAK_IF_NAN
#endif /* JERRY_BUILTIN_DATE */

View File

@ -30,9 +30,9 @@ NUMBER_VALUE (LIT_MAGIC_STRING_LENGTH,
7,
ECMA_PROPERTY_FLAG_DEFAULT_LENGTH)
ROUTINE (LIT_MAGIC_STRING_PARSE, ecma_builtin_date_parse, 1, 1)
ROUTINE (LIT_MAGIC_STRING_UTC_U, ecma_builtin_date_utc, NON_FIXED, 7)
ROUTINE (LIT_MAGIC_STRING_NOW, ecma_builtin_date_now, 0, 0)
ROUTINE (LIT_MAGIC_STRING_PARSE, ECMA_DATE_ROUTINE_PARSE, 1, 1)
ROUTINE (LIT_MAGIC_STRING_UTC_U, ECMA_DATE_ROUTINE_UTC, NON_FIXED, 7)
ROUTINE (LIT_MAGIC_STRING_NOW, ECMA_DATE_ROUTINE_NOW, 0, 0)
#if JERRY_ESNEXT
STRING_VALUE (LIT_MAGIC_STRING_NAME,

View File

@ -32,211 +32,168 @@
* @{
*/
/**
* Day names
*/
const char day_names_p[7][3] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
/**
* Month names
*/
const char month_names_p[12][3] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
/**
* Helper function to get day number from time value.
* Calculate the elapsed days since Unix Epoch
*
* See also:
* ECMA-262 v5, 15.9.1.2
*
* @return time value for day number
* @return elapsed days since Unix Epoch
*/
extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_day (ecma_number_t time) /**< time value */
extern inline int32_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_day_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
return (ecma_number_t) floor (time / ECMA_DATE_MS_PER_DAY);
} /* ecma_date_day */
/**
* Helper function to get time within day from time value.
*
* See also:
* ECMA-262 v5, 15.9.1.2
*
* @return time value within the day
*/
extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_time_within_day (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t modulo = fmod (time, ECMA_DATE_MS_PER_DAY);
if (modulo < 0)
if (time < 0)
{
modulo += ECMA_DATE_MS_PER_DAY;
time -= ECMA_DATE_MS_PER_DAY - 1;
}
return modulo;
} /* ecma_date_time_within_day */
return (int32_t) (time / ECMA_DATE_MS_PER_DAY);
} /* ecma_date_day_from_time */
/**
* Helper function to get the day number of the first day of a year.
* Abstract operation: DayFromYear
*
* See also:
* ECMA-262 v5, 15.9.1.3
* See also:
* ECMA-262 v11, 20.4.1.3
*
* @return day number of the first day of a year
* @return first of day in the given year
*/
static ecma_number_t
ecma_date_day_from_year (ecma_number_t year) /**< year value */
static int32_t
ecma_date_day_from_year (int32_t year) /**< year value */
{
JERRY_ASSERT (!ecma_number_is_nan (year));
if (JERRY_LIKELY (year >= 1970))
{
return (int32_t) (365 * (year - 1970)
+ ((year - 1969) / 4)
- ((year - 1901) / 100)
+ ((year - 1601) / 400));
}
return (ecma_number_t) (365 * (year - 1970)
+ floor ((year - 1969) / 4)
- floor ((year - 1901) / 100)
+ floor ((year - 1601) / 400));
return (int32_t) (365 * (year - 1970)
+ floor ((year - 1969) / 4.0)
- floor ((year - 1901) / 100.0)
+ floor ((year - 1601) / 400.0));
} /* ecma_date_day_from_year */
/**
* Helper function to get the time value of the start of a year.
* Abstract operation: DaysInYear
*
* See also:
* ECMA-262 v5, 15.9.1.3
* See also:
* ECMA-262 v11, 20.4.1.3
*
* @return time value of the start of a year
* @return number of days in the given year
*/
static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_time_from_year (ecma_number_t year) /**< year value */
static int
ecma_date_days_in_year (int32_t year) /**< year */
{
JERRY_ASSERT (!ecma_number_is_nan (year));
if (year % 4 != 0
|| (year % 100 == 0 && (year % 400 != 0)))
{
return ECMA_DATE_DAYS_IN_YEAR;
}
return ECMA_DATE_MS_PER_DAY * ecma_date_day_from_year (year);
} /* ecma_date_time_from_year */
return ECMA_DATE_DAYS_IN_LEAP_YEAR;
} /* ecma_date_days_in_year */
/**
* Helper function to determine a year value from the time value.
* Abstract operation: InLeapYear
*
* See also:
* ECMA-262 v5, 15.9.1.3
* See also:
* ECMA-262 v11, 20.4.1.3
*
* @return year value
* @return 1 - if the year is leap
* 0 - otherwise
*/
ecma_number_t
static int32_t
ecma_date_in_leap_year (int32_t year) /**< time value */
{
return ecma_date_days_in_year (year) - ECMA_DATE_DAYS_IN_YEAR;
} /* ecma_date_in_leap_year */
/**
* First days of months in normal and leap years
*/
static const uint16_t first_day_in_month[2][12] =
{
{
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, /* normal year */
}
,
{
0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 /* leap year */
}
};
/**
* Abstract operation: YearFromTime
*
* See also:
* ECMA-262 v11, 20.4.1.3
*
* @return year corresponds to the given time
*/
int32_t
ecma_date_year_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
/* ECMA-262 v5, 15.9.1.1 define the largest year that is
* representable (285616) forward from 01 January, 1970 UTC.
*/
ecma_number_t year = (ecma_number_t) (1970 + 285616);
ecma_number_t lower_year_boundary = (ecma_number_t) (1970 - 285616);
int32_t approx = (int32_t) (floor (time / ECMA_DATE_MS_PER_DAY / 365.2425) + 1970);
int64_t year_ms = ecma_date_day_from_year (approx) * ((int64_t) ECMA_DATE_MS_PER_DAY);
if (ecma_date_time_from_year (year) < time || ecma_date_time_from_year (lower_year_boundary) > time)
if (year_ms > time)
{
return ecma_number_make_nan ();
approx--;
}
while (ecma_date_time_from_year (year) > time)
if (year_ms + ecma_date_days_in_year (approx) * ((int64_t) ECMA_DATE_MS_PER_DAY) <= time)
{
ecma_number_t year_boundary = (ecma_number_t) floor (lower_year_boundary + (year - lower_year_boundary) / 2);
if (ecma_date_time_from_year (year_boundary) > time)
{
year = year_boundary;
}
else
{
lower_year_boundary = year_boundary;
}
year--;
approx++;
}
return year;
return approx;
} /* ecma_date_year_from_time */
/**
* Helper function to decide if time value is in a leap-year.
* Abstract operation: MonthFromTime
*
* See also:
* ECMA-262 v5, 15.9.1.3
* See also:
* ECMA-262 v11, 20.4.1.4
*
* @return 1 if time within a leap year
* 0 otherwise
* @return month corresponds to the given time
*/
static int
ecma_date_in_leap_year (ecma_number_t year) /**< time value */
{
int mod_400 = (int) fmod (floor (year), 400);
JERRY_ASSERT (mod_400 >= -399 && mod_400 <= 399);
if ((mod_400 % 4) != 0)
{
return 0;
}
if ((mod_400 % 100) != 0)
{
return 1;
}
if (mod_400 != 0)
{
return 0;
}
return 1;
} /* ecma_date_in_leap_year */
/**
* End day for the first 11 months.
*/
static const int16_t ecma_date_month_end_day[10] =
{
58, 89, 119, 150, 180, 211, 242, 272, 303, 333
};
/**
* Helper function to get month from time value.
*
* See also:
* ECMA-262 v5, 15.9.1.4
*
* @return month number
*/
ecma_number_t
int32_t
ecma_date_month_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t year = ecma_date_year_from_time (time);
int32_t year = ecma_date_year_from_time (time);
int32_t day_within_year = ecma_date_day_from_time (time) - ecma_date_day_from_year (year);
if (ecma_number_is_nan (year))
JERRY_ASSERT (day_within_year >= 0 && day_within_year < ECMA_DATE_DAYS_IN_LEAP_YEAR);
int32_t in_leap_year = ecma_date_in_leap_year (year);
for (int i = 1; i < 12; i++)
{
return ecma_number_make_nan ();
}
int day_within_year = (int) (ecma_date_day (time) - ecma_date_day_from_year (year));
JERRY_ASSERT (day_within_year >= 0);
if (day_within_year <= 30)
{
return 0;
}
day_within_year -= ecma_date_in_leap_year (year);
JERRY_ASSERT (day_within_year < 365);
for (int i = 0; i < 10; i++)
{
if (day_within_year <= ecma_date_month_end_day[i])
if (day_within_year < first_day_in_month[in_leap_year][i])
{
return i + 1;
return i - 1;
}
}
@ -244,84 +201,64 @@ ecma_date_month_from_time (ecma_number_t time) /**< time value */
} /* ecma_date_month_from_time */
/**
* Helper function to get date number from time value.
* Abstract operation: DateFromTime
*
* See also:
* ECMA-262 v5, 15.9.1.5
* See also:
* ECMA-262 v11, 20.4.1.4
*
* @return date number
* @return date corresponds to the given time
*/
ecma_number_t
int32_t
ecma_date_date_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t year = ecma_date_year_from_time (time);
int32_t year = ecma_date_year_from_time (time);
int32_t day_within_year = ecma_date_day_from_time (time) - ecma_date_day_from_year (year);
if (ecma_number_is_nan (year))
JERRY_ASSERT (day_within_year >= 0 && day_within_year < ECMA_DATE_DAYS_IN_LEAP_YEAR);
int32_t in_leap_year = ecma_date_in_leap_year (year);
int32_t month = 11;
for (int i = 1; i < 12; i++)
{
return ecma_number_make_nan ();
}
int day_within_year = (int) (ecma_date_day (time) - ecma_date_day_from_year (year));
JERRY_ASSERT (day_within_year >= 0);
if (day_within_year <= 30)
{
return day_within_year + 1;
}
int leap_year = ecma_date_in_leap_year (year);
if (day_within_year <= 58 + leap_year)
{
return day_within_year - 30;
}
day_within_year -= leap_year;
JERRY_ASSERT (day_within_year < 365);
for (int i = 1; i < 10; i++)
{
if (day_within_year <= ecma_date_month_end_day[i])
if (day_within_year < first_day_in_month[in_leap_year][i])
{
return day_within_year - ecma_date_month_end_day[i - 1];
month = i - 1;
break;
}
}
return day_within_year - 333;
return day_within_year + 1 - first_day_in_month[in_leap_year][month];
} /* ecma_date_date_from_time */
/**
* Helper function to get weekday from time value.
* Abstract operation: WeekDay
*
* See also:
* ECMA-262 v5, 15.9.1.6
* See also:
* ECMA-262 v11, 20.4.1.4
*
* Used by:
* - The Date.prototype.getDay routine. (Generated.)
* - The Date.prototype.getUTCDay routine. (Generated.)
*
* @return weekday number
* @return weekday corresponds to the given time
*/
ecma_number_t
int32_t
ecma_date_week_day (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t week_day = (ecma_number_t) fmod ((ecma_date_day (time) + 4), 7);
int32_t day = ecma_date_day_from_time (time);
return (week_day < 0) ? (7 + week_day) : week_day;
int week_day = (day + 4) % 7;
return week_day >= 0 ? week_day : week_day + 7;
} /* ecma_date_week_day */
/**
* Helper function to get the local time zone offset at a given UTC timestamp.
* You can add this number to the given UTC timestamp to get local time.
* Abstract operation: LocalTZA
*
* See also:
* ECMA-262 v5, 15.9.1.9
* See also:
* ECMA-262 v11, 20.4.1.7
*
* @return local time zone adjustment
*/
@ -332,10 +269,10 @@ ecma_date_local_time_zone_adjustment (ecma_number_t time) /**< time value */
} /* ecma_date_local_time_zone_adjustment */
/**
* Helper function to get UTC time from local time.
* Abstract operation: UTC
*
* See also:
* ECMA-262 v5, 15.9.1.9
* See also:
* ECMA-262 v11, 20.4.1.9
*
* @return UTC time
*/
@ -346,83 +283,99 @@ ecma_date_utc (ecma_number_t time) /**< time value */
} /* ecma_date_utc */
/**
* Helper function to get hour from time value.
* Calculate the time component from the given time
*
* See also:
* ECMA-262 v5, 15.9.1.10
*
* @return hour value
* @return time component of the given time
*/
ecma_number_t
int32_t
ecma_date_time_in_day_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t day = ecma_date_day_from_time (time);
return (int32_t) (time - (day * ECMA_DATE_MS_PER_DAY));
} /* ecma_date_time_in_day_from_time */
/**
* Abstract operation: HourFromTime
*
* See also:
* ECMA-262 v11, 20.4.1.10
*
* @return hours component of the given time
*/
int32_t
ecma_date_hour_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t hour = (ecma_number_t) fmod (floor (time / ECMA_DATE_MS_PER_HOUR),
ECMA_DATE_HOURS_PER_DAY);
return (hour < 0) ? ECMA_DATE_HOURS_PER_DAY + hour : hour;
int32_t time_in_day = ecma_date_time_in_day_from_time (time);
return (int32_t) (time_in_day / ECMA_DATE_MS_PER_HOUR);
} /* ecma_date_hour_from_time */
/**
* Helper function to get minute from time value.
* Abstract operation: HourFromTime
*
* See also:
* ECMA-262 v5, 15.9.1.10
* See also:
* ECMA-262 v11, 20.4.1.10
*
* @return minute value
* @return minutes component of the given time
*/
ecma_number_t
int32_t
ecma_date_min_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t min = (ecma_number_t) fmod (floor (time / ECMA_DATE_MS_PER_MINUTE),
ECMA_DATE_MINUTES_PER_HOUR);
return (min < 0) ? ECMA_DATE_MINUTES_PER_HOUR + min : min;
int32_t time_in_day = ecma_date_time_in_day_from_time (time);
return ((int32_t) (time_in_day / ECMA_DATE_MS_PER_MINUTE)) % ECMA_DATE_MINUTES_PER_HOUR;
} /* ecma_date_min_from_time */
/**
* Helper function to get second from time value.
* Abstract operation: HourFromTime
*
* See also:
* ECMA-262 v5, 15.9.1.10
* See also:
* ECMA-262 v11, 20.4.1.10
*
* @return second value
* @return seconds component of the given time
*/
ecma_number_t
int32_t
ecma_date_sec_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t sec = (ecma_number_t) fmod (floor (time / ECMA_DATE_MS_PER_SECOND),
ECMA_DATE_SECONDS_PER_MINUTE);
return (sec < 0) ? ECMA_DATE_SECONDS_PER_MINUTE + sec : sec;
int32_t time_in_day = ecma_date_time_in_day_from_time (time);
return ((int32_t) (time_in_day / ECMA_DATE_MS_PER_SECOND)) % ECMA_DATE_SECONDS_PER_MINUTE;
} /* ecma_date_sec_from_time */
/**
* Helper function to get millisecond from time value.
* Abstract operation: HourFromTime
*
* See also:
* ECMA-262 v5, 15.9.1.10
* See also:
* ECMA-262 v11, 20.4.1.10
*
* @return millisecond value
* @return milliseconds component of the given time
*/
ecma_number_t
int32_t
ecma_date_ms_from_time (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
ecma_number_t milli = (ecma_number_t) fmod (time, ECMA_DATE_MS_PER_SECOND);
return (milli < 0) ? ECMA_DATE_MS_PER_SECOND + milli : milli;
int32_t time_in_day = ecma_date_time_in_day_from_time (time);
return (int32_t) (time_in_day % ECMA_DATE_MS_PER_SECOND);
} /* ecma_date_ms_from_time */
/**
* Helper function to make time value from hour, min, sec and ms.
* Abstract operation: MakeTime
*
* See also:
* ECMA-262 v5, 15.9.1.11
* See also:
* ECMA-262 v11, 20.4.1.11
*
* @return time value
* @return constructed time in milliseconds
*/
ecma_number_t
ecma_date_make_time (ecma_number_t hour, /**< hour value */
@ -430,37 +383,32 @@ ecma_date_make_time (ecma_number_t hour, /**< hour value */
ecma_number_t sec, /**< second value */
ecma_number_t ms) /**< millisecond value */
{
if (ecma_number_is_nan (hour)
|| ecma_number_is_nan (min)
|| ecma_number_is_nan (sec)
|| ecma_number_is_nan (ms)
|| ecma_number_is_infinity (hour)
|| ecma_number_is_infinity (min)
|| ecma_number_is_infinity (sec)
|| ecma_number_is_infinity (ms))
if (!ecma_number_is_finite (hour)
|| !ecma_number_is_finite (min)
|| !ecma_number_is_finite (sec)
|| !ecma_number_is_finite (ms))
{
return ecma_number_make_nan ();
}
/* Replaced toInteger to ecma_number_trunc because it does the same thing. */
ecma_number_t h = ecma_number_trunc (hour);
ecma_number_t m = ecma_number_trunc (min);
ecma_number_t s = ecma_number_trunc (sec);
ecma_number_t milli = ecma_number_trunc (ms);
return (h * ECMA_DATE_MS_PER_HOUR
+ m * ECMA_DATE_MS_PER_MINUTE
+ s * ECMA_DATE_MS_PER_SECOND
+ milli);
return (ecma_number_t) ((h * ECMA_DATE_MS_PER_HOUR
+ m * ECMA_DATE_MS_PER_MINUTE
+ s * ECMA_DATE_MS_PER_SECOND
+ milli));
} /* ecma_date_make_time */
/**
* Helper function to make day value from year, month and date.
* Abstract operation: MakeDay
*
* See also:
* ECMA-262 v5, 15.9.1.12
* See also:
* ECMA-262 v11, 20.4.1.12
*
* @return day value
* @return elpased number of days since Unix Epoch
*/
ecma_number_t
ecma_date_make_day (ecma_number_t year, /**< year value */
@ -468,96 +416,70 @@ ecma_date_make_day (ecma_number_t year, /**< year value */
ecma_number_t date) /**< date value */
{
/* 1. */
if (ecma_number_is_nan (year)
|| ecma_number_is_nan (month)
|| ecma_number_is_nan (date)
|| ecma_number_is_infinity (year)
|| ecma_number_is_infinity (month)
|| ecma_number_is_infinity (date))
if (!ecma_number_is_finite (year)
|| !ecma_number_is_finite (month)
|| !ecma_number_is_finite (date)
|| fabs (year) > INT32_MAX)
{
return ecma_number_make_nan ();
}
/* 2., 3., 4. */
ecma_number_t y = ecma_number_trunc (year);
int32_t y = (int32_t) (year);
ecma_number_t m = ecma_number_trunc (month);
ecma_number_t dt = ecma_number_trunc (date);
/* 5. */
ecma_number_t ym = y + (ecma_number_t) floor (m / 12);
int32_t ym = y + (int32_t) (floor (m / 12));
/* 6. */
ecma_number_t mn = (ecma_number_t) fmod (m, 12);
mn = (mn < 0) ? 12 + mn : mn;
int32_t mn = (int32_t) fmod (m, 12);
/* 7. */
ecma_number_t time = ecma_date_time_from_year (ym);
/**
* The algorithm below searches the following date: ym-mn-1
* To find this time it starts from the beginning of the year (ym)
* then find the first day of the month.
*/
if (!ecma_number_is_nan (time)
&& ecma_date_year_from_time (time) == ym)
if (mn < 0)
{
/* Get the month */
time += 31 * mn * ECMA_DATE_MS_PER_DAY;
/* Get the month's first day */
time += ((ecma_number_t) 1.0 - ecma_date_date_from_time (time)) * ECMA_DATE_MS_PER_DAY;
if (!ecma_number_is_nan (time)
&& ecma_date_month_from_time (time) == mn
&& ecma_date_date_from_time (time) == 1)
{
/* 8. */
return ecma_date_day (time) + dt - ((ecma_number_t) 1.0);
}
mn += 12;
}
return ecma_number_make_nan ();
/* 7. */
ecma_number_t days = (ecma_date_day_from_year (ym)
+ first_day_in_month[ecma_date_in_leap_year (ym)][mn]
+ (dt - 1));
return days * ECMA_DATE_MS_PER_DAY;
} /* ecma_date_make_day */
/**
* Helper function to make date value from day and time.
* Abstract operation: MakeTime
*
* See also:
* ECMA-262 v5, 15.9.1.13
* See also:
* ECMA-262 v11, 20.4.1.13
*
* @return date value
* @return elpased number of milliceconds since Unix Epoch
*/
ecma_number_t
ecma_date_make_date (ecma_number_t day, /**< day value */
ecma_number_t time) /**< time value */
{
if (ecma_number_is_nan (day)
|| ecma_number_is_nan (time))
if (!ecma_number_is_finite (day)
|| !ecma_number_is_finite (time))
{
return ecma_number_make_nan ();
}
ecma_number_t result = day * ECMA_DATE_MS_PER_DAY + time;
if (ecma_number_is_infinity (result))
{
return ecma_number_make_nan ();
}
return result;
return day + time;
} /* ecma_date_make_date */
/**
* Helper function to calculate number of milliseconds from time value.
* Abstract operation: TimeClip
*
* See also:
* ECMA-262 v5, 15.9.1.14
* See also:
* ECMA-262 v11, 20.4.1.14
*
* @return number of milliseconds
* @return elpased number of milliceconds since Unix Epoch
*/
ecma_number_t
ecma_date_time_clip (ecma_number_t time) /**< time value */
{
if (ecma_number_is_nan (time)
|| ecma_number_is_infinity (time)
if (!ecma_number_is_finite (time)
|| fabs (time) > ECMA_DATE_MAX_VALUE)
{
return ecma_number_make_nan ();
@ -566,22 +488,6 @@ ecma_date_time_clip (ecma_number_t time) /**< time value */
return ecma_number_trunc (time);
} /* ecma_date_time_clip */
/**
* Helper function to calculate timezone offset.
*
* See also:
* ECMA-262 v5, 15.9.5.26
*
* @return timezone offset
*/
extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_timezone_offset (ecma_number_t time) /**< time value */
{
JERRY_ASSERT (!ecma_number_is_nan (time));
return (-ecma_date_local_time_zone_adjustment (time)) / ECMA_DATE_MS_PER_MINUTE;
} /* ecma_date_timezone_offset */
/**
* Common function to convert date to string.
*
@ -615,7 +521,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
{
case LIT_CHAR_UPPERCASE_Y: /* Year. */
{
number = (int32_t) ecma_date_year_from_time (datetime_number);
number = ecma_date_year_from_time (datetime_number);
if (number >= 100000 || number <= -100000)
{
@ -633,7 +539,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
}
case LIT_CHAR_LOWERCASE_Y: /* ISO Year: -000001, 0000, 0001, 9999, +012345 */
{
number = (int32_t) ecma_date_year_from_time (datetime_number);
number = ecma_date_year_from_time (datetime_number);
if (0 <= number && number <= 9999)
{
number_length = 4;
@ -646,7 +552,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
}
case LIT_CHAR_UPPERCASE_M: /* Month. */
{
int32_t month = (int32_t) ecma_date_month_from_time (datetime_number);
int32_t month = ecma_date_month_from_time (datetime_number);
JERRY_ASSERT (month >= 0 && month <= 11);
@ -658,19 +564,19 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
/* The 'ecma_date_month_from_time' (ECMA 262 v5, 15.9.1.4) returns a
* number from 0 to 11, but we have to print the month from 1 to 12
* for ISO 8601 standard (ECMA 262 v5, 15.9.1.15). */
number = ((int32_t) ecma_date_month_from_time (datetime_number)) + 1;
number = ecma_date_month_from_time (datetime_number) + 1;
number_length = 2;
break;
}
case LIT_CHAR_UPPERCASE_D: /* Day. */
{
number = (int32_t) ecma_date_date_from_time (datetime_number);
number = ecma_date_date_from_time (datetime_number);
number_length = 2;
break;
}
case LIT_CHAR_UPPERCASE_W: /* Day of week. */
{
int32_t day = (int32_t) ecma_date_week_day (datetime_number);
int32_t day = ecma_date_week_day (datetime_number);
JERRY_ASSERT (day >= 0 && day <= 6);
@ -679,25 +585,25 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
}
case LIT_CHAR_LOWERCASE_H: /* Hour. */
{
number = (int32_t) ecma_date_hour_from_time (datetime_number);
number = ecma_date_hour_from_time (datetime_number);
number_length = 2;
break;
}
case LIT_CHAR_LOWERCASE_M: /* Minutes. */
{
number = (int32_t) ecma_date_min_from_time (datetime_number);
number = ecma_date_min_from_time (datetime_number);
number_length = 2;
break;
}
case LIT_CHAR_LOWERCASE_S: /* Seconds. */
{
number = (int32_t) ecma_date_sec_from_time (datetime_number);
number = ecma_date_sec_from_time (datetime_number);
number_length = 2;
break;
}
case LIT_CHAR_LOWERCASE_I: /* Milliseconds. */
{
number = (int32_t) ecma_date_ms_from_time (datetime_number);
number = ecma_date_ms_from_time (datetime_number);
number_length = 3;
break;
}
@ -715,7 +621,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
time_zone = -time_zone;
}
number = time_zone / (int32_t) ECMA_DATE_MS_PER_HOUR;
number = time_zone / ECMA_DATE_MS_PER_HOUR;
number_length = 2;
break;
}
@ -730,7 +636,7 @@ ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
time_zone = -time_zone;
}
number = time_zone % (int32_t) ECMA_DATE_MS_PER_HOUR / (int32_t) ECMA_DATE_MS_PER_MINUTE;
number = (time_zone % ECMA_DATE_MS_PER_HOUR) / ECMA_DATE_MS_PER_MINUTE;
number_length = 2;
break;
}

View File

@ -111,16 +111,16 @@ ecma_builtin_is_regexp_exec (ecma_extended_object_t *obj_p);
*/
/** Hours in a day. */
#define ECMA_DATE_HOURS_PER_DAY ((ecma_number_t) 24)
#define ECMA_DATE_HOURS_PER_DAY (24)
/** Minutes in an hour. */
#define ECMA_DATE_MINUTES_PER_HOUR ((ecma_number_t) 60)
#define ECMA_DATE_MINUTES_PER_HOUR (60)
/** Seconds in a minute. */
#define ECMA_DATE_SECONDS_PER_MINUTE ((ecma_number_t) 60)
#define ECMA_DATE_SECONDS_PER_MINUTE (60)
/** Milliseconds in a second. */
#define ECMA_DATE_MS_PER_SECOND ((ecma_number_t) 1000)
#define ECMA_DATE_MS_PER_SECOND (1000)
/** ECMA_DATE_MS_PER_MINUTE == 60000 */
#define ECMA_DATE_MS_PER_MINUTE (ECMA_DATE_MS_PER_SECOND * ECMA_DATE_SECONDS_PER_MINUTE)
@ -129,7 +129,11 @@ ecma_builtin_is_regexp_exec (ecma_extended_object_t *obj_p);
#define ECMA_DATE_MS_PER_HOUR (ECMA_DATE_MS_PER_MINUTE * ECMA_DATE_MINUTES_PER_HOUR)
/** ECMA_DATE_MS_PER_DAY == 86400000 */
#define ECMA_DATE_MS_PER_DAY (ECMA_DATE_MS_PER_HOUR * ECMA_DATE_HOURS_PER_DAY)
#define ECMA_DATE_MS_PER_DAY ((ECMA_DATE_MS_PER_HOUR * ECMA_DATE_HOURS_PER_DAY))
#define ECMA_DATE_DAYS_IN_YEAR (365)
#define ECMA_DATE_DAYS_IN_LEAP_YEAR (366)
/**
* This gives a range of 8,640,000,000,000,000 milliseconds
@ -150,23 +154,23 @@ typedef enum
extern const char day_names_p[7][3];
extern const char month_names_p[12][3];
ecma_number_t ecma_date_day (ecma_number_t time);
ecma_number_t ecma_date_time_within_day (ecma_number_t time);
ecma_number_t ecma_date_year_from_time (ecma_number_t time);
ecma_number_t ecma_date_month_from_time (ecma_number_t time);
ecma_number_t ecma_date_date_from_time (ecma_number_t time);
ecma_number_t ecma_date_week_day (ecma_number_t time);
int32_t ecma_date_day_from_time (ecma_number_t time);
int32_t ecma_date_year_from_time (ecma_number_t time);
int32_t ecma_date_month_from_time (ecma_number_t time);
int32_t ecma_date_date_from_time (ecma_number_t time);
int32_t ecma_date_week_day (ecma_number_t time);
int32_t ecma_date_hour_from_time (ecma_number_t time);
int32_t ecma_date_min_from_time (ecma_number_t time);
int32_t ecma_date_sec_from_time (ecma_number_t time);
int32_t ecma_date_ms_from_time (ecma_number_t time);
int32_t ecma_date_time_in_day_from_time (ecma_number_t time);
ecma_number_t ecma_date_local_time_zone_adjustment (ecma_number_t time);
ecma_number_t ecma_date_utc (ecma_number_t time);
ecma_number_t ecma_date_hour_from_time (ecma_number_t time);
ecma_number_t ecma_date_min_from_time (ecma_number_t time);
ecma_number_t ecma_date_sec_from_time (ecma_number_t time);
ecma_number_t ecma_date_ms_from_time (ecma_number_t time);
ecma_number_t ecma_date_make_time (ecma_number_t hour, ecma_number_t min, ecma_number_t sec, ecma_number_t ms);
ecma_number_t ecma_date_make_day (ecma_number_t year, ecma_number_t month, ecma_number_t date);
ecma_number_t ecma_date_make_date (ecma_number_t day, ecma_number_t time);
ecma_number_t ecma_date_time_clip (ecma_number_t time);
ecma_number_t ecma_date_timezone_offset (ecma_number_t time);
ecma_value_t ecma_date_value_to_string (ecma_number_t datetime_number);
ecma_value_t ecma_date_value_to_utc_string (ecma_number_t datetime_number);

View File

@ -210,16 +210,20 @@ ecma_builtin_intrinsic_dispatch_routine (uint8_t builtin_routine_id, /**< built-
return ecma_raise_type_error (ECMA_ERR_MSG ("Argument 'this' is not a Date object"));
}
ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (this_arg);
ecma_number_t *prim_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t,
ext_object_p->u.class_prop.u.value);
#if JERRY_ESNEXT
ecma_number_t *date_value_p = &((ecma_date_object_t *) ecma_get_object_from_value (this_arg))->date_value;
#else /* !JERRY_ESNEXT */
ecma_extended_object_t *arg_ext_object_p = (ecma_extended_object_t *) ecma_get_object_from_value (argument);
ecma_number_t *date_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t,
arg_ext_object_p->u.class_prop.u.date);
#endif /* JERRY_ESNEXT */
if (ecma_number_is_nan (*prim_value_p))
if (ecma_number_is_nan (*date_value_p))
{
return ecma_make_magic_string_value (LIT_MAGIC_STRING_INVALID_DATE_UL);
}
return ecma_date_value_to_utc_string (*prim_value_p);
return ecma_date_value_to_utc_string (*date_value_p);
}
case ECMA_INTRINSIC_STRING_TRIM_START:
case ECMA_INTRINSIC_STRING_TRIM_END:

View File

@ -61,6 +61,7 @@ var wrongFormats = ["",
"+0002015-01-01",
"-0002015-01-01",
"2015-01T00:00:00.000-03X00",
"2015-01T00:00:00.000-02-02",
"2015-01-01T00-03:00",
"Fri Jan 01 1 00:00:00 GMT+0000",
"Fri Jan 01 11 00:00:00 GMT+0000",

View File

@ -33,18 +33,6 @@
int
main (void)
{
/* int ecma_date_day (time)*/
TEST_ASSERT (ecma_date_day (0) == 0);
TEST_ASSERT (ecma_date_day (MS_PER_DAY) == 1);
/* ecma_number_t ecma_date_time_within_day (time) */
TEST_ASSERT (ecma_date_time_within_day (0) == 0);
TEST_ASSERT (ecma_date_time_within_day (42) == 42);
TEST_ASSERT (ecma_date_time_within_day (42.51) == 42.51);
TEST_ASSERT (ecma_date_time_within_day (MS_PER_DAY + 42) == 42);
/* int ecma_date_year_from_time (time) */
TEST_ASSERT (ecma_date_year_from_time (0) == 1970);
@ -119,13 +107,13 @@ main (void)
/* ecma_number_t ecma_date_make_day (year, month, date) */
TEST_ASSERT (ecma_date_make_day (1970, 0, 1) == 0);
TEST_ASSERT (ecma_date_make_day (1970, -1, 1) == -31);
TEST_ASSERT (ecma_date_make_day (1970, 0, 2.5) == 1);
TEST_ASSERT (ecma_date_make_day (1970, 1, 35) == 65);
TEST_ASSERT (ecma_date_make_day (1970, 13, 35) == 430);
TEST_ASSERT (ecma_date_make_day (2016, 2, 1) == 16861);
TEST_ASSERT (ecma_date_make_day (2016, 8, 31) == 17075);
TEST_ASSERT (ecma_date_make_day (2016, 9, 1) == 17075);
TEST_ASSERT (ecma_date_make_day (1970, -1, 1) == -2678400000);
TEST_ASSERT (ecma_date_make_day (1970, 0, 2.5) == 86400000);
TEST_ASSERT (ecma_date_make_day (1970, 1, 35) == 5616000000);
TEST_ASSERT (ecma_date_make_day (1970, 13, 35) == 37152000000);
TEST_ASSERT (ecma_date_make_day (2016, 2, 1) == 1456790400000);
TEST_ASSERT (ecma_date_make_day (2016, 8, 31) == 1475280000000);
TEST_ASSERT (ecma_date_make_day (2016, 9, 1) == 1475280000000);
/* ecma_number_t ecma_date_make_date (day, time) */