diff --git a/src/binding.cc b/src/binding.cc index f06f4f86..31f41872 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -852,6 +852,23 @@ const v8::Array* v8__Array__New_with_elements(v8::Isolate* isolate, uint32_t v8__Array__Length(const v8::Array& self) { return self.Length(); } +const v8::Date* v8__Date__New(const v8::Context& context, double time) { + // v8::Date::New() is kind of weird in that it returns a v8::Value, + // not a v8::Date, even though the object is always a Date object. + // Let's paper over that quirk here. + v8::MaybeLocal maybe_date; + + v8::Local value; + if (v8::Date::New(ptr_to_local(&context), time).ToLocal(&value)) { + assert(value->IsDate()); + maybe_date = value.As(); + } + + return maybe_local_to_ptr(maybe_date); +} + +double v8__Date__ValueOf(const v8::Date& self) { return self.ValueOf(); } + const v8::External* v8__External__New(v8::Isolate* isolate, void* value) { return local_to_ptr(v8::External::New(isolate, value)); } diff --git a/src/date.rs b/src/date.rs new file mode 100644 index 00000000..d76a15d0 --- /dev/null +++ b/src/date.rs @@ -0,0 +1,29 @@ +// Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. + +use crate::Context; +use crate::Date; +use crate::HandleScope; +use crate::Local; + +extern "C" { + fn v8__Date__New(context: *const Context, value: f64) -> *const Date; + fn v8__Date__ValueOf(this: *const Date) -> f64; +} + +/// An instance of the built-in Date constructor (ECMA-262, 15.9). +impl Date { + pub fn new<'s>( + scope: &mut HandleScope<'s>, + value: f64, + ) -> Option> { + unsafe { + scope.cast_local(|sd| v8__Date__New(sd.get_current_context(), value)) + } + } + + /// A specialization of Value::NumberValue that is more efficient + /// because we know the structure of this object. + pub fn value_of(&self) -> f64 { + unsafe { v8__Date__ValueOf(self) } + } +} diff --git a/src/lib.rs b/src/lib.rs index 14fe4774..7a92b3cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ mod array_buffer; mod array_buffer_view; mod context; mod data; +mod date; mod exception; mod external; mod external_references; diff --git a/tests/test_api.rs b/tests/test_api.rs index 8f54a895..d7c9c938 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -3485,3 +3485,33 @@ fn synthetic_module() { check("a", 1.0); check("b", 2.0); } + +#[allow(clippy::float_cmp)] +#[test] +fn date() { + let time = 1_291_404_900_000.; // 2010-12-03 20:35:00 - Mees <3 + + let _setup_guard = setup(); + let isolate = &mut v8::Isolate::new(Default::default()); + + let scope = &mut v8::HandleScope::new(isolate); + + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let date = v8::Date::new(scope, time).unwrap(); + assert_eq!(date.value_of(), time); + + let key = v8::String::new(scope, "d").unwrap(); + context.global(scope).set(scope, key.into(), date.into()); + + let result = eval(scope, "d.toISOString()").unwrap(); + let result = result.to_string(scope).unwrap(); + let result = result.to_rust_string_lossy(scope); + assert_eq!(result, "2010-12-03T19:35:00.000Z"); + + // V8 chops off fractions. + let date = v8::Date::new(scope, std::f64::consts::PI).unwrap(); + assert_eq!(date.value_of(), 3.0); + assert_eq!(date.number_value(scope).unwrap(), 3.0); +}