1 /* Copyright JS Foundation and other contributors, http://js.foundation
2 *
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <math.h>
17
18 #include "ecma-alloc.h"
19 #include "ecma-builtin-helpers.h"
20 #include "ecma-exceptions.h"
21 #include "ecma-globals.h"
22 #include "ecma-helpers.h"
23 #include "ecma-objects.h"
24 #include "ecma-try-catch-macro.h"
25 #include "lit-char-helpers.h"
26
27 #if ENABLED (JERRY_BUILTIN_DATE)
28
29 /** \addtogroup ecma ECMA
30 * @{
31 *
32 * \addtogroup ecmabuiltinhelpers ECMA builtin helper operations
33 * @{
34 */
35
36 const char day_names_p[7][3] =
37 {
38 "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
39 };
40
41 const char month_names_p[12][3] =
42 {
43 "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
44 };
45
46 /**
47 * Helper function to get day number from time value.
48 *
49 * See also:
50 * ECMA-262 v5, 15.9.1.2
51 *
52 * @return time value for day number
53 */
54 extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_day(ecma_number_t time)55 ecma_date_day (ecma_number_t time) /**< time value */
56 {
57 JERRY_ASSERT (!ecma_number_is_nan (time));
58
59 return (ecma_number_t) floor (time / ECMA_DATE_MS_PER_DAY);
60 } /* ecma_date_day */
61
62 /**
63 * Helper function to get time within day from time value.
64 *
65 * See also:
66 * ECMA-262 v5, 15.9.1.2
67 *
68 * @return time value within the day
69 */
70 extern inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_time_within_day(ecma_number_t time)71 ecma_date_time_within_day (ecma_number_t time) /**< time value */
72 {
73 JERRY_ASSERT (!ecma_number_is_nan (time));
74
75 ecma_number_t modulo = fmod (time, ECMA_DATE_MS_PER_DAY);
76 if (modulo < 0)
77 {
78 modulo += ECMA_DATE_MS_PER_DAY;
79 }
80
81 return modulo;
82 } /* ecma_date_time_within_day */
83
84 /**
85 * Helper function to get the day number of the first day of a year.
86 *
87 * See also:
88 * ECMA-262 v5, 15.9.1.3
89 *
90 * @return day number of the first day of a year
91 */
92 static ecma_number_t
ecma_date_day_from_year(ecma_number_t year)93 ecma_date_day_from_year (ecma_number_t year) /**< year value */
94 {
95 JERRY_ASSERT (!ecma_number_is_nan (year));
96
97 return (ecma_number_t) (365 * (year - 1970)
98 + floor ((year - 1969) / 4)
99 - floor ((year - 1901) / 100)
100 + floor ((year - 1601) / 400));
101 } /* ecma_date_day_from_year */
102
103 /**
104 * Helper function to get the time value of the start of a year.
105 *
106 * See also:
107 * ECMA-262 v5, 15.9.1.3
108 *
109 * @return time value of the start of a year
110 */
111 static inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_time_from_year(ecma_number_t year)112 ecma_date_time_from_year (ecma_number_t year) /**< year value */
113 {
114 JERRY_ASSERT (!ecma_number_is_nan (year));
115
116 return ECMA_DATE_MS_PER_DAY * ecma_date_day_from_year (year);
117 } /* ecma_date_time_from_year */
118
119 /**
120 * Helper function to determine a year value from the time value.
121 *
122 * See also:
123 * ECMA-262 v5, 15.9.1.3
124 *
125 * @return year value
126 */
127 ecma_number_t
ecma_date_year_from_time(ecma_number_t time)128 ecma_date_year_from_time (ecma_number_t time) /**< time value */
129 {
130 JERRY_ASSERT (!ecma_number_is_nan (time));
131
132 /* ECMA-262 v5, 15.9.1.1 define the largest year that is
133 * representable (285616) forward from 01 January, 1970 UTC.
134 */
135 ecma_number_t year = (ecma_number_t) (1970 + 285616);
136 ecma_number_t lower_year_boundary = (ecma_number_t) (1970 - 285616);
137
138 if (ecma_date_time_from_year (year) < time || ecma_date_time_from_year (lower_year_boundary) > time)
139 {
140 return ecma_number_make_nan ();
141 }
142
143 while (ecma_date_time_from_year (year) > time)
144 {
145 ecma_number_t year_boundary = (ecma_number_t) floor (lower_year_boundary + (year - lower_year_boundary) / 2);
146 if (ecma_date_time_from_year (year_boundary) > time)
147 {
148 year = year_boundary;
149 }
150 else
151 {
152 lower_year_boundary = year_boundary;
153 }
154
155 year--;
156 }
157
158 return year;
159 } /* ecma_date_year_from_time */
160
161 /**
162 * Helper function to decide if time value is in a leap-year.
163 *
164 * See also:
165 * ECMA-262 v5, 15.9.1.3
166 *
167 * @return 1 if time within a leap year
168 * 0 otherwise
169 */
170 static int
ecma_date_in_leap_year(ecma_number_t year)171 ecma_date_in_leap_year (ecma_number_t year) /**< time value */
172 {
173 int mod_400 = (int) fmod (floor (year), 400);
174
175 JERRY_ASSERT (mod_400 >= -399 && mod_400 <= 399);
176
177 if ((mod_400 % 4) != 0)
178 {
179 return 0;
180 }
181
182 if ((mod_400 % 100) != 0)
183 {
184 return 1;
185 }
186
187 if (mod_400 != 0)
188 {
189 return 0;
190 }
191
192 return 1;
193 } /* ecma_date_in_leap_year */
194
195 /**
196 * End day for the first 11 months.
197 */
198 static const int16_t ecma_date_month_end_day[10] =
199 {
200 58, 89, 119, 150, 180, 211, 242, 272, 303, 333
201 };
202
203 /**
204 * Helper function to get month from time value.
205 *
206 * See also:
207 * ECMA-262 v5, 15.9.1.4
208 *
209 * @return month number
210 */
211 ecma_number_t
ecma_date_month_from_time(ecma_number_t time)212 ecma_date_month_from_time (ecma_number_t time) /**< time value */
213 {
214 JERRY_ASSERT (!ecma_number_is_nan (time));
215
216 ecma_number_t year = ecma_date_year_from_time (time);
217
218 if (ecma_number_is_nan (year))
219 {
220 return ecma_number_make_nan ();
221 }
222
223 int day_within_year = (int) (ecma_date_day (time) - ecma_date_day_from_year (year));
224
225 JERRY_ASSERT (day_within_year >= 0);
226
227 if (day_within_year <= 30)
228 {
229 return 0;
230 }
231
232 day_within_year -= ecma_date_in_leap_year (year);
233
234 JERRY_ASSERT (day_within_year < 365);
235
236 for (int i = 0; i < 10; i++)
237 {
238 if (day_within_year <= ecma_date_month_end_day[i])
239 {
240 return i + 1;
241 }
242 }
243
244 return 11;
245 } /* ecma_date_month_from_time */
246
247 /**
248 * Helper function to get date number from time value.
249 *
250 * See also:
251 * ECMA-262 v5, 15.9.1.5
252 *
253 * @return date number
254 */
255 ecma_number_t
ecma_date_date_from_time(ecma_number_t time)256 ecma_date_date_from_time (ecma_number_t time) /**< time value */
257 {
258 JERRY_ASSERT (!ecma_number_is_nan (time));
259
260 ecma_number_t year = ecma_date_year_from_time (time);
261
262 if (ecma_number_is_nan (year))
263 {
264 return ecma_number_make_nan ();
265 }
266
267 int day_within_year = (int) (ecma_date_day (time) - ecma_date_day_from_year (year));
268
269 JERRY_ASSERT (day_within_year >= 0);
270
271 if (day_within_year <= 30)
272 {
273 return day_within_year + 1;
274 }
275
276 int leap_year = ecma_date_in_leap_year (year);
277
278 if (day_within_year <= 58 + leap_year)
279 {
280 return day_within_year - 30;
281 }
282
283 day_within_year -= leap_year;
284
285 JERRY_ASSERT (day_within_year < 365);
286
287 for (int i = 1; i < 10; i++)
288 {
289 if (day_within_year <= ecma_date_month_end_day[i])
290 {
291 return day_within_year - ecma_date_month_end_day[i - 1];
292 }
293 }
294
295 return day_within_year - 333;
296 } /* ecma_date_date_from_time */
297
298 /**
299 * Helper function to get weekday from time value.
300 *
301 * See also:
302 * ECMA-262 v5, 15.9.1.6
303 *
304 * Used by:
305 * - The Date.prototype.getDay routine. (Generated.)
306 * - The Date.prototype.getUTCDay routine. (Generated.)
307 *
308 * @return weekday number
309 */
310 ecma_number_t
ecma_date_week_day(ecma_number_t time)311 ecma_date_week_day (ecma_number_t time) /**< time value */
312 {
313 JERRY_ASSERT (!ecma_number_is_nan (time));
314
315 ecma_number_t week_day = (ecma_number_t) fmod ((ecma_date_day (time) + 4), 7);
316
317 return (week_day < 0) ? (7 + week_day) : week_day;
318 } /* ecma_date_week_day */
319
320 /**
321 * Helper function to get the local time zone offset at a given UTC timestamp.
322 * You can add this number to the given UTC timestamp to get local time.
323 *
324 * See also:
325 * ECMA-262 v5, 15.9.1.9
326 *
327 * @return local time zone adjustment
328 */
329 inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_local_time_zone_adjustment(ecma_number_t time)330 ecma_date_local_time_zone_adjustment (ecma_number_t time) /**< time value */
331 {
332 return jerry_port_get_local_time_zone_adjustment (time, true);
333 } /* ecma_date_local_time_zone_adjustment */
334
335 /**
336 * Helper function to get UTC time from local time.
337 *
338 * See also:
339 * ECMA-262 v5, 15.9.1.9
340 *
341 * @return UTC time
342 */
343 ecma_number_t
ecma_date_utc(ecma_number_t time)344 ecma_date_utc (ecma_number_t time) /**< time value */
345 {
346 return time - jerry_port_get_local_time_zone_adjustment (time, false);
347 } /* ecma_date_utc */
348
349 /**
350 * Helper function to get hour from time value.
351 *
352 * See also:
353 * ECMA-262 v5, 15.9.1.10
354 *
355 * @return hour value
356 */
357 ecma_number_t
ecma_date_hour_from_time(ecma_number_t time)358 ecma_date_hour_from_time (ecma_number_t time) /**< time value */
359 {
360 JERRY_ASSERT (!ecma_number_is_nan (time));
361
362 ecma_number_t hour = (ecma_number_t) fmod (floor (time / ECMA_DATE_MS_PER_HOUR),
363 ECMA_DATE_HOURS_PER_DAY);
364 return (hour < 0) ? ECMA_DATE_HOURS_PER_DAY + hour : hour;
365 } /* ecma_date_hour_from_time */
366
367 /**
368 * Helper function to get minute from time value.
369 *
370 * See also:
371 * ECMA-262 v5, 15.9.1.10
372 *
373 * @return minute value
374 */
375 ecma_number_t
ecma_date_min_from_time(ecma_number_t time)376 ecma_date_min_from_time (ecma_number_t time) /**< time value */
377 {
378 JERRY_ASSERT (!ecma_number_is_nan (time));
379
380 ecma_number_t min = (ecma_number_t) fmod (floor (time / ECMA_DATE_MS_PER_MINUTE),
381 ECMA_DATE_MINUTES_PER_HOUR);
382 return (min < 0) ? ECMA_DATE_MINUTES_PER_HOUR + min : min;
383 } /* ecma_date_min_from_time */
384
385 /**
386 * Helper function to get second from time value.
387 *
388 * See also:
389 * ECMA-262 v5, 15.9.1.10
390 *
391 * @return second value
392 */
393 ecma_number_t
ecma_date_sec_from_time(ecma_number_t time)394 ecma_date_sec_from_time (ecma_number_t time) /**< time value */
395 {
396 JERRY_ASSERT (!ecma_number_is_nan (time));
397
398 ecma_number_t sec = (ecma_number_t) fmod (floor (time / ECMA_DATE_MS_PER_SECOND),
399 ECMA_DATE_SECONDS_PER_MINUTE);
400 return (sec < 0) ? ECMA_DATE_SECONDS_PER_MINUTE + sec : sec;
401 } /* ecma_date_sec_from_time */
402
403 /**
404 * Helper function to get millisecond from time value.
405 *
406 * See also:
407 * ECMA-262 v5, 15.9.1.10
408 *
409 * @return millisecond value
410 */
411 ecma_number_t
ecma_date_ms_from_time(ecma_number_t time)412 ecma_date_ms_from_time (ecma_number_t time) /**< time value */
413 {
414 JERRY_ASSERT (!ecma_number_is_nan (time));
415
416 ecma_number_t milli = (ecma_number_t) fmod (time, ECMA_DATE_MS_PER_SECOND);
417 return (milli < 0) ? ECMA_DATE_MS_PER_SECOND + milli : milli;
418 } /* ecma_date_ms_from_time */
419
420 /**
421 * Helper function to make time value from hour, min, sec and ms.
422 *
423 * See also:
424 * ECMA-262 v5, 15.9.1.11
425 *
426 * @return time value
427 */
428 ecma_number_t
ecma_date_make_time(ecma_number_t hour,ecma_number_t min,ecma_number_t sec,ecma_number_t ms)429 ecma_date_make_time (ecma_number_t hour, /**< hour value */
430 ecma_number_t min, /**< minute value */
431 ecma_number_t sec, /**< second value */
432 ecma_number_t ms) /**< millisecond value */
433 {
434 if (ecma_number_is_nan (hour)
435 || ecma_number_is_nan (min)
436 || ecma_number_is_nan (sec)
437 || ecma_number_is_nan (ms)
438 || ecma_number_is_infinity (hour)
439 || ecma_number_is_infinity (min)
440 || ecma_number_is_infinity (sec)
441 || ecma_number_is_infinity (ms))
442 {
443 return ecma_number_make_nan ();
444 }
445
446 /* Replaced toInteger to ecma_number_trunc because it does the same thing. */
447 ecma_number_t h = ecma_number_trunc (hour);
448 ecma_number_t m = ecma_number_trunc (min);
449 ecma_number_t s = ecma_number_trunc (sec);
450 ecma_number_t milli = ecma_number_trunc (ms);
451
452 return (h * ECMA_DATE_MS_PER_HOUR
453 + m * ECMA_DATE_MS_PER_MINUTE
454 + s * ECMA_DATE_MS_PER_SECOND
455 + milli);
456 } /* ecma_date_make_time */
457
458 /**
459 * Helper function to make day value from year, month and date.
460 *
461 * See also:
462 * ECMA-262 v5, 15.9.1.12
463 *
464 * @return day value
465 */
466 ecma_number_t
ecma_date_make_day(ecma_number_t year,ecma_number_t month,ecma_number_t date)467 ecma_date_make_day (ecma_number_t year, /**< year value */
468 ecma_number_t month, /**< month value */
469 ecma_number_t date) /**< date value */
470 {
471 /* 1. */
472 if (ecma_number_is_nan (year)
473 || ecma_number_is_nan (month)
474 || ecma_number_is_nan (date)
475 || ecma_number_is_infinity (year)
476 || ecma_number_is_infinity (month)
477 || ecma_number_is_infinity (date))
478 {
479 return ecma_number_make_nan ();
480 }
481
482 /* 2., 3., 4. */
483 ecma_number_t y = ecma_number_trunc (year);
484 ecma_number_t m = ecma_number_trunc (month);
485 ecma_number_t dt = ecma_number_trunc (date);
486 /* 5. */
487 ecma_number_t ym = y + (ecma_number_t) floor (m / 12);
488 /* 6. */
489 ecma_number_t mn = (ecma_number_t) fmod (m, 12);
490 mn = (mn < 0) ? 12 + mn : mn;
491
492 /* 7. */
493 ecma_number_t time = ecma_date_time_from_year (ym);
494
495 /**
496 * The algorithm below searches the following date: ym-mn-1
497 * To find this time it starts from the beginning of the year (ym)
498 * then find the first day of the month.
499 */
500 if (!ecma_number_is_nan (time)
501 && ecma_date_year_from_time (time) == ym)
502 {
503 /* Get the month */
504 time += 31 * mn * ECMA_DATE_MS_PER_DAY;
505
506 /* Get the month's first day */
507 time += ((ecma_number_t) 1.0 - ecma_date_date_from_time (time)) * ECMA_DATE_MS_PER_DAY;
508
509 if (!ecma_number_is_nan (time)
510 && ecma_date_month_from_time (time) == mn
511 && ecma_date_date_from_time (time) == 1)
512 {
513 /* 8. */
514 return ecma_date_day (time) + dt - ((ecma_number_t) 1.0);
515 }
516 }
517
518 return ecma_number_make_nan ();
519 } /* ecma_date_make_day */
520
521 /**
522 * Helper function to make date value from day and time.
523 *
524 * See also:
525 * ECMA-262 v5, 15.9.1.13
526 *
527 * @return date value
528 */
529 ecma_number_t
ecma_date_make_date(ecma_number_t day,ecma_number_t time)530 ecma_date_make_date (ecma_number_t day, /**< day value */
531 ecma_number_t time) /**< time value */
532 {
533 if (ecma_number_is_nan (day)
534 || ecma_number_is_nan (time))
535 {
536 return ecma_number_make_nan ();
537 }
538
539 ecma_number_t result = day * ECMA_DATE_MS_PER_DAY + time;
540
541 if (ecma_number_is_infinity (result))
542 {
543 return ecma_number_make_nan ();
544 }
545
546 return result;
547 } /* ecma_date_make_date */
548
549 /**
550 * Helper function to calculate number of milliseconds from time value.
551 *
552 * See also:
553 * ECMA-262 v5, 15.9.1.14
554 *
555 * @return number of milliseconds
556 */
557 ecma_number_t
ecma_date_time_clip(ecma_number_t time)558 ecma_date_time_clip (ecma_number_t time) /**< time value */
559 {
560 if (ecma_number_is_nan (time)
561 || ecma_number_is_infinity (time)
562 || fabs (time) > ECMA_DATE_MAX_VALUE)
563 {
564 return ecma_number_make_nan ();
565 }
566
567 return ecma_number_trunc (time);
568 } /* ecma_date_time_clip */
569
570 /**
571 * Helper function to calculate timezone offset.
572 *
573 * See also:
574 * ECMA-262 v5, 15.9.5.26
575 *
576 * @return timezone offset
577 */
578 inline ecma_number_t JERRY_ATTR_ALWAYS_INLINE
ecma_date_timezone_offset(ecma_number_t time)579 ecma_date_timezone_offset (ecma_number_t time) /**< time value */
580 {
581 JERRY_ASSERT (!ecma_number_is_nan (time));
582
583 return (-ecma_date_local_time_zone_adjustment (time)) / ECMA_DATE_MS_PER_MINUTE;
584 } /* ecma_date_timezone_offset */
585
586 /**
587 * Common function to convert date to string.
588 *
589 * @return ecma value
590 * Returned value must be freed with ecma_free_value.
591 */
592 static ecma_value_t
ecma_date_to_string_format(ecma_number_t datetime_number,const char * format_p)593 ecma_date_to_string_format (ecma_number_t datetime_number, /**< datetime */
594 const char *format_p) /**< format buffer */
595 {
596 const uint32_t date_buffer_length = 37;
597 JERRY_VLA (lit_utf8_byte_t, date_buffer, date_buffer_length);
598
599 lit_utf8_byte_t *dest_p = date_buffer;
600
601 while (*format_p != LIT_CHAR_NULL)
602 {
603 if (*format_p != LIT_CHAR_DOLLAR_SIGN)
604 {
605 *dest_p++ = (lit_utf8_byte_t) *format_p++;
606 continue;
607 }
608
609 format_p++;
610
611 const char *str_p = NULL;
612 int32_t number = 0;
613 int32_t number_length = 0;
614
615 switch (*format_p)
616 {
617 case LIT_CHAR_UPPERCASE_Y: /* Year. */
618 {
619 number = (int32_t) ecma_date_year_from_time (datetime_number);
620
621 if (number >= 100000 || number <= -100000)
622 {
623 number_length = 6;
624 }
625 else if (number >= 10000 || number <= -10000)
626 {
627 number_length = 5;
628 }
629 else
630 {
631 number_length = 4;
632 }
633 break;
634 }
635 case LIT_CHAR_LOWERCASE_Y: /* ISO Year: -000001, 0000, 0001, 9999, +012345 */
636 {
637 number = (int32_t) ecma_date_year_from_time (datetime_number);
638 if (0 <= number && number <= 9999)
639 {
640 number_length = 4;
641 }
642 else
643 {
644 number_length = 6;
645 }
646 break;
647 }
648 case LIT_CHAR_UPPERCASE_M: /* Month. */
649 {
650 int32_t month = (int32_t) ecma_date_month_from_time (datetime_number);
651
652 JERRY_ASSERT (month >= 0 && month <= 11);
653
654 str_p = month_names_p[month];
655 break;
656 }
657 case LIT_CHAR_UPPERCASE_O: /* Month as number. */
658 {
659 /* The 'ecma_date_month_from_time' (ECMA 262 v5, 15.9.1.4) returns a
660 * number from 0 to 11, but we have to print the month from 1 to 12
661 * for ISO 8601 standard (ECMA 262 v5, 15.9.1.15). */
662 number = ((int32_t) ecma_date_month_from_time (datetime_number)) + 1;
663 number_length = 2;
664 break;
665 }
666 case LIT_CHAR_UPPERCASE_D: /* Day. */
667 {
668 number = (int32_t) ecma_date_date_from_time (datetime_number);
669 number_length = 2;
670 break;
671 }
672 case LIT_CHAR_UPPERCASE_W: /* Day of week. */
673 {
674 int32_t day = (int32_t) ecma_date_week_day (datetime_number);
675
676 JERRY_ASSERT (day >= 0 && day <= 6);
677
678 str_p = day_names_p[day];
679 break;
680 }
681 case LIT_CHAR_LOWERCASE_H: /* Hour. */
682 {
683 number = (int32_t) ecma_date_hour_from_time (datetime_number);
684 number_length = 2;
685 break;
686 }
687 case LIT_CHAR_LOWERCASE_M: /* Minutes. */
688 {
689 number = (int32_t) ecma_date_min_from_time (datetime_number);
690 number_length = 2;
691 break;
692 }
693 case LIT_CHAR_LOWERCASE_S: /* Seconds. */
694 {
695 number = (int32_t) ecma_date_sec_from_time (datetime_number);
696 number_length = 2;
697 break;
698 }
699 case LIT_CHAR_LOWERCASE_I: /* Milliseconds. */
700 {
701 number = (int32_t) ecma_date_ms_from_time (datetime_number);
702 number_length = 3;
703 break;
704 }
705 case LIT_CHAR_LOWERCASE_Z: /* Time zone hours part. */
706 {
707 int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number);
708
709 if (time_zone >= 0)
710 {
711 *dest_p++ = LIT_CHAR_PLUS;
712 }
713 else
714 {
715 *dest_p++ = LIT_CHAR_MINUS;
716 time_zone = -time_zone;
717 }
718
719 number = time_zone / (int32_t) ECMA_DATE_MS_PER_HOUR;
720 number_length = 2;
721 break;
722 }
723 default:
724 {
725 JERRY_ASSERT (*format_p == LIT_CHAR_UPPERCASE_Z); /* Time zone minutes part. */
726
727 int32_t time_zone = (int32_t) ecma_date_local_time_zone_adjustment (datetime_number);
728
729 if (time_zone < 0)
730 {
731 time_zone = -time_zone;
732 }
733
734 number = time_zone % (int32_t) ECMA_DATE_MS_PER_HOUR / (int32_t) ECMA_DATE_MS_PER_MINUTE;
735 number_length = 2;
736 break;
737 }
738 }
739
740 format_p++;
741
742 if (str_p != NULL)
743 {
744 /* Print string values: month or day name which is always 3 characters */
745 memcpy (dest_p, str_p, 3);
746 dest_p += 3;
747 continue;
748 }
749
750 /* Print right aligned number values. */
751 JERRY_ASSERT (number_length > 0);
752
753 if (number < 0)
754 {
755 number = -number;
756 *dest_p++ = '-';
757 }
758 else if (*(format_p - 1) == LIT_CHAR_LOWERCASE_Y && number_length == 6)
759 {
760 /* positive sign is compulsory for extended years */
761 *dest_p++ = '+';
762 }
763
764 dest_p += number_length;
765 lit_utf8_byte_t *buffer_p = dest_p;
766
767 do
768 {
769 buffer_p--;
770 *buffer_p = (lit_utf8_byte_t) ((number % 10) + (int32_t) LIT_CHAR_0);
771 number /= 10;
772 }
773 while (--number_length);
774 }
775
776 JERRY_ASSERT (dest_p <= date_buffer + date_buffer_length);
777
778 return ecma_make_string_value (ecma_new_ecma_string_from_utf8 (date_buffer,
779 (lit_utf8_size_t) (dest_p - date_buffer)));
780 } /* ecma_date_to_string_format */
781
782 /**
783 * Common function to create a time zone specific string from a numeric value.
784 *
785 * Used by:
786 * - The Date routine.
787 * - The Date.prototype.toString routine.
788 *
789 * @return ecma value
790 * Returned value must be freed with ecma_free_value.
791 */
792 ecma_value_t
ecma_date_value_to_string(ecma_number_t datetime_number)793 ecma_date_value_to_string (ecma_number_t datetime_number) /**< datetime */
794 {
795 datetime_number += ecma_date_local_time_zone_adjustment (datetime_number);
796 return ecma_date_to_string_format (datetime_number, "$W $M $D $Y $h:$m:$s GMT$z$Z");
797 } /* ecma_date_value_to_string */
798
799 /**
800 * Common function to create a time zone specific string from a numeric value.
801 *
802 * Used by:
803 * - The Date.prototype.toUTCString routine.
804 *
805 * @return ecma value
806 * Returned value must be freed with ecma_free_value.
807 */
808 ecma_value_t
ecma_date_value_to_utc_string(ecma_number_t datetime_number)809 ecma_date_value_to_utc_string (ecma_number_t datetime_number) /**< datetime */
810 {
811 return ecma_date_to_string_format (datetime_number, "$W, $D $M $Y $h:$m:$s GMT");
812 } /* ecma_date_value_to_utc_string */
813
814 /**
815 * Common function to create a ISO specific string from a numeric value.
816 *
817 * Used by:
818 * - The Date.prototype.toISOString routine.
819 *
820 * @return ecma value
821 * Returned value must be freed with ecma_free_value.
822 */
823 ecma_value_t
ecma_date_value_to_iso_string(ecma_number_t datetime_number)824 ecma_date_value_to_iso_string (ecma_number_t datetime_number) /**<datetime */
825 {
826 return ecma_date_to_string_format (datetime_number, "$y-$O-$DT$h:$m:$s.$iZ");
827 } /* ecma_date_value_to_iso_string */
828
829 /**
830 * Common function to create a date string from a numeric value.
831 *
832 * Used by:
833 * - The Date.prototype.toDateString routine.
834 *
835 * @return ecma value
836 * Returned value must be freed with ecma_free_value.
837 */
838 ecma_value_t
ecma_date_value_to_date_string(ecma_number_t datetime_number)839 ecma_date_value_to_date_string (ecma_number_t datetime_number) /**<datetime */
840 {
841 return ecma_date_to_string_format (datetime_number, "$Y-$O-$D");
842 } /* ecma_date_value_to_date_string */
843
844 /**
845 * Common function to create a time string from a numeric value.
846 *
847 * Used by:
848 * - The Date.prototype.toTimeString routine.
849 *
850 * @return ecma value
851 * Returned value must be freed with ecma_free_value.
852 */
853 ecma_value_t
ecma_date_value_to_time_string(ecma_number_t datetime_number)854 ecma_date_value_to_time_string (ecma_number_t datetime_number) /**<datetime */
855 {
856 return ecma_date_to_string_format (datetime_number, "$h:$m:$s.$i");
857 } /* ecma_date_value_to_time_string */
858
859 /**
860 * @}
861 * @}
862 */
863
864 #endif /* ENABLED (JERRY_BUILTIN_DATE) */
865