From 5060e6b04266ea7cd5435d22465660af981483d4 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Mon, 19 Dec 2016 23:48:26 +0200 Subject: [PATCH 1/4] Change time API zero/one basedness to match ES --- src-input/duk_api_time.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src-input/duk_api_time.c b/src-input/duk_api_time.c index 20090f1c..af17216d 100644 --- a/src-input/duk_api_time.c +++ b/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_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; duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags); /* XXX: expensive conversion */ + DUK_ASSERT(comp->month >= 1 && comp->month <= 12); 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->hour = (duk_uint_t) parts[DUK_DATE_IDX_HOUR]; 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_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 * 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_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_MINUTE] = (duk_double_t) comp->minute; dparts[DUK_DATE_IDX_SECOND] = (duk_double_t) comp->second; dparts[DUK_DATE_IDX_MILLISECOND] = comp->millisecond; 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); return d; From 60783bff65d45163fa0668dab4a5db12b6af7793 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Mon, 19 Dec 2016 23:48:43 +0200 Subject: [PATCH 2/4] API test updates for zero/one based time --- tests/api/test-time-components.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/api/test-time-components.c b/tests/api/test-time-components.c index 59d95454..d7c39608 100644 --- a/tests/api/test-time-components.c +++ b/tests/api/test-time-components.c @@ -12,13 +12,15 @@ hours 3 minutes 4 seconds 5 milliseconds 6 +weekday 6 year: 2016 -month: 1 +month: 0 day: 2 hour: 3 minute: 4 second: 5 millisecond: 6.000000 +weekday: 6 final top: 0 ==> rc=0, result='undefined' ===*/ @@ -31,7 +33,8 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { /* Ecmascript time-to-components (UTC): * * - 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, @@ -45,13 +48,10 @@ static duk_ret_t test_1(duk_context *ctx, void *udata) { " print('minutes', d.getUTCMinutes());\n" " print('seconds', d.getUTCSeconds());\n" " print('milliseconds', d.getUTCMilliseconds());\n" + " print('weekday', d.getUTCDay());\n" "})();"); - /* C API equivalent: - * - * - comp.month is one-based. - * - comp.day is one-based. - */ + /* C API equivalent. */ duk_time_to_components(ctx, 1451703845006.0, &comp); 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("second: %d\n", (int) comp.second); printf("millisecond: %lf\n", (double) comp.millisecond); + printf("weekday: %d\n", (int) comp.weekday); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; @@ -100,16 +101,14 @@ static duk_ret_t test_2(duk_context *ctx, void *udata) { " print(d.valueOf())\n" "})();"); - /* C API equivalent: + /* C API equivalent; note that: * * - No special handling for two-digit years. - * - comp.month is one-based. - * - comp.day is one-based. */ memset((void *) &comp, 0, sizeof(comp)); comp.year = 2016; - comp.month = 1; + comp.month = 0; comp.day = 2; comp.hour = 3; comp.minute = 4; @@ -122,7 +121,7 @@ static duk_ret_t test_2(duk_context *ctx, void *udata) { memset((void *) &comp, 0, sizeof(comp)); comp.year = 2016; - comp.month = 1; + comp.month = 0; comp.day = 2; comp.hour = 3; comp.minute = 0; From f0c2e778834e0abb51f20c7033c900bc963f30b3 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Tue, 20 Dec 2016 00:13:17 +0200 Subject: [PATCH 3/4] API doc changes for time zero/one basedness --- website/api/duk_components_to_time.yaml | 5 ++--- website/api/duk_time_to_components.yaml | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/website/api/duk_components_to_time.yaml b/website/api/duk_components_to_time.yaml index fe53338b..adf60495 100644 --- a/website/api/duk_components_to_time.yaml +++ b/website/api/duk_components_to_time.yaml @@ -14,7 +14,6 @@ summary: |
  • There's no special handling of two-digit years. For example, Date.UTC(99, 0, 1) gets interpreted as 1999-01-01. If comp->time is 99, it's interpreted as the year 99.
  • -
  • The month component is one-based, not zero-based.
  • The milliseconds component is allowed fractions (sub-millisecond resolution) so that the resulting time value may have fractions.
  • @@ -31,8 +30,8 @@ example: | memset((void *) &comp, 0, sizeof(comp)); /* good practice even if fully initialized */ comp.year = 2016; - comp.month = 1; /* 1-based, 1=January */ - comp.day = 2; /* 1-based */ + comp.month = 0; /* 0-based, 1=January */ + comp.day = 2; /* 1-based: second of January */ comp.hour = 3; comp.minute = 4; comp.second = 5; diff --git a/website/api/duk_time_to_components.yaml b/website/api/duk_time_to_components.yaml index 872957db..f02bb3e1 100644 --- a/website/api/duk_time_to_components.yaml +++ b/website/api/duk_time_to_components.yaml @@ -11,7 +11,6 @@ summary: |

    There are some differences to the Ecmascript Date UTC accessors like Date.prototype.getUTCMinutes():

      -
    • The month component is one-based, not zero-based.
    • The time value is allowed to have fractions (sub-millisecond resolution) so that the millisecond component may also have fractions.
    • @@ -25,9 +24,12 @@ example: | "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); 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.millisecond); From 7e48f01640ce5ea57472cd1b4a211f68cef5c060 Mon Sep 17 00:00:00 2001 From: Sami Vaarala Date: Tue, 20 Dec 2016 00:06:06 +0200 Subject: [PATCH 4/4] Releases: time API zero vs. one-based --- RELEASES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASES.rst b/RELEASES.rst index ac42c79b..6b9c5c9b 100644 --- a/RELEASES.rst +++ b/RELEASES.rst @@ -1965,7 +1965,7 @@ Planned * 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 - 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 internal prototype, equivalent to Object.create(null) (GH-1126)