Skip to content

Commit e72cb94

Browse files
jarrodconnollyaddaleax
authored andcommitted
n-api: implement date object
Implements `napi_create_date()` as well as `napi_is_date()` to allow working with JavaScript Date objects. PR-URL: #25917 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Colin Ihrig <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent d6759db commit e72cb94

File tree

7 files changed

+227
-0
lines changed

7 files changed

+227
-0
lines changed

doc/api/n-api.md

+73
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,7 @@ typedef enum {
243243
napi_queue_full,
244244
napi_closing,
245245
napi_bigint_expected,
246+
napi_date_expected,
246247
} napi_status;
247248
```
248249
If additional information is required upon an API returning a failed status,
@@ -1527,6 +1528,31 @@ This API allocates a `node::Buffer` object and initializes it with data copied
15271528
from the passed-in buffer. While this is still a fully-supported data
15281529
structure, in most cases using a `TypedArray` will suffice.
15291530

1531+
#### napi_create_date
1532+
<!-- YAML
1533+
added: REPLACEME
1534+
napiVersion: 4
1535+
-->
1536+
1537+
> Stability: 1 - Experimental
1538+
1539+
```C
1540+
napi_status napi_create_date(napi_env env,
1541+
double time,
1542+
napi_value* result);
1543+
```
1544+
1545+
- `[in] env`: The environment that the API is invoked under.
1546+
- `[in] time`: ECMAScript time value in milliseconds since 01 January, 1970 UTC.
1547+
- `[out] result`: A `napi_value` representing a JavaScript `Date`.
1548+
1549+
Returns `napi_ok` if the API succeeded.
1550+
1551+
This API allocates a JavaScript `Date` object.
1552+
1553+
JavaScript `Date` objects are described in
1554+
[Section 20.3][] of the ECMAScript Language Specification.
1555+
15301556
#### napi_create_external
15311557
<!-- YAML
15321558
added: v8.0.0
@@ -2147,6 +2173,31 @@ Returns `napi_ok` if the API succeeded.
21472173

21482174
This API returns various properties of a `DataView`.
21492175

2176+
#### napi_get_date_value
2177+
<!-- YAML
2178+
added: REPLACEME
2179+
napiVersion: 4
2180+
-->
2181+
2182+
> Stability: 1 - Experimental
2183+
2184+
```C
2185+
napi_status napi_get_date_value(napi_env env,
2186+
napi_value value,
2187+
double* result)
2188+
```
2189+
2190+
- `[in] env`: The environment that the API is invoked under.
2191+
- `[in] value`: `napi_value` representing a JavaScript `Date`.
2192+
- `[out] result`: Time value as a `double` represented as milliseconds
2193+
since midnight at the beginning of 01 January, 1970 UTC.
2194+
2195+
Returns `napi_ok` if the API succeeded. If a non-date `napi_value` is passed
2196+
in it returns `napi_date_expected`.
2197+
2198+
This API returns the C double primitive of time value for the given JavaScript
2199+
`Date`.
2200+
21502201
#### napi_get_value_bool
21512202
<!-- YAML
21522203
added: v8.0.0
@@ -2731,6 +2782,27 @@ Returns `napi_ok` if the API succeeded.
27312782

27322783
This API checks if the `Object` passed in is a buffer.
27332784

2785+
### napi_is_date
2786+
<!-- YAML
2787+
added: REPLACEME
2788+
napiVersion: 4
2789+
-->
2790+
2791+
> Stability: 1 - Experimental
2792+
2793+
```C
2794+
napi_status napi_is_date(napi_env env, napi_value value, bool* result)
2795+
```
2796+
2797+
- `[in] env`: The environment that the API is invoked under.
2798+
- `[in] value`: The JavaScript value to check.
2799+
- `[out] result`: Whether the given `napi_value` represents a JavaScript `Date`
2800+
object.
2801+
2802+
Returns `napi_ok` if the API succeeded.
2803+
2804+
This API checks if the `Object` passed in is a date.
2805+
27342806
### napi_is_error
27352807
<!-- YAML
27362808
added: v8.0.0
@@ -4712,6 +4784,7 @@ This API may only be called from the main thread.
47124784
[Object Lifetime Management]: #n_api_object_lifetime_management
47134785
[Object Wrap]: #n_api_object_wrap
47144786
[Section 12.5.5]: https://tc39.github.io/ecma262/#sec-typeof-operator
4787+
[Section 20.3]: https://tc39.github.io/ecma262/#sec-date-objects
47154788
[Section 22.1]: https://tc39.github.io/ecma262/#sec-array-objects
47164789
[Section 22.2]: https://tc39.github.io/ecma262/#sec-typedarray-objects
47174790
[Section 24.1]: https://tc39.github.io/ecma262/#sec-arraybuffer-objects

src/js_native_api.h

+14
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,20 @@ NAPI_EXTERN napi_status napi_adjust_external_memory(napi_env env,
449449

450450
#ifdef NAPI_EXPERIMENTAL
451451

452+
// Dates
453+
NAPI_EXTERN napi_status napi_create_date(napi_env env,
454+
double time,
455+
napi_value* result);
456+
457+
NAPI_EXTERN napi_status napi_is_date(napi_env env,
458+
napi_value value,
459+
bool* is_date);
460+
461+
NAPI_EXTERN napi_status napi_get_date_value(napi_env env,
462+
napi_value value,
463+
double* result);
464+
465+
// BigInt
452466
NAPI_EXTERN napi_status napi_create_bigint_int64(napi_env env,
453467
int64_t value,
454468
napi_value* result);

src/js_native_api_types.h

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ typedef enum {
7676
napi_queue_full,
7777
napi_closing,
7878
napi_bigint_expected,
79+
napi_date_expected,
7980
} napi_status;
8081

8182
typedef napi_value (*napi_callback)(napi_env env,

src/js_native_api_v8.cc

+42
Original file line numberDiff line numberDiff line change
@@ -2887,6 +2887,48 @@ napi_status napi_is_promise(napi_env env,
28872887
return napi_clear_last_error(env);
28882888
}
28892889

2890+
napi_status napi_create_date(napi_env env,
2891+
double time,
2892+
napi_value* result) {
2893+
NAPI_PREAMBLE(env);
2894+
CHECK_ARG(env, result);
2895+
2896+
v8::MaybeLocal<v8::Value> maybe_date = v8::Date::New(env->context(), time);
2897+
CHECK_MAYBE_EMPTY(env, maybe_date, napi_generic_failure);
2898+
2899+
*result = v8impl::JsValueFromV8LocalValue(maybe_date.ToLocalChecked());
2900+
2901+
return GET_RETURN_STATUS(env);
2902+
}
2903+
2904+
napi_status napi_is_date(napi_env env,
2905+
napi_value value,
2906+
bool* is_date) {
2907+
CHECK_ENV(env);
2908+
CHECK_ARG(env, value);
2909+
CHECK_ARG(env, is_date);
2910+
2911+
*is_date = v8impl::V8LocalValueFromJsValue(value)->IsDate();
2912+
2913+
return napi_clear_last_error(env);
2914+
}
2915+
2916+
napi_status napi_get_date_value(napi_env env,
2917+
napi_value value,
2918+
double* result) {
2919+
NAPI_PREAMBLE(env);
2920+
CHECK_ARG(env, value);
2921+
CHECK_ARG(env, result);
2922+
2923+
v8::Local<v8::Value> val = v8impl::V8LocalValueFromJsValue(value);
2924+
RETURN_STATUS_IF_FALSE(env, val->IsDate(), napi_date_expected);
2925+
2926+
v8::Local<v8::Date> date = val.As<v8::Date>();
2927+
*result = date->ValueOf();
2928+
2929+
return GET_RETURN_STATUS(env);
2930+
}
2931+
28902932
napi_status napi_run_script(napi_env env,
28912933
napi_value script,
28922934
napi_value* result) {
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "test_date",
5+
"sources": [
6+
"../entry_point.c",
7+
"test_date.c"
8+
]
9+
}
10+
]
11+
}

test/js-native-api/test_date/test.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const common = require('../../common');
4+
5+
// This tests the date-related n-api calls
6+
7+
const assert = require('assert');
8+
const test_date = require(`./build/${common.buildType}/test_date`);
9+
10+
const dateTypeTestDate = test_date.createDate(1549183351);
11+
assert.strictEqual(test_date.isDate(dateTypeTestDate), true);
12+
13+
assert.strictEqual(test_date.isDate(new Date(1549183351)), true);
14+
15+
assert.strictEqual(test_date.isDate(2.4), false);
16+
assert.strictEqual(test_date.isDate('not a date'), false);
17+
assert.strictEqual(test_date.isDate(undefined), false);
18+
assert.strictEqual(test_date.isDate(null), false);
19+
assert.strictEqual(test_date.isDate({}), false);
20+
21+
assert.strictEqual(test_date.getDateValue(new Date(1549183351)), 1549183351);
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#define NAPI_EXPERIMENTAL
2+
3+
#include <js_native_api.h>
4+
#include "../common.h"
5+
6+
static napi_value createDate(napi_env env, napi_callback_info info) {
7+
size_t argc = 1;
8+
napi_value args[1];
9+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL));
10+
11+
NAPI_ASSERT(env, argc >= 1, "Wrong number of arguments");
12+
13+
napi_valuetype valuetype0;
14+
NAPI_CALL(env, napi_typeof(env, args[0], &valuetype0));
15+
16+
NAPI_ASSERT(env, valuetype0 == napi_number,
17+
"Wrong type of arguments. Expects a number as first argument.");
18+
19+
double time;
20+
NAPI_CALL(env, napi_get_value_double(env, args[0], &time));
21+
22+
napi_value date;
23+
NAPI_CALL(env, napi_create_date(env, time, &date));
24+
25+
return date;
26+
}
27+
28+
static napi_value isDate(napi_env env, napi_callback_info info) {
29+
napi_value date, result;
30+
size_t argc = 1;
31+
bool is_date;
32+
33+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL));
34+
NAPI_CALL(env, napi_is_date(env, date, &is_date));
35+
NAPI_CALL(env, napi_get_boolean(env, is_date, &result));
36+
37+
return result;
38+
}
39+
40+
static napi_value getDateValue(napi_env env, napi_callback_info info) {
41+
napi_value date, result;
42+
size_t argc = 1;
43+
double value;
44+
45+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &date, NULL, NULL));
46+
NAPI_CALL(env, napi_get_date_value(env, date, &value));
47+
NAPI_CALL(env, napi_create_double(env, value, &result));
48+
49+
return result;
50+
}
51+
52+
EXTERN_C_START
53+
napi_value Init(napi_env env, napi_value exports) {
54+
napi_property_descriptor descriptors[] = {
55+
DECLARE_NAPI_PROPERTY("createDate", createDate),
56+
DECLARE_NAPI_PROPERTY("isDate", isDate),
57+
DECLARE_NAPI_PROPERTY("getDateValue", getDateValue),
58+
};
59+
60+
NAPI_CALL(env, napi_define_properties(
61+
env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
62+
63+
return exports;
64+
}
65+
EXTERN_C_END

0 commit comments

Comments
 (0)