ecma-builtin-helpers-date.c 21.7 KB
Newer Older
1
/* Copyright JS Foundation and other contributors, http://js.foundation
2 3 4 5 6 7 8 9 10 11 12 13 14 15
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

16 17
#include <math.h>

18
#include "ecma-alloc.h"
19
#include "ecma-builtin-helpers.h"
20
#include "ecma-exceptions.h"
21 22
#include "ecma-globals.h"
#include "ecma-helpers.h"
23 24
#include "ecma-objects.h"
#include "ecma-try-catch-macro.h"
25
#include "lit-char-helpers.h"
26

27
#if ENABLED (JERRY_BUILTIN_DATE)
28 29 30 31 32 33 34 35 36 37 38 39 40 41

/** \addtogroup ecma ECMA
 * @{
 *
 * \addtogroup ecmabuiltinhelpers ECMA builtin helper operations
 * @{
 */

/**
 * Helper function to get day number from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.2
 *
Z
Zoltan Herczeg 已提交
42
 * @return time value for day number
43
 */
44
extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
45 46
ecma_date_day (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
47
  JERRY_ASSERT (!ecma_number_is_nan (time));
48 49

  return (ecma_number_t) floor (time / ECMA_DATE_MS_PER_DAY);
50 51 52 53 54 55 56 57
} /* ecma_date_day */

/**
 * Helper function to get time within day from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.2
 *
Z
Zoltan Herczeg 已提交
58
 * @return time value within the day
59
 */
60
extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
61 62
ecma_date_time_within_day (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
63
  JERRY_ASSERT (!ecma_number_is_nan (time));
64

C
Csaba Osztrogonác 已提交
65 66 67 68 69 70 71
  ecma_number_t modulo = fmod (time, ECMA_DATE_MS_PER_DAY);
  if (modulo < 0)
  {
    modulo += ECMA_DATE_MS_PER_DAY;
  }

  return modulo;
72 73 74 75 76 77 78 79
} /* ecma_date_time_within_day */

/**
 * Helper function to get the day number of the first day of a year.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.3
 *
Z
Zoltan Herczeg 已提交
80
 * @return day number of the first day of a year
81
 */
Z
Zoltan Herczeg 已提交
82
static ecma_number_t
83 84
ecma_date_day_from_year (ecma_number_t year) /**< year value */
{
Z
Zoltan Herczeg 已提交
85
  JERRY_ASSERT (!ecma_number_is_nan (year));
86 87 88 89 90

  return (ecma_number_t) (365 * (year - 1970)
                          + floor ((year - 1969) / 4)
                          - floor ((year - 1901) / 100)
                          + floor ((year - 1601) / 400));
91 92 93 94 95 96 97 98 99 100
} /* ecma_date_day_from_year */

/**
 * Helper function to get the time value of the start of a year.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.3
 *
 * @return  time value of the start of a year
 */
101
static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
102 103
ecma_date_time_from_year (ecma_number_t year) /**< year value */
{
Z
Zoltan Herczeg 已提交
104
  JERRY_ASSERT (!ecma_number_is_nan (year));
105 106

  return ECMA_DATE_MS_PER_DAY * ecma_date_day_from_year (year);
107 108 109 110 111 112 113 114
} /* ecma_date_time_from_year */

/**
 * Helper function to determine a year value from the time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.3
 *
Z
Zoltan Herczeg 已提交
115
 * @return year value
116
 */
117
ecma_number_t
118 119
ecma_date_year_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
120
  JERRY_ASSERT (!ecma_number_is_nan (time));
121 122 123 124

  /* ECMA-262 v5, 15.9.1.1 define the largest year that is
   * representable (285616) forward from 01 January, 1970 UTC.
   */
125 126
  ecma_number_t year = (ecma_number_t) (1970 + 285616);
  ecma_number_t lower_year_boundary = (ecma_number_t) (1970 - 285616);
127

128 129 130 131 132
  if (ecma_date_time_from_year (year) < time || ecma_date_time_from_year (lower_year_boundary) > time)
  {
    return ecma_number_make_nan ();
  }

133
  while (ecma_date_time_from_year (year) > time)
134
  {
135 136
    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)
137
    {
138 139 140 141 142
      year = year_boundary;
    }
    else
    {
      lower_year_boundary = year_boundary;
143
    }
Z
Zoltan Herczeg 已提交
144

145 146 147 148 149 150 151 152 153 154 155 156
    year--;
  }

  return year;
} /* ecma_date_year_from_time */

/**
 * Helper function to decide if time value is in a leap-year.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.3
 *
Z
Zoltan Herczeg 已提交
157 158
 * @return 1 if time within a leap year
 *         0 otherwise
159
 */
Z
Zoltan Herczeg 已提交
160 161
static int
ecma_date_in_leap_year (ecma_number_t year) /**< time value */
162
{
Z
Zoltan Herczeg 已提交
163 164 165 166 167
  int mod_400 = (int) fmod (floor (year), 400);

  JERRY_ASSERT (mod_400 >= -399 && mod_400 <= 399);

  if ((mod_400 % 4) != 0)
168
  {
Z
Zoltan Herczeg 已提交
169
    return 0;
170 171
  }

Z
Zoltan Herczeg 已提交
172 173 174 175 176 177 178 179 180 181 182
  if ((mod_400 % 100) != 0)
  {
    return 1;
  }

  if (mod_400 != 0)
  {
    return 0;
  }

  return 1;
183 184 185
} /* ecma_date_in_leap_year */

/**
Z
Zoltan Herczeg 已提交
186
 * End day for the first 11 months.
187
 */
Z
Zoltan Herczeg 已提交
188
static const int16_t ecma_date_month_end_day[10] =
189
{
Z
Zoltan Herczeg 已提交
190 191
  58, 89, 119, 150, 180, 211, 242, 272, 303, 333
};
192 193 194 195 196 197 198

/**
 * Helper function to get month from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.4
 *
Z
Zoltan Herczeg 已提交
199
 * @return month number
200
 */
201
ecma_number_t
202 203
ecma_date_month_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
204
  JERRY_ASSERT (!ecma_number_is_nan (time));
205

Z
Zoltan Herczeg 已提交
206
  ecma_number_t year = ecma_date_year_from_time (time);
207 208 209 210 211 212

  if (ecma_number_is_nan (year))
  {
    return ecma_number_make_nan ();
  }

Z
Zoltan Herczeg 已提交
213
  int day_within_year = (int) (ecma_date_day (time) - ecma_date_day_from_year (year));
214

Z
Zoltan Herczeg 已提交
215
  JERRY_ASSERT (day_within_year >= 0);
216

Z
Zoltan Herczeg 已提交
217
  if (day_within_year <= 30)
218 219 220
  {
    return 0;
  }
Z
Zoltan Herczeg 已提交
221 222 223 224 225 226

  day_within_year -= ecma_date_in_leap_year (year);

  JERRY_ASSERT (day_within_year < 365);

  for (int i = 0; i < 10; i++)
227
  {
Z
Zoltan Herczeg 已提交
228 229 230 231
    if (day_within_year <= ecma_date_month_end_day[i])
    {
      return i + 1;
    }
232 233 234 235 236 237 238 239 240 241 242
  }

  return 11;
} /* ecma_date_month_from_time */

/**
 * Helper function to get date number from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.5
 *
Z
Zoltan Herczeg 已提交
243
 * @return date number
244
 */
245
ecma_number_t
246 247
ecma_date_date_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
248 249 250
  JERRY_ASSERT (!ecma_number_is_nan (time));

  ecma_number_t year = ecma_date_year_from_time (time);
251 252 253 254 255 256

  if (ecma_number_is_nan (year))
  {
    return ecma_number_make_nan ();
  }

Z
Zoltan Herczeg 已提交
257 258 259 260 261
  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)
262
  {
Z
Zoltan Herczeg 已提交
263
    return day_within_year + 1;
264
  }
265

Z
Zoltan Herczeg 已提交
266
  int leap_year = ecma_date_in_leap_year (year);
267

Z
Zoltan Herczeg 已提交
268
  if (day_within_year <= 58 + leap_year)
269
  {
Z
Zoltan Herczeg 已提交
270 271 272 273 274 275 276 277 278 279
    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])
280
    {
Z
Zoltan Herczeg 已提交
281
      return day_within_year - ecma_date_month_end_day[i - 1];
282 283 284
    }
  }

Z
Zoltan Herczeg 已提交
285
  return day_within_year - 333;
286 287 288 289 290 291 292 293
} /* ecma_date_date_from_time */

/**
 * Helper function to get weekday from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.6
 *
294 295 296 297
 * Used by:
 *         - The Date.prototype.getDay routine. (Generated.)
 *         - The Date.prototype.getUTCDay routine. (Generated.)
 *
298 299
 * @return  weekday number
 */
Z
Zoltan Herczeg 已提交
300
ecma_number_t
301 302
ecma_date_week_day (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
303
  JERRY_ASSERT (!ecma_number_is_nan (time));
304

305
  ecma_number_t week_day = (ecma_number_t) fmod ((ecma_date_day (time) + 4), 7);
Z
Zoltan Herczeg 已提交
306 307

  return (week_day < 0) ? (7 + week_day) : week_day;
308 309 310
} /* ecma_date_week_day */

/**
311 312
 * 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.
313 314 315 316
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.9
 *
317
 * @return local time zone adjustment
318
 */
319
inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
320
ecma_date_local_time_zone_adjustment (ecma_number_t time) /**< time value */
321
{
322 323
  return jerry_port_get_local_time_zone_adjustment (time, true);
} /* ecma_date_local_time_zone_adjustment */
324 325

/**
326
 * Helper function to get UTC time from local time.
327 328 329 330
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.9
 *
331
 * @return UTC time
332
 */
Z
Zoltan Herczeg 已提交
333
ecma_number_t
334 335
ecma_date_utc (ecma_number_t time) /**< time value */
{
336
  return time - jerry_port_get_local_time_zone_adjustment (time, false);
337 338 339 340 341 342 343 344
} /* ecma_date_utc */

/**
 * Helper function to get hour from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.10
 *
Z
Zoltan Herczeg 已提交
345
 * @return hour value
346
 */
Z
Zoltan Herczeg 已提交
347
ecma_number_t
348 349
ecma_date_hour_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
350
  JERRY_ASSERT (!ecma_number_is_nan (time));
351

352 353 354
  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;
355 356 357 358 359 360 361 362
} /* ecma_date_hour_from_time */

/**
 * Helper function to get minute from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.10
 *
Z
Zoltan Herczeg 已提交
363
 * @return minute value
364
 */
Z
Zoltan Herczeg 已提交
365
ecma_number_t
366 367
ecma_date_min_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
368
  JERRY_ASSERT (!ecma_number_is_nan (time));
369

370 371 372
  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;
373 374 375 376 377 378 379 380
} /* ecma_date_min_from_time */

/**
 * Helper function to get second from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.10
 *
Z
Zoltan Herczeg 已提交
381
 * @return second value
382
 */
Z
Zoltan Herczeg 已提交
383
ecma_number_t
384 385
ecma_date_sec_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
386
  JERRY_ASSERT (!ecma_number_is_nan (time));
387

388 389 390
  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;
391 392 393 394 395 396 397 398
} /* ecma_date_sec_from_time */

/**
 * Helper function to get millisecond from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.10
 *
Z
Zoltan Herczeg 已提交
399
 * @return millisecond value
400
 */
Z
Zoltan Herczeg 已提交
401
ecma_number_t
402 403
ecma_date_ms_from_time (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
404
  JERRY_ASSERT (!ecma_number_is_nan (time));
405

406 407
  ecma_number_t milli = (ecma_number_t) fmod (time, ECMA_DATE_MS_PER_SECOND);
  return (milli < 0) ? ECMA_DATE_MS_PER_SECOND + milli : milli;
408 409 410 411 412 413 414 415
} /* ecma_date_ms_from_time */

/**
 * Helper function to make time value from hour, min, sec and ms.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.11
 *
Z
Zoltan Herczeg 已提交
416
 * @return time value
417 418 419 420 421 422 423
 */
ecma_number_t
ecma_date_make_time (ecma_number_t hour, /**< hour value */
                     ecma_number_t min, /**< minute value */
                     ecma_number_t sec, /**< second value */
                     ecma_number_t ms) /**< millisecond value */
{
424 425 426 427 428
  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)
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
      || ecma_number_is_infinity (min)
      || ecma_number_is_infinity (sec)
      || ecma_number_is_infinity (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);
} /* ecma_date_make_time */

/**
 * Helper function to make day value from year, month and date.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.12
 *
Z
Zoltan Herczeg 已提交
454
 * @return day value
455 456 457 458 459 460
 */
ecma_number_t
ecma_date_make_day (ecma_number_t year, /**< year value */
                    ecma_number_t month, /**< month value */
                    ecma_number_t date) /**< date value */
{
461
  /* 1. */
462 463 464 465
  if (ecma_number_is_nan (year)
      || ecma_number_is_nan (month)
      || ecma_number_is_nan (date)
      || ecma_number_is_infinity (year)
466 467 468 469 470 471
      || ecma_number_is_infinity (month)
      || ecma_number_is_infinity (date))
  {
    return ecma_number_make_nan ();
  }

472
  /* 2., 3., 4. */
473 474 475
  ecma_number_t y = ecma_number_trunc (year);
  ecma_number_t m = ecma_number_trunc (month);
  ecma_number_t dt = ecma_number_trunc (date);
476
  /* 5. */
477
  ecma_number_t ym = y + (ecma_number_t) floor (m / 12);
478
  /* 6. */
479
  ecma_number_t mn = (ecma_number_t) fmod (m, 12);
480
  mn = (mn < 0) ? 12 + mn : mn;
481 482

  /* 7. */
483
  ecma_number_t time = ecma_date_time_from_year (ym);
484 485 486

  /**
   * The algorithm below searches the following date: ym-mn-1
Z
Zoltan Herczeg 已提交
487
   * To find this time it starts from the beginning of the year (ym)
488
   * then find the first day of the month.
489
   */
490 491
  if (!ecma_number_is_nan (time)
      && ecma_date_year_from_time (time) == ym)
492
  {
493 494
    /* Get the month */
    time += 31 * mn * ECMA_DATE_MS_PER_DAY;
495

496
    /* Get the month's first day */
497
    time += ((ecma_number_t) 1.0 - ecma_date_date_from_time (time)) * ECMA_DATE_MS_PER_DAY;
498

499 500 501
    if (!ecma_number_is_nan (time)
        && ecma_date_month_from_time (time) == mn
        && ecma_date_date_from_time (time) == 1)
502 503 504 505 506
    {
      /* 8. */
      return ecma_date_day (time) + dt - ((ecma_number_t) 1.0);
    }
  }
507

508
  return ecma_number_make_nan ();
509 510 511 512 513 514 515 516
} /* ecma_date_make_day */

/**
 * Helper function to make date value from day and time.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.13
 *
Z
Zoltan Herczeg 已提交
517
 * @return date value
518
 */
Z
Zoltan Herczeg 已提交
519
ecma_number_t
520 521 522
ecma_date_make_date (ecma_number_t day, /**< day value */
                     ecma_number_t time) /**< time value */
{
523
  if (ecma_number_is_nan (day)
Z
Zoltan Herczeg 已提交
524
      || ecma_number_is_nan (time))
525 526 527 528
  {
    return ecma_number_make_nan ();
  }

Z
Zoltan Herczeg 已提交
529 530 531 532 533 534 535 536
  ecma_number_t result = day * ECMA_DATE_MS_PER_DAY + time;

  if (ecma_number_is_infinity (result))
  {
    return ecma_number_make_nan ();
  }

  return result;
537 538 539 540 541 542 543 544
} /* ecma_date_make_date */

/**
 * Helper function to calculate number of milliseconds from time value.
 *
 * See also:
 *          ECMA-262 v5, 15.9.1.14
 *
Z
Zoltan Herczeg 已提交
545
 * @return number of milliseconds
546
 */
Z
Zoltan Herczeg 已提交
547
ecma_number_t
548 549
ecma_date_time_clip (ecma_number_t time) /**< time value */
{
550 551
  if (ecma_number_is_nan (time)
      || ecma_number_is_infinity (time)
552 553 554 555 556 557 558 559
      || fabs (time) > ECMA_DATE_MAX_VALUE)
  {
    return ecma_number_make_nan ();
  }

  return ecma_number_trunc (time);
} /* ecma_date_time_clip */

560 561 562 563 564 565
/**
 * Helper function to calculate timezone offset.
 *
 * See also:
 *          ECMA-262 v5, 15.9.5.26
 *
Z
Zoltan Herczeg 已提交
566
 * @return timezone offset
567
 */
568
inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
569 570
ecma_date_timezone_offset (ecma_number_t time) /**< time value */
{
Z
Zoltan Herczeg 已提交
571
  JERRY_ASSERT (!ecma_number_is_nan (time));
572

573
  return (-ecma_date_local_time_zone_adjustment (time)) / ECMA_DATE_MS_PER_MINUTE;
574 575
} /* ecma_date_timezone_offset */

576
/**
Z
Zoltan Herczeg 已提交
577
 * Common function to convert date to string.
578
 *
Z
Zoltan Herczeg 已提交
579 580
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
581
 */
Z
Zoltan Herczeg 已提交
582 583 584
static ecma_value_t
ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
                            const char *format_p) /**< format buffer */
585
{
586
  static const char * const day_names_p[8] =
587
  {
Z
Zoltan Herczeg 已提交
588 589
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
  };
590

591
  static const char * const month_names_p[13] =
592
  {
Z
Zoltan Herczeg 已提交
593
    "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
594 595
  };

596
  const uint32_t date_buffer_length = 37;
Y
Yonggang Luo 已提交
597
  JERRY_VLA (lit_utf8_byte_t, date_buffer, date_buffer_length);
598

Z
Zoltan Herczeg 已提交
599 600 601
  lit_utf8_byte_t *dest_p = date_buffer;

  while (*format_p != LIT_CHAR_NULL)
602
  {
Z
Zoltan Herczeg 已提交
603 604 605 606 607
    if (*format_p != LIT_CHAR_DOLLAR_SIGN)
    {
      *dest_p++ = (lit_utf8_byte_t) *format_p++;
      continue;
    }
608

Z
Zoltan Herczeg 已提交
609
    format_p++;
610

Z
Zoltan Herczeg 已提交
611 612 613
    const char *str_p = NULL;
    int32_t number = 0;
    int32_t number_length = 0;
614

Z
Zoltan Herczeg 已提交
615 616 617 618 619
    switch (*format_p)
    {
      case LIT_CHAR_UPPERCASE_Y: /* Year. */
      {
        number = (int32_t) ecma_date_year_from_time (datetime_number);
620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645

        if (number >= 100000 || number <= -100000)
        {
          number_length = 6;
        }
        else if (number >= 10000 || number <= -10000)
        {
          number_length = 5;
        }
        else
        {
          number_length = 4;
        }
        break;
      }
      case LIT_CHAR_LOWERCASE_Y: /* ISO Year: -000001, 0000, 0001, 9999, +012345 */
      {
        number = (int32_t) ecma_date_year_from_time (datetime_number);
        if (0 <= number && number <= 9999)
        {
          number_length = 4;
        }
        else
        {
          number_length = 6;
        }
Z
Zoltan Herczeg 已提交
646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
        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. */
      {
707
        int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number);
Z
Zoltan Herczeg 已提交
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722

        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;
      }
723
      default:
Z
Zoltan Herczeg 已提交
724
      {
725 726
        JERRY_ASSERT (*format_p == LIT_CHAR_UPPERCASE_Z); /* Time zone seconds part. */

727
        int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number);
Z
Zoltan Herczeg 已提交
728 729 730 731 732 733 734 735 736 737 738

        if (time_zone < 0)
        {
          time_zone = -time_zone;
        }

        number = time_zone % (int32_t) ECMA_DATE_MS_PER_HOUR;
        number_length = 2;
        break;
      }
    }
739

Z
Zoltan Herczeg 已提交
740
    format_p++;
741

Z
Zoltan Herczeg 已提交
742 743 744 745 746 747 748 749 750 751 752
    if (str_p != NULL)
    {
      /* Print string values. */
      do
      {
        *dest_p++ = (lit_utf8_byte_t) *str_p++;
      }
      while (*str_p != LIT_CHAR_NULL);

      continue;
    }
753

Z
Zoltan Herczeg 已提交
754 755
    /* Print right aligned number values. */
    JERRY_ASSERT (number_length > 0);
756

757 758 759 760 761 762 763 764 765 766 767
    if (number < 0)
    {
      number = -number;
      *dest_p++ = '-';
    }
    else if (*(format_p - 1) == LIT_CHAR_LOWERCASE_Y && number_length == 6)
    {
      /* positive sign is compulsory for extended years */
      *dest_p++ = '+';
    }

Z
Zoltan Herczeg 已提交
768 769
    dest_p += number_length;
    lit_utf8_byte_t *buffer_p = dest_p;
770

Z
Zoltan Herczeg 已提交
771 772 773 774 775 776 777 778
    do
    {
      buffer_p--;
      *buffer_p = (lit_utf8_byte_t) ((number % 10) + (int32_t) LIT_CHAR_0);
      number /= 10;
    }
    while (--number_length);
  }
779

Z
Zoltan Herczeg 已提交
780
  JERRY_ASSERT (dest_p <= date_buffer + date_buffer_length);
781

Z
Zoltan Herczeg 已提交
782 783 784
  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 */
785

786
/**
787 788 789 790
 * Common function to create a time zone specific string from a numeric value.
 *
 * Used by:
 *        - The Date routine.
791
 *        - The Date.prototype.toString routine.
792
 *
793 794
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
795
 */
796
ecma_value_t
797 798
ecma_date_value_to_string (ecma_number_t datetime_number) /**< datetime */
{
799
  datetime_number += ecma_date_local_time_zone_adjustment (datetime_number);
Z
Zoltan Herczeg 已提交
800
  return ecma_date_to_string_format (datetime_number, "$W $M $D $Y $h:$m:$s GMT$z:$Z");
801 802 803 804 805 806
} /* ecma_date_value_to_string */

/**
 * Common function to create a time zone specific string from a numeric value.
 *
 * Used by:
807
 *        - The Date.prototype.toUTCString routine.
808
 *
809 810
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
811
 */
812
ecma_value_t
813 814
ecma_date_value_to_utc_string (ecma_number_t datetime_number) /**< datetime */
{
Z
Zoltan Herczeg 已提交
815
  return ecma_date_to_string_format (datetime_number, "$W, $D $M $Y $h:$m:$s GMT");
816 817 818
} /* ecma_date_value_to_utc_string */

/**
819
 * Common function to create a ISO specific string from a numeric value.
820 821 822 823
 *
 * Used by:
 *        - The Date.prototype.toISOString routine.
 *
824 825
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
826
 */
827
ecma_value_t
828
ecma_date_value_to_iso_string (ecma_number_t datetime_number) /**<datetime */
829
{
830
  return ecma_date_to_string_format (datetime_number, "$y-$O-$DT$h:$m:$s.$iZ");
831 832 833 834 835 836 837 838
} /* ecma_date_value_to_iso_string */

/**
 * Common function to create a date string from a numeric value.
 *
 * Used by:
 *        - The Date.prototype.toDateString routine.
 *
839 840
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
841
 */
842
ecma_value_t
843 844
ecma_date_value_to_date_string (ecma_number_t datetime_number) /**<datetime */
{
Z
Zoltan Herczeg 已提交
845
  return ecma_date_to_string_format (datetime_number, "$Y-$O-$D");
846 847 848 849 850 851 852 853
} /* ecma_date_value_to_date_string */

/**
 * Common function to create a time string from a numeric value.
 *
 * Used by:
 *        - The Date.prototype.toTimeString routine.
 *
854 855
 * @return ecma value
 *         Returned value must be freed with ecma_free_value.
856
 */
857
ecma_value_t
858 859
ecma_date_value_to_time_string (ecma_number_t datetime_number) /**<datetime */
{
Z
Zoltan Herczeg 已提交
860
  return ecma_date_to_string_format (datetime_number, "$h:$m:$s.$i");
861
} /* ecma_date_value_to_time_string */
862

863 864 865 866 867
/**
 * @}
 * @}
 */

868
#endif /* ENABLED (JERRY_BUILTIN_DATE) */