/** * Helper function to calculate timezone offset. * * See also: * ECMA-262 v5, 15.9.5.26 * * @return timezone offset */ inline ecma_number_t __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 (time)) / ECMA_DATE_MS_PER_MINUTE; } /* ecma_date_timezone_offset */
/** * 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_prototype_dispatch_routine (uint16_t builtin_routine_id, /**< built-in wide routine * identifier */ ecma_value_t this_arg, /**< 'this' argument value */ const ecma_value_t arguments_list[], /**< list of arguments * passed to routine */ ecma_length_t arguments_number) /**< length of arguments' list */ { if (JERRY_UNLIKELY (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_JSON)) { return ecma_builtin_date_prototype_to_json (this_arg); } if (!ecma_is_value_object (this_arg) || !ecma_object_class_is (ecma_get_object_from_value (this_arg), LIT_MAGIC_STRING_DATE_UL)) { return ecma_raise_type_error (ECMA_ERR_MSG ("Date object expected")); } ecma_object_t *object_p = ecma_get_object_from_value (this_arg); ecma_extended_object_t *ext_object_p = (ecma_extended_object_t *) object_p; ecma_number_t *prim_value_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_number_t, ext_object_p->u.class_prop.u.value); if (builtin_routine_id == ECMA_DATE_PROTOTYPE_GET_TIME) { return ecma_make_number_value (*prim_value_p); } if (builtin_routine_id == ECMA_DATE_PROTOTYPE_SET_TIME) { ecma_value_t time = (arguments_number >= 1 ? arguments_list[0] : ECMA_VALUE_UNDEFINED); ecma_value_t ret_value = ECMA_VALUE_EMPTY; /* 1. */ ECMA_OP_TO_NUMBER_TRY_CATCH (time_num, time, ret_value); *prim_value_p = ecma_date_time_clip (time_num); ret_value = ecma_make_number_value (time_num); ECMA_OP_TO_NUMBER_FINALIZE (time_num); return ret_value; } 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 (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); } return ecma_builtin_date_prototype_dispatch_set (builtin_routine_id, ext_object_p, this_num, 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)) { return ecma_raise_range_error (ECMA_ERR_MSG ("Date must be a finite number.")); } return ecma_date_value_to_iso_string (*prim_value_p); } if (ecma_number_is_nan (*prim_value_p)) { return ecma_make_magic_string_value (LIT_MAGIC_STRING_INVALID_DATE_UL); } switch (builtin_routine_id) { case ECMA_DATE_PROTOTYPE_TO_STRING: { return ecma_date_value_to_string (*prim_value_p); } case ECMA_DATE_PROTOTYPE_TO_DATE_STRING: { return ecma_date_value_to_date_string (*prim_value_p); } case ECMA_DATE_PROTOTYPE_TO_TIME_STRING: { return ecma_date_value_to_time_string (*prim_value_p); } default: { JERRY_ASSERT (builtin_routine_id == ECMA_DATE_PROTOTYPE_TO_UTC_STRING); return ecma_date_value_to_utc_string (*prim_value_p); } } } /* ecma_builtin_date_prototype_dispatch_routine */
/** * Common function to create a time zone specific string from a numeric value. * * Used by: * - The Date routine. * - The Date.prototype.toString routine. * * @return ecma value * Returned value must be freed with ecma_free_value. */ ecma_value_t ecma_date_value_to_string (ecma_number_t datetime_number) /**< datetime */ { datetime_number += ecma_date_local_time_zone (datetime_number); return ecma_date_to_string_format (datetime_number, "$W $M $D $Y $h:$m:$s GMT$z:$Z"); } /* ecma_date_value_to_string */
/** * Common function to convert date to string. * * @return ecma value * Returned value must be freed with ecma_free_value. */ static ecma_value_t ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */ const char *format_p) /**< format buffer */ { const char *day_names_p[8] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; const char *month_names_p[13] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; const uint32_t date_buffer_length = 34; lit_utf8_byte_t date_buffer[date_buffer_length]; lit_utf8_byte_t *dest_p = date_buffer; while (*format_p != LIT_CHAR_NULL) { if (*format_p != LIT_CHAR_DOLLAR_SIGN) { *dest_p++ = (lit_utf8_byte_t) *format_p++; continue; } format_p++; const char *str_p = NULL; int32_t number = 0; int32_t number_length = 0; switch (*format_p) { case LIT_CHAR_UPPERCASE_Y: /* Year. */ { number = (int32_t) ecma_date_year_from_time (datetime_number); number_length = 4; break; } case LIT_CHAR_UPPERCASE_M: /* Month. */ { int32_t month = (int32_t) ecma_date_month_from_time (datetime_number); JERRY_ASSERT (month >= 0 && month <= 11); str_p = month_names_p[month]; break; } case LIT_CHAR_UPPERCASE_O: /* Month as number. */ { /* 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_length = 2; break; } case LIT_CHAR_UPPERCASE_D: /* Day. */ { number = (int32_t) 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); JERRY_ASSERT (day >= 0 && day <= 6); str_p = day_names_p[day]; break; } case LIT_CHAR_LOWERCASE_H: /* Hour. */ { number = (int32_t) 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_length = 2; break; } case LIT_CHAR_LOWERCASE_S: /* Seconds. */ { number = (int32_t) 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_length = 3; break; } case LIT_CHAR_LOWERCASE_Z: /* Time zone minutes part. */ { int32_t time_zone = (int32_t) ecma_date_local_time_zone (datetime_number); if (time_zone >= 0) { *dest_p++ = LIT_CHAR_PLUS; } else { *dest_p++ = LIT_CHAR_MINUS; time_zone = -time_zone; } number = time_zone / (int32_t) ECMA_DATE_MS_PER_HOUR; number_length = 2; break; } case LIT_CHAR_UPPERCASE_Z: /* Time zone seconds part. */ { int32_t time_zone = (int32_t) ecma_date_local_time_zone (datetime_number); if (time_zone < 0) { time_zone = -time_zone; } number = time_zone % (int32_t) ECMA_DATE_MS_PER_HOUR; number_length = 2; break; } default: { JERRY_UNREACHABLE (); break; } } format_p++; if (str_p != NULL) { /* Print string values. */ do { *dest_p++ = (lit_utf8_byte_t) *str_p++; } while (*str_p != LIT_CHAR_NULL); continue; } /* Print right aligned number values. */ JERRY_ASSERT (number_length > 0); dest_p += number_length; lit_utf8_byte_t *buffer_p = dest_p; do { buffer_p--; *buffer_p = (lit_utf8_byte_t) ((number % 10) + (int32_t) LIT_CHAR_0); number /= 10; } while (--number_length); } JERRY_ASSERT (dest_p <= date_buffer + date_buffer_length); return ecma_make_string_value (ecma_new_ecma_string_from_utf8 (date_buffer, (lit_utf8_size_t) (dest_p - date_buffer))); } /* ecma_date_to_string_format */