napi/bindgen_runtime/js_values/
date.rs1use std::{ptr, str::FromStr};
2
3use chrono::{DateTime, Local, LocalResult, NaiveDateTime, TimeZone};
4
5use crate::{bindgen_prelude::*, check_status, sys, ValueType};
6
7impl<Tz: TimeZone> TypeName for DateTime<Tz> {
8 fn type_name() -> &'static str {
9 "DateTime"
10 }
11
12 fn value_type() -> ValueType {
13 ValueType::Object
14 }
15}
16
17impl<Tz: TimeZone> ValidateNapiValue for DateTime<Tz> {
18 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
19 let mut is_date = false;
20 check_status!(unsafe { sys::napi_is_date(env, napi_val, &mut is_date) })?;
21 if !is_date {
22 return Err(Error::new(
23 Status::InvalidArg,
24 "Expected a Date object".to_owned(),
25 ));
26 }
27
28 Ok(ptr::null_mut())
29 }
30}
31
32impl ToNapiValue for NaiveDateTime {
33 unsafe fn to_napi_value(env: sys::napi_env, val: NaiveDateTime) -> Result<sys::napi_value> {
34 let mut ptr = std::ptr::null_mut();
35 let millis_since_epoch_utc = val.and_utc().timestamp_millis() as f64;
36
37 check_status!(
38 unsafe { sys::napi_create_date(env, millis_since_epoch_utc, &mut ptr) },
39 "Failed to convert rust type `NaiveDateTime` into napi value",
40 )?;
41
42 Ok(ptr)
43 }
44}
45
46impl FromNapiValue for NaiveDateTime {
47 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
48 let mut to_iso_string = ptr::null_mut();
49 check_status!(
50 unsafe {
51 napi_sys::napi_create_string_utf8(
52 env,
53 c"toISOString".as_ptr().cast(),
54 11,
55 &mut to_iso_string,
56 )
57 },
58 "create toISOString JavaScript string failed"
59 )?;
60 let mut to_iso_string_method = ptr::null_mut();
61 check_status!(
62 unsafe { sys::napi_get_property(env, napi_val, to_iso_string, &mut to_iso_string_method) },
63 "get toISOString method failed"
64 )?;
65 let mut iso_string_value = ptr::null_mut();
66 check_status!(
67 unsafe {
68 sys::napi_call_function(
69 env,
70 napi_val,
71 to_iso_string_method,
72 0,
73 ptr::null(),
74 &mut iso_string_value,
75 )
76 },
77 "Call toISOString on Date Object failed"
78 )?;
79
80 let mut iso_string_length = 0;
81 check_status!(
82 unsafe {
83 sys::napi_get_value_string_utf8(
84 env,
85 iso_string_value,
86 ptr::null_mut(),
87 0,
88 &mut iso_string_length,
89 )
90 },
91 "Get ISOString length failed"
92 )?;
93 let mut iso_string = String::with_capacity(iso_string_length + 1);
94 check_status!(
95 unsafe {
96 sys::napi_get_value_string_utf8(
97 env,
98 iso_string_value,
99 iso_string.as_mut_ptr().cast(),
100 iso_string_length,
101 &mut iso_string_length,
102 )
103 },
104 "Get ISOString length failed"
105 )?;
106
107 unsafe { iso_string.as_mut_vec().set_len(iso_string_length) };
108
109 let naive = NaiveDateTime::from_str(iso_string.as_str()).map_err(|err| {
110 Error::new(
111 Status::InvalidArg,
112 format!("Failed to convert napi value into rust type `NaiveDateTime` {err} {iso_string}"),
113 )
114 })?;
115
116 Ok(naive)
117 }
118}
119
120impl<Tz: TimeZone> ToNapiValue for DateTime<Tz> {
121 unsafe fn to_napi_value(env: sys::napi_env, val: DateTime<Tz>) -> Result<sys::napi_value> {
122 let mut ptr = std::ptr::null_mut();
123 let millis_since_epoch_utc = val.timestamp_millis() as f64;
124
125 check_status!(
126 unsafe { sys::napi_create_date(env, millis_since_epoch_utc, &mut ptr) },
127 "Failed to convert rust type `DateTime` into napi value",
128 )?;
129
130 Ok(ptr)
131 }
132}
133
134impl<Tz: TimeZone> FromNapiValue for DateTime<Tz>
135where
136 DateTime<Tz>: From<DateTime<Local>>,
137{
138 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
139 let mut milliseconds_since_epoch_utc = 0.0;
140
141 check_status!(
142 unsafe { sys::napi_get_date_value(env, napi_val, &mut milliseconds_since_epoch_utc) },
143 "Failed to convert napi value into rust type `DateTime`",
144 )?;
145
146 match Local.timestamp_millis_opt(milliseconds_since_epoch_utc as i64) {
147 LocalResult::Single(dt) => Ok(dt.into()),
148 _ => Err(Error::new(
149 Status::DateExpected,
150 "Found invalid date".to_owned(),
151 )),
152 }
153 }
154}