Skip to content

Commit 65cef6b

Browse files
committed
Implement Date.parse
JerryScript-DCO-1.0-Signed-off-by: László Langó [email protected]
1 parent 017aa6b commit 65cef6b

File tree

3 files changed

+303
-3
lines changed

3 files changed

+303
-3
lines changed

jerry-core/ecma/builtin-objects/ecma-builtin-date.cpp

Lines changed: 244 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@
1515
*/
1616

1717
#include "ecma-alloc.h"
18+
#include "ecma-builtin-helpers.h"
19+
#include "ecma-conversion.h"
1820
#include "ecma-globals.h"
1921
#include "ecma-helpers.h"
22+
#include "ecma-try-catch-macro.h"
2023

2124
#ifndef CONFIG_ECMA_COMPACT_PROFILE_DISABLE_DATE_BUILTIN
2225

@@ -37,20 +40,259 @@
3740
* @{
3841
*/
3942

43+
/**
44+
* Helper function to try to parse a part of a date string
45+
*
46+
* @return NaN if cannot read from string, ToNumber() otherwise
47+
*/
48+
static ecma_number_t
49+
ecma_date_parse_date_chars (lit_utf8_byte_t *date_start_p, /**< start pointer of the utf8 string */
50+
lit_utf8_byte_t **date_char_p, /**< current pointer of the utf8 string */
51+
lit_utf8_size_t date_str_size, /**< size of the utf8 string */
52+
uint32_t num_of_chars) /**< number of characters to read and convert */
53+
{
54+
ecma_number_t ret_value = ecma_number_make_nan ();
55+
JERRY_ASSERT ((*date_char_p - date_start_p) >= 0);
56+
uint32_t num_of_visited_chars = (uint32_t) (*date_char_p - date_start_p);
57+
58+
if ((date_str_size - num_of_visited_chars) >= num_of_chars)
59+
{
60+
ecma_string_t *str_p = ecma_new_ecma_string_from_utf8 (*date_char_p, num_of_chars);
61+
ret_value = ecma_string_to_number (str_p);
62+
ecma_deref_ecma_string (str_p);
63+
64+
*date_char_p += num_of_chars * sizeof (lit_utf8_byte_t);
65+
}
66+
67+
return ret_value;
68+
} /* ecma_date_parse_date_chars */
69+
4070
/**
4171
* The Date object's 'parse' routine
4272
*
4373
* See also:
4474
* ECMA-262 v5, 15.9.4.2
75+
* ECMA-262 v5, 15.9.1.15
4576
*
4677
* @return completion value
4778
* Returned value must be freed with ecma_free_completion_value.
4879
*/
4980
static ecma_completion_value_t
50-
ecma_builtin_date_parse (ecma_value_t this_arg, /**< this argument */
81+
ecma_builtin_date_parse (ecma_value_t this_arg __attr_unused___, /**< this argument */
5182
ecma_value_t arg) /**< string */
5283
{
53-
ECMA_BUILTIN_CP_UNIMPLEMENTED (this_arg, arg);
84+
ecma_completion_value_t ret_value = ecma_make_empty_completion_value ();
85+
ecma_number_t *date_num_p = ecma_alloc_number ();
86+
*date_num_p = ecma_number_make_nan ();
87+
ecma_number_t time = ECMA_NUMBER_ZERO;
88+
89+
/* Date Time String fromat (ECMA-262 v5, 15.9.1.15) */
90+
ecma_string_t *date_str_p;
91+
ECMA_TRY_CATCH (date_str_value,
92+
ecma_op_to_string (arg),
93+
ret_value);
94+
95+
date_str_p = ecma_get_string_from_value (date_str_value);
96+
97+
lit_utf8_size_t date_str_size = ecma_string_get_size (date_str_p);
98+
MEM_DEFINE_LOCAL_ARRAY (date_start_p, date_str_size, lit_utf8_byte_t);
99+
100+
ecma_string_to_utf8_string (date_str_p, date_start_p, (ssize_t) date_str_size);
101+
102+
lit_utf8_byte_t *date_char_p = date_start_p;
103+
104+
ecma_number_t year;
105+
ecma_number_t month = ECMA_NUMBER_ONE;
106+
ecma_number_t day = ECMA_NUMBER_ONE;
107+
ecma_number_t hours = ECMA_NUMBER_ZERO;
108+
ecma_number_t minutes = ECMA_NUMBER_ZERO;
109+
ecma_number_t seconds = ECMA_NUMBER_ZERO;
110+
ecma_number_t milliseconds = ECMA_NUMBER_ZERO;
111+
112+
/* 1. read year */
113+
year = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 4);
114+
115+
if (ecma_number_is_nan (year)
116+
|| year < 0)
117+
{
118+
goto end; /* NaN */
119+
}
120+
121+
/* 2. read month if any */
122+
if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p)
123+
&& *date_char_p == '-')
124+
{
125+
/* eat up '-' */
126+
date_char_p += sizeof (lit_utf8_byte_t);
127+
month = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
128+
129+
if (ecma_number_is_nan (month)
130+
|| month > 12
131+
|| month < 1)
132+
{
133+
goto end; /* NaN */
134+
}
135+
}
136+
137+
/* 3. read day if any */
138+
if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p)
139+
&& *date_char_p == '-')
140+
{
141+
/* eat up '-' */
142+
date_char_p += sizeof (lit_utf8_byte_t);
143+
day = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
144+
145+
if (ecma_number_is_nan (day)
146+
|| day < 1
147+
|| day > 31)
148+
{
149+
goto end; /* NaN */
150+
}
151+
}
152+
153+
/* 4. read time if any */
154+
if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p)
155+
&& *date_char_p == 'T')
156+
{
157+
/* 4.1 read hours and minutes */
158+
JERRY_ASSERT ((date_char_p - date_start_p) >= 0);
159+
uint32_t num_of_visited_chars = (uint32_t) (date_char_p - date_start_p);
160+
161+
if ((date_str_size - num_of_visited_chars) < 5)
162+
{
163+
goto end; /* NaN */
164+
}
165+
166+
/* eat up 'T' */
167+
date_char_p += sizeof (lit_utf8_byte_t);
168+
hours = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
169+
170+
if (ecma_number_is_nan (hours)
171+
|| hours < 0
172+
|| hours > 24)
173+
{
174+
goto end; /* NaN */
175+
}
176+
177+
/* eat up ':' */
178+
date_char_p += sizeof (lit_utf8_byte_t);
179+
180+
minutes = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
181+
182+
if (ecma_number_is_nan (minutes)
183+
|| minutes < 0
184+
|| minutes > 59)
185+
{
186+
goto end; /* NaN */
187+
}
188+
189+
/* 4.2 read seconds if any */
190+
if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p) && *date_char_p == ':')
191+
{
192+
/* eat up ':' */
193+
date_char_p += sizeof (lit_utf8_byte_t);
194+
seconds = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
195+
196+
if (ecma_number_is_nan (seconds)
197+
|| seconds < 0
198+
|| seconds > 59)
199+
{
200+
goto end; /* NaN */
201+
}
202+
203+
/* 4.3 read milliseconds if any */
204+
if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p) && *date_char_p == '.')
205+
{
206+
/* eat up '.' */
207+
date_char_p += sizeof (lit_utf8_byte_t);
208+
milliseconds = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 3);
209+
210+
if (ecma_number_is_nan (milliseconds)
211+
|| milliseconds < 0)
212+
{
213+
goto end; /* NaN */
214+
}
215+
}
216+
217+
time = ecma_date_make_time (hours, minutes, seconds, milliseconds);
218+
}
219+
220+
/* 4.4 read timezone if any */
221+
if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p) && *date_char_p == 'Z')
222+
{
223+
date_char_p += sizeof (lit_utf8_byte_t);
224+
time = ecma_date_utc (ecma_date_make_time (hours,
225+
minutes,
226+
seconds,
227+
milliseconds));
228+
}
229+
else if (date_str_size != (lit_utf8_size_t) (date_char_p - date_start_p)
230+
&& (*date_char_p == '+' || *date_char_p == '-'))
231+
{
232+
JERRY_ASSERT ((date_char_p - date_start_p) >= 0);
233+
uint32_t num_of_visited_chars = (uint32_t) (date_char_p - date_start_p);
234+
235+
if ((date_str_size - num_of_visited_chars) < 6)
236+
{
237+
goto end; /* NaN */
238+
}
239+
240+
bool is_negative = false;
241+
242+
if (*date_char_p == '-')
243+
{
244+
is_negative = true;
245+
}
246+
247+
/* eat up '+/-' */
248+
date_char_p += sizeof (lit_utf8_byte_t);
249+
250+
/* 4.1 read hours and minutes */
251+
hours = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
252+
253+
if (ecma_number_is_nan (hours)
254+
|| hours < 0
255+
|| hours > 24)
256+
{
257+
goto end; /* NaN */
258+
}
259+
260+
/* eat up ':' */
261+
date_char_p += sizeof (lit_utf8_byte_t);
262+
263+
minutes = ecma_date_parse_date_chars (date_start_p, &date_char_p, date_str_size, 2);
264+
265+
if (ecma_number_is_nan (minutes)
266+
|| minutes < 0
267+
|| minutes > 59)
268+
{
269+
goto end; /* NaN */
270+
}
271+
272+
if (is_negative)
273+
{
274+
time += ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
275+
}
276+
else
277+
{
278+
time -= ecma_date_make_time (hours, minutes, ECMA_NUMBER_ZERO, ECMA_NUMBER_ZERO);
279+
}
280+
}
281+
}
282+
283+
if (date_str_size == (lit_utf8_size_t) (date_char_p - date_start_p))
284+
{
285+
ecma_number_t date = ecma_date_make_day (year, month - 1, day);
286+
*date_num_p = ecma_date_make_date (date, time);
287+
}
288+
289+
end:
290+
ret_value = ecma_make_normal_completion_value (ecma_make_number_value (date_num_p));
291+
292+
MEM_FINALIZE_LOCAL_ARRAY (date_start_p);
293+
ECMA_FINALIZE (date_str_value);
294+
295+
return ret_value;
54296
} /* ecma_builtin_date_parse */
55297

56298
/**

jerry-core/ecma/builtin-objects/ecma-builtin-helpers-date.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ ecma_date_in_leap_year (ecma_number_t time) /**< time value */
215215
return time; /* time is NaN */
216216
}
217217

218-
return ecma_date_days_in_year (ecma_date_time_from_year (time)) - 365;
218+
return ecma_date_days_in_year (ecma_date_year_from_time (time)) - 365;
219219
} /* ecma_date_in_leap_year */
220220

221221
/**

tests/jerry/date-parse.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright 2015 Samsung Electronics Co., Ltd.
2+
// Copyright 2015 University of Szeged.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
var wrongFormats = ["", "2", "20", "201", "2015-", "2015-01-", "2015-01-01-",
17+
"qwerty", "2015-01-01T", "2015-01-01T1:1", "2015-01-01T01",
18+
"2015-01-01T01", "2015-01-01T01:01F", "T2015", "2015-01-01Z",
19+
"2015-01-01+01:00", "2015-01-01T00:00+01", "2015-01-01T00:00+1",
20+
"2015-01-01T00:00-01", "2015-01-01T00:00.000", "2015-01-01T00:00:",
21+
"2015-01-01T00:", "2015-01-01T00:00:00.1", "2015-01-01T00:00:00.01",
22+
"2015-01-01T00:00+01:00Z", "2015/01/01", "2015-01-32", "2015--1",
23+
"2015-13", "2015-01--1", "-215", "-215-01-01", "2015-01-00",
24+
"2015-01-01T25:00", "2015-01-01T00:60", "2015-01-01T-1:00",
25+
"2015-01-01T00:-1"];
26+
27+
for (i in wrongFormats) {
28+
var d = Date.parse(wrongFormats[i]);
29+
assert (isNaN(d));
30+
}
31+
32+
var d;
33+
d = Date.parse("2015");
34+
assert (d == 1420070400000);
35+
36+
d = Date.parse("2015-01");
37+
assert (d == 1420070400000);
38+
39+
d = Date.parse("2015-01-01");
40+
assert (d == 1420070400000);
41+
42+
d = Date.parse("2015-01T00:00");
43+
assert (d == 1420070400000);
44+
45+
d = Date.parse("2015-01T00:00:00");
46+
assert (d == 1420070400000);
47+
48+
d = Date.parse("2015-01T00:00:00.000");
49+
assert (d == 1420070400000);
50+
51+
d = Date.parse("2015-01T00:00:00.000+03:00");
52+
assert (d == 1420059600000);
53+
54+
d = Date.parse("2015-01T00:00:00.000-03:00");
55+
assert (d == 1420081200000);
56+
57+
d = Date.parse("2015-07-03T14:35:43.123+01:30");
58+
assert (d == 1435928743123);

0 commit comments

Comments
 (0)