Browse Source

Merge pull request #1209 from svaarala/api-get-time-zerobased-month

Make month in the time API zero-based to match Ecmascript APIs
pull/1213/head
Sami Vaarala 8 years ago
committed by GitHub
parent
commit
9b8129ad2f
  1. 2
      RELEASES.rst
  2. 20
      src-input/duk_api_time.c
  3. 23
      tests/api/test-time-components.c
  4. 5
      website/api/duk_components_to_time.yaml
  5. 6
      website/api/duk_time_to_components.yaml

2
RELEASES.rst

@ -1965,7 +1965,7 @@ Planned
* Add time functions to the C API (duk_get_now(), duk_time_to_components(), * Add time functions to the C API (duk_get_now(), duk_time_to_components(),
duk_components_to_time()) to allow C code to conveniently work with the duk_components_to_time()) to allow C code to conveniently work with the
same time provider as seen by Ecmascript code (GH-771) same time provider as seen by Ecmascript code (GH-771, GH-1209)
* Add duk_push_bare_object() API call which pushes an object without an * Add duk_push_bare_object() API call which pushes an object without an
internal prototype, equivalent to Object.create(null) (GH-1126) internal prototype, equivalent to Object.create(null) (GH-1126)

20
src-input/duk_api_time.c

@ -17,14 +17,17 @@ DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval,
DUK_ASSERT(comp != NULL); /* XXX: or check? */ DUK_ASSERT(comp != NULL); /* XXX: or check? */
DUK_UNREF(ctx); DUK_UNREF(ctx);
/* XXX: one-based or zero-based? or expose flag(s)? */ /* Convert as one-based, but change month to zero-based to match the
* Ecmascript Date built-in behavior 1:1.
*/
flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO; flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO;
duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags); duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags);
/* XXX: expensive conversion */ /* XXX: expensive conversion */
DUK_ASSERT(comp->month >= 1 && comp->month <= 12);
comp->year = (duk_uint_t) parts[DUK_DATE_IDX_YEAR]; comp->year = (duk_uint_t) parts[DUK_DATE_IDX_YEAR];
comp->month = (duk_uint_t) parts[DUK_DATE_IDX_MONTH]; comp->month = (duk_uint_t) parts[DUK_DATE_IDX_MONTH] - 1;
comp->day = (duk_uint_t) parts[DUK_DATE_IDX_DAY]; comp->day = (duk_uint_t) parts[DUK_DATE_IDX_DAY];
comp->hour = (duk_uint_t) parts[DUK_DATE_IDX_HOUR]; comp->hour = (duk_uint_t) parts[DUK_DATE_IDX_HOUR];
comp->minute = (duk_uint_t) parts[DUK_DATE_IDX_MINUTE]; comp->minute = (duk_uint_t) parts[DUK_DATE_IDX_MINUTE];
@ -42,7 +45,12 @@ DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_comp
DUK_ASSERT(comp != NULL); /* XXX: or check? */ DUK_ASSERT(comp != NULL); /* XXX: or check? */
DUK_UNREF(ctx); DUK_UNREF(ctx);
flags = 0; /* XXX */ /* Match Date constructor behavior (with UTC time). Month is given
* as zero-based. Day-of-month is given as one-based so normalize
* it to zero-based as the internal conversion helpers expects all
* components to be zero-based.
*/
flags = 0;
/* XXX: expensive conversion; use array format in API instead, or unify /* XXX: expensive conversion; use array format in API instead, or unify
* time provider and time API to use same struct? * time provider and time API to use same struct?
@ -50,17 +58,13 @@ DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_comp
dparts[DUK_DATE_IDX_YEAR] = (duk_double_t) comp->year; dparts[DUK_DATE_IDX_YEAR] = (duk_double_t) comp->year;
dparts[DUK_DATE_IDX_MONTH] = (duk_double_t) comp->month; dparts[DUK_DATE_IDX_MONTH] = (duk_double_t) comp->month;
dparts[DUK_DATE_IDX_DAY] = (duk_double_t) comp->day; dparts[DUK_DATE_IDX_DAY] = (duk_double_t) comp->day - 1.0;
dparts[DUK_DATE_IDX_HOUR] = (duk_double_t) comp->hour; dparts[DUK_DATE_IDX_HOUR] = (duk_double_t) comp->hour;
dparts[DUK_DATE_IDX_MINUTE] = (duk_double_t) comp->minute; dparts[DUK_DATE_IDX_MINUTE] = (duk_double_t) comp->minute;
dparts[DUK_DATE_IDX_SECOND] = (duk_double_t) comp->second; dparts[DUK_DATE_IDX_SECOND] = (duk_double_t) comp->second;
dparts[DUK_DATE_IDX_MILLISECOND] = comp->millisecond; dparts[DUK_DATE_IDX_MILLISECOND] = comp->millisecond;
dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */ dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */
/* The internal call assumes zero-based day and month. */
dparts[DUK_DATE_IDX_MONTH] -= 1.0;
dparts[DUK_DATE_IDX_DAY] -= 1.0;
d = duk_bi_date_get_timeval_from_dparts(dparts, flags); d = duk_bi_date_get_timeval_from_dparts(dparts, flags);
return d; return d;

23
tests/api/test-time-components.c

@ -12,13 +12,15 @@ hours 3
minutes 4 minutes 4
seconds 5 seconds 5
milliseconds 6 milliseconds 6
weekday 6
year: 2016 year: 2016
month: 1 month: 0
day: 2 day: 2
hour: 3 hour: 3
minute: 4 minute: 4
second: 5 second: 5
millisecond: 6.000000 millisecond: 6.000000
weekday: 6
final top: 0 final top: 0
==> rc=0, result='undefined' ==> rc=0, result='undefined'
===*/ ===*/
@ -31,7 +33,8 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) {
/* Ecmascript time-to-components (UTC): /* Ecmascript time-to-components (UTC):
* *
* - d.getUTCMonth() is zero-based. * - d.getUTCMonth() is zero-based.
* - d.getUTCDate() is one-based. * - d.getUTCDate() (day in month) is one-based.
* - d.getUTCDay() (weekday) is zero-based.
*/ */
duk_eval_string_noresult(ctx, duk_eval_string_noresult(ctx,
@ -45,13 +48,10 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) {
" print('minutes', d.getUTCMinutes());\n" " print('minutes', d.getUTCMinutes());\n"
" print('seconds', d.getUTCSeconds());\n" " print('seconds', d.getUTCSeconds());\n"
" print('milliseconds', d.getUTCMilliseconds());\n" " print('milliseconds', d.getUTCMilliseconds());\n"
" print('weekday', d.getUTCDay());\n"
"})();"); "})();");
/* C API equivalent: /* C API equivalent. */
*
* - comp.month is one-based.
* - comp.day is one-based.
*/
duk_time_to_components(ctx, 1451703845006.0, &comp); duk_time_to_components(ctx, 1451703845006.0, &comp);
printf("year: %d\n", (int) comp.year); printf("year: %d\n", (int) comp.year);
@ -61,6 +61,7 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) {
printf("minute: %d\n", (int) comp.minute); printf("minute: %d\n", (int) comp.minute);
printf("second: %d\n", (int) comp.second); printf("second: %d\n", (int) comp.second);
printf("millisecond: %lf\n", (double) comp.millisecond); printf("millisecond: %lf\n", (double) comp.millisecond);
printf("weekday: %d\n", (int) comp.weekday);
printf("final top: %ld\n", (long) duk_get_top(ctx)); printf("final top: %ld\n", (long) duk_get_top(ctx));
return 0; return 0;
@ -100,16 +101,14 @@ static duk_ret_t test_2(duk_context *ctx, void *udata) {
" print(d.valueOf())\n" " print(d.valueOf())\n"
"})();"); "})();");
/* C API equivalent: /* C API equivalent; note that:
* *
* - No special handling for two-digit years. * - No special handling for two-digit years.
* - comp.month is one-based.
* - comp.day is one-based.
*/ */
memset((void *) &comp, 0, sizeof(comp)); memset((void *) &comp, 0, sizeof(comp));
comp.year = 2016; comp.year = 2016;
comp.month = 1; comp.month = 0;
comp.day = 2; comp.day = 2;
comp.hour = 3; comp.hour = 3;
comp.minute = 4; comp.minute = 4;
@ -122,7 +121,7 @@ static duk_ret_t test_2(duk_context *ctx, void *udata) {
memset((void *) &comp, 0, sizeof(comp)); memset((void *) &comp, 0, sizeof(comp));
comp.year = 2016; comp.year = 2016;
comp.month = 1; comp.month = 0;
comp.day = 2; comp.day = 2;
comp.hour = 3; comp.hour = 3;
comp.minute = 0; comp.minute = 0;

5
website/api/duk_components_to_time.yaml

@ -14,7 +14,6 @@ summary: |
<li>There's no special handling of two-digit years. For example, <li>There's no special handling of two-digit years. For example,
<code>Date.UTC(99, 0, 1)</code> gets interpreted as 1999-01-01. <code>Date.UTC(99, 0, 1)</code> gets interpreted as 1999-01-01.
If <code>comp-&gt;time</code> is 99, it's interpreted as the year 99.</li> If <code>comp-&gt;time</code> is 99, it's interpreted as the year 99.</li>
<li>The month component is one-based, not zero-based.</li>
<li>The milliseconds component is allowed fractions (sub-millisecond <li>The milliseconds component is allowed fractions (sub-millisecond
resolution) so that the resulting time value may have fractions.</li> resolution) so that the resulting time value may have fractions.</li>
</ul> </ul>
@ -31,8 +30,8 @@ example: |
memset((void *) &comp, 0, sizeof(comp)); /* good practice even if fully initialized */ memset((void *) &comp, 0, sizeof(comp)); /* good practice even if fully initialized */
comp.year = 2016; comp.year = 2016;
comp.month = 1; /* 1-based, 1=January */ comp.month = 0; /* 0-based, 1=January */
comp.day = 2; /* 1-based */ comp.day = 2; /* 1-based: second of January */
comp.hour = 3; comp.hour = 3;
comp.minute = 4; comp.minute = 4;
comp.second = 5; comp.second = 5;

6
website/api/duk_time_to_components.yaml

@ -11,7 +11,6 @@ summary: |
<p>There are some differences to the Ecmascript <code>Date</code> UTC <p>There are some differences to the Ecmascript <code>Date</code> UTC
accessors like <code>Date.prototype.getUTCMinutes()</code>:</p> accessors like <code>Date.prototype.getUTCMinutes()</code>:</p>
<ul> <ul>
<li>The month component is one-based, not zero-based.</li>
<li>The time value is allowed to have fractions (sub-millisecond <li>The time value is allowed to have fractions (sub-millisecond
resolution) so that the millisecond component may also have resolution) so that the millisecond component may also have
fractions.</li> fractions.</li>
@ -25,9 +24,12 @@ example: |
"Thursday", "Friday", "Saturday" "Thursday", "Friday", "Saturday"
}; };
/* Note that month is zero-based to match the Ecmascript API, so for
* human readable printing add 1 to the month.
*/
duk_time_components(ctx, time, &comp); duk_time_components(ctx, time, &comp);
printf("Datetime: %04d-%02d-%02d %02d:%02d:%02d.%03dZ\n", printf("Datetime: %04d-%02d-%02d %02d:%02d:%02d.%03dZ\n",
(int) comp.year, (int) comp.month, (int) comp.day, (int) comp.year, (int) (comp.month + 1), (int) comp.day,
(int) comp.hour, (int) comp.minute, (int) comp.second, (int) comp.hour, (int) comp.minute, (int) comp.second,
(int) comp.millisecond); (int) comp.millisecond);

Loading…
Cancel
Save