napi_h/bindgen_runtime/js_values/
date.rs1use std::{ptr, str::FromStr};
2
3use chrono::{DateTime, NaiveDateTime, Utc};
4
5use crate::{bindgen_prelude::*, check_status, sys, ValueType};
6
7impl TypeName for DateTime<Utc> {
8 fn type_name() -> &'static str {
9 "DateTime"
10 }
11
12 fn value_type() -> ValueType {
13 ValueType::Object
14 }
15}
16
17impl ValidateNapiValue for DateTime<Utc> {
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.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 "toISOString\0".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!(
113 "Failed to convert napi value into rust type `NaiveDateTime` {} {}",
114 err, iso_string
115 ),
116 )
117 })?;
118
119 Ok(naive)
120 }
121}
122
123impl ToNapiValue for DateTime<Utc> {
124 unsafe fn to_napi_value(env: sys::napi_env, val: DateTime<Utc>) -> Result<sys::napi_value> {
125 let mut ptr = std::ptr::null_mut();
126 let millis_since_epoch_utc = val.timestamp_millis() as f64;
127
128 check_status!(
129 unsafe { sys::napi_create_date(env, millis_since_epoch_utc, &mut ptr) },
130 "Failed to convert rust type `DateTime<Utc>` into napi value",
131 )?;
132
133 Ok(ptr)
134 }
135}
136
137impl FromNapiValue for DateTime<Utc> {
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<Utc>`",
144 )?;
145
146 let milliseconds_since_epoch_utc = milliseconds_since_epoch_utc as i64;
147 let timestamp_seconds = milliseconds_since_epoch_utc / 1_000;
148 let naive = NaiveDateTime::from_timestamp_opt(
149 timestamp_seconds,
150 (milliseconds_since_epoch_utc % 1_000 * 1_000_000) as u32,
151 )
152 .ok_or_else(|| Error::new(Status::DateExpected, "Found invalid date".to_owned()))?;
153 Ok(DateTime::<Utc>::from_naive_utc_and_offset(naive, Utc))
154 }
155}