Skip to content

Commit

Permalink
src: add napi_date
Browse files Browse the repository at this point in the history
PR-URL: nodejs/node-addon-api#497
Reviewed-By: NickNaso <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
Reviewed-By: Gabriel Schulhof <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
  • Loading branch information
John French committed Sep 5, 2019
1 parent 90cefe4 commit 19f41af
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ The following is the documentation for node-addon-api.
- [String](doc/string.md)
- [Name](doc/basic_types.md#name)
- [Number](doc/number.md)
- [Date](doc/date.md)
- [BigInt](doc/bigint.md)
- [Boolean](doc/boolean.md)
- [Env](doc/env.md)
Expand Down
8 changes: 8 additions & 0 deletions doc/basic_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,14 @@ bool Napi::Value::IsExternal() const;
Returns `true` if the underlying value is a N-API external object or `false`
otherwise.

#### IsDate
```cpp
bool Napi::Value::IsDate() const;
```

Returns `true` if the underlying value is a JavaScript `Date` or `false`
otherwise.

#### ToBoolean
```cpp
Napi::Boolean Napi::Value::ToBoolean() const;
Expand Down
68 changes: 68 additions & 0 deletions doc/date.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Date

`Napi::Date` class is a representation of the JavaScript `Date` object. The
`Napi::Date` class inherits its behavior from `Napi::Value` class
(for more info see [`Napi::Value`](value.md))

## Methods

### Constructor

Creates a new _empty_ instance of a `Napi::Date` object.

```cpp
Napi::Date::Date();
```

Creates a new _non-empty_ instance of a `Napi::Date` object.

```cpp
Napi::Date::Date(napi_env env, napi_value value);
```
- `[in] env`: The environment in which to construct the `Napi::Date` object.
- `[in] value`: The `napi_value` which is a handle for a JavaScript `Date`.
### New
Creates a new instance of a `Napi::Date` object.
```cpp
static Napi::Date Napi::Date::New(Napi::Env env, double value);
```

- `[in] env`: The environment in which to construct the `Napi::Date` object.
- `[in] value`: The time value the JavaScript `Date` will contain represented
as the number of milliseconds since 1 January 1970 00:00:00 UTC.

Returns a new instance of `Napi::Date` object.

### ValueOf

```cpp
double Napi::Date::ValueOf() const;
```

Returns the time value as `double` primitive represented as the number of
milliseconds since 1 January 1970 00:00:00 UTC.

## Operators

### operator double

Converts a `Napi::Date` value to a `double` primitive.

```cpp
Napi::Date::operator double() const;
```

### Example

The following shows an example of casting a `Napi::Date` value to a `double`
primitive.

```cpp
double operatorVal = Napi::Date::New(Env(), 0); // Napi::Date to double
// or
auto instanceVal = info[0].As<Napi::Date>().ValueOf();
```
9 changes: 9 additions & 0 deletions doc/value.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The following classes inherit, either directly or indirectly, from `Napi::Value`
- [`Napi::ArrayBuffer`](array_buffer.md)
- [`Napi::Boolean`](boolean.md)
- [`Napi::Buffer`](buffer.md)
- [`Napi::Date`](date.md)
- [`Napi::External`](external.md)
- [`Napi::Function`](function.md)
- [`Napi::Name`](name.md)
Expand Down Expand Up @@ -226,6 +227,14 @@ bool Napi::Value::IsBuffer() const;

Returns a `bool` indicating if this `Napi::Value` is a Node buffer.

### IsDate

```cpp
bool Napi::Value::IsDate() const;
```

Returns a `bool` indicating if this `Napi::Value` is a JavaScript date.

### As

```cpp
Expand Down
44 changes: 44 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,19 @@ inline bool Value::IsBigInt() const {
}
#endif // NAPI_EXPERIMENTAL

#if (NAPI_VERSION > 4)
inline bool Value::IsDate() const {
if (IsEmpty()) {
return false;
}

bool result;
napi_status status = napi_is_date(_env, _value, &result);
NAPI_THROW_IF_FAILED(_env, status, false);
return result;
}
#endif

inline bool Value::IsString() const {
return Type() == napi_string;
}
Expand Down Expand Up @@ -660,6 +673,37 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
}
#endif // NAPI_EXPERIMENTAL

#if (NAPI_VERSION > 4)
////////////////////////////////////////////////////////////////////////////////
// Date Class
////////////////////////////////////////////////////////////////////////////////

inline Date Date::New(napi_env env, double val) {
napi_value value;
napi_status status = napi_create_date(env, val, &value);
NAPI_THROW_IF_FAILED(env, status, Date());
return Date(env, value);
}

inline Date::Date() : Value() {
}

inline Date::Date(napi_env env, napi_value value) : Value(env, value) {
}

inline Date::operator double() const {
return ValueOf();
}

inline double Date::ValueOf() const {
double result;
napi_status status = napi_get_date_value(
_env, _value, &result);
NAPI_THROW_IF_FAILED(_env, status, 0);
return result;
}
#endif

////////////////////////////////////////////////////////////////////////////////
// Name class
////////////////////////////////////////////////////////////////////////////////
Expand Down
24 changes: 24 additions & 0 deletions napi.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ namespace Napi {
#if (NAPI_VERSION > 2147483646)
class BigInt;
#endif // NAPI_EXPERIMENTAL
#if (NAPI_VERSION > 4)
class Date;
#endif
class String;
class Object;
class Array;
Expand Down Expand Up @@ -246,6 +249,9 @@ namespace Napi {
#if (NAPI_VERSION > 2147483646)
bool IsBigInt() const; ///< Tests if a value is a JavaScript bigint.
#endif // NAPI_EXPERIMENTAL
#if (NAPI_VERSION > 4)
bool IsDate() const; ///< Tests if a value is a JavaScript date.
#endif
bool IsString() const; ///< Tests if a value is a JavaScript string.
bool IsSymbol() const; ///< Tests if a value is a JavaScript symbol.
bool IsArray() const; ///< Tests if a value is a JavaScript array.
Expand Down Expand Up @@ -358,6 +364,24 @@ namespace Napi {
};
#endif // NAPI_EXPERIMENTAL

#if (NAPI_VERSION > 4)
/// A JavaScript date value.
class Date : public Value {
public:
/// Creates a new Date value from a double primitive.
static Date New(
napi_env env, ///< N-API environment
double value ///< Number value
);

Date(); ///< Creates a new _empty_ Date instance.
Date(napi_env env, napi_value value); ///< Wraps a N-API value primitive.
operator double() const; ///< Converts a Date value to double primitive

double ValueOf() const; ///< Converts a Date value to a double primitive.
};
#endif

/// A JavaScript string or symbol value (that can be used as a property name).
class Name : public Value {
public:
Expand Down
6 changes: 6 additions & 0 deletions test/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ Object InitBuffer(Env env);
#if (NAPI_VERSION > 2)
Object InitCallbackScope(Env env);
#endif
#if (NAPI_VERSION > 4)
Object InitDate(Env env);
#endif
Object InitDataView(Env env);
Object InitDataViewReadWrite(Env env);
Object InitError(Env env);
Expand Down Expand Up @@ -56,6 +59,9 @@ Object Init(Env env, Object exports) {
// released in once it is no longer experimental
#if (NAPI_VERSION > 2147483646)
exports.Set("bigint", InitBigInt(env));
#endif
#if (NAPI_VERSION > 4)
exports.Set("date", InitDate(env));
#endif
exports.Set("buffer", InitBuffer(env));
#if (NAPI_VERSION > 2)
Expand Down
1 change: 1 addition & 0 deletions test/binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
'basic_types/number.cc',
'basic_types/value.cc',
'bigint.cc',
'date.cc',
'binding.cc',
'buffer.cc',
'callbackscope.cc',
Expand Down
45 changes: 45 additions & 0 deletions test/date.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#define NAPI_EXPERIMENTAL
#include "napi.h"

using namespace Napi;

#if (NAPI_VERSION > 4)
namespace {

Value CreateDate(const CallbackInfo& info) {
double input = info[0].As<Number>().DoubleValue();

return Date::New(info.Env(), input);
}

Value IsDate(const CallbackInfo& info) {
Date input = info[0].As<Date>();

return Boolean::New(info.Env(), input.IsDate());
}

Value ValueOf(const CallbackInfo& info) {
Date input = info[0].As<Date>();

return Number::New(info.Env(), input.ValueOf());
}

Value OperatorValue(const CallbackInfo& info) {
Date input = info[0].As<Date>();

return Boolean::New(info.Env(), input.ValueOf() == static_cast<double>(input));
}

} // anonymous namespace

Object InitDate(Env env) {
Object exports = Object::New(env);
exports["CreateDate"] = Function::New(env, CreateDate);
exports["IsDate"] = Function::New(env, IsDate);
exports["ValueOf"] = Function::New(env, ValueOf);
exports["OperatorValue"] = Function::New(env, OperatorValue);

return exports;
}

#endif
20 changes: 20 additions & 0 deletions test/date.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict';

const buildType = process.config.target_defaults.default_configuration;
const assert = require('assert');

test(require(`./build/${buildType}/binding.node`));
test(require(`./build/${buildType}/binding_noexcept.node`));

function test(binding) {
const {
CreateDate,
IsDate,
ValueOf,
OperatorValue,
} = binding.date;
assert.deepStrictEqual(CreateDate(0), new Date(0));
assert.strictEqual(IsDate(new Date(0)), true);
assert.strictEqual(ValueOf(new Date(42)), 42);
assert.strictEqual(OperatorValue(new Date(42)), true);
}
6 changes: 6 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ let testModules = [
'basic_types/number',
'basic_types/value',
'bigint',
'date',
'buffer',
'callbackscope',
'dataview/dataview',
Expand Down Expand Up @@ -69,6 +70,11 @@ if ((process.env.npm_config_NAPI_VERSION !== undefined) &&
testModules.splice(testModules.indexOf('threadsafe_function/threadsafe_function'), 1);
}

if ((process.env.npm_config_NAPI_VERSION !== undefined) &&
(process.env.npm_config_NAPI_VERSION < 5)) {
testModules.splice(testModules.indexOf('date'), 1);
}

if (typeof global.gc === 'function') {
console.log('Starting test suite\n');

Expand Down

0 comments on commit 19f41af

Please sign in to comment.