• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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