quickjs_runtime/quickjs_utils/
dates.rs

1//! Utils for working with Date objects
2
3use crate::jsutils::JsError;
4use crate::quickjs_utils;
5#[cfg(feature = "bellard")]
6use crate::quickjs_utils::class_ids::JS_CLASS_DATE;
7use crate::quickjs_utils::{functions, primitives};
8use crate::quickjsrealmadapter::QuickJsRealmAdapter;
9use crate::quickjsvalueadapter::QuickJsValueAdapter;
10use libquickjs_sys as q;
11#[cfg(feature = "bellard")]
12use libquickjs_sys::JS_GetClassID;
13#[cfg(feature = "quickjs-ng")]
14use libquickjs_sys::JS_IsDate;
15
16/// create a new instance of a Date object
17pub fn new_date_q(context: &QuickJsRealmAdapter) -> Result<QuickJsValueAdapter, JsError> {
18    unsafe { new_date(context.context) }
19}
20
21/// create a new instance of a Date object
22/// # Safety
23/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
24pub unsafe fn new_date(context: *mut q::JSContext) -> Result<QuickJsValueAdapter, JsError> {
25    let constructor = quickjs_utils::get_constructor(context, "Date")?;
26    let date_ref = functions::call_constructor(context, &constructor, &[])?;
27    Ok(date_ref)
28}
29
30/// check if a JSValueRef is an instance of Date
31pub fn is_date_q(context: &QuickJsRealmAdapter, obj_ref: &QuickJsValueAdapter) -> bool {
32    unsafe { is_date(context.context, obj_ref) }
33}
34
35/// check if a JSValueRef is an instance of Date
36/// # Safety
37/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
38#[allow(unused_variables)]
39pub unsafe fn is_date(ctx: *mut q::JSContext, obj: &QuickJsValueAdapter) -> bool {
40    #[cfg(feature = "bellard")]
41    {
42        JS_GetClassID(*obj.borrow_value()) == JS_CLASS_DATE
43    }
44    #[cfg(feature = "quickjs-ng")]
45    {
46        JS_IsDate(*obj.borrow_value())
47    }
48}
49
50/// set the timestamp for a Date object
51pub fn set_time_q(
52    context: &QuickJsRealmAdapter,
53    date_ref: &QuickJsValueAdapter,
54    timestamp: f64,
55) -> Result<(), JsError> {
56    unsafe { set_time(context.context, date_ref, timestamp) }
57}
58
59/// set the timestamp for a Date object
60/// # Safety
61/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
62pub unsafe fn set_time(
63    context: *mut q::JSContext,
64    date_ref: &QuickJsValueAdapter,
65    timestamp: f64,
66) -> Result<(), JsError> {
67    functions::invoke_member_function(
68        context,
69        date_ref,
70        "setTime",
71        &[primitives::from_f64(timestamp)],
72    )?;
73    Ok(())
74}
75/// get the timestamp from a Date object
76pub fn get_time_q(
77    context: &QuickJsRealmAdapter,
78    date_ref: &QuickJsValueAdapter,
79) -> Result<f64, JsError> {
80    unsafe { get_time(context.context, date_ref) }
81}
82/// get the timestamp from a Date object
83/// # Safety
84/// When passing a context pointer please make sure the corresponding QuickJsContext is still valid
85pub unsafe fn get_time(
86    context: *mut q::JSContext,
87    date_ref: &QuickJsValueAdapter,
88) -> Result<f64, JsError> {
89    let time_ref = functions::invoke_member_function(context, date_ref, "getTime", &[])?;
90    if time_ref.is_f64() {
91        primitives::to_f64(&time_ref)
92    } else if time_ref.is_i32() {
93        primitives::to_i32(&time_ref).map(|i| i as f64)
94    } else {
95        Err(JsError::new_string(format!(
96            "could not get time, val was a {}",
97            time_ref.get_js_type()
98        )))
99    }
100}
101
102#[cfg(test)]
103pub mod tests {
104    use crate::facades::tests::init_test_rt;
105    use crate::quickjs_utils::dates;
106    use crate::quickjs_utils::dates::{get_time_q, is_date_q, set_time_q};
107
108    #[test]
109    fn test_date() {
110        let rt = init_test_rt();
111        rt.exe_rt_task_in_event_loop(|q_js_rt| {
112            let q_ctx = q_js_rt.get_main_realm();
113            let date_ref = dates::new_date_q(q_ctx).expect("new_date failed");
114            assert!(is_date_q(q_ctx, &date_ref));
115
116            set_time_q(q_ctx, &date_ref, 1746776901898f64).expect("could not set time");
117            log::info!(
118                "date_str={}",
119                date_ref.to_string().expect("could not get date_ref string")
120            );
121            let gt_res = get_time_q(q_ctx, &date_ref);
122            match gt_res {
123                Ok(t) => {
124                    assert_eq!(t, 1746776901898f64);
125                }
126                Err(e) => {
127                    panic!("get time failed: {}", e);
128                }
129            }
130
131            set_time_q(q_ctx, &date_ref, 2f64).expect("could not set time");
132            let gt_res = get_time_q(q_ctx, &date_ref);
133            match gt_res {
134                Ok(t) => {
135                    assert_eq!(t, 2f64);
136                }
137                Err(e) => {
138                    panic!("get time 2 failed: {}", e);
139                }
140            }
141        });
142    }
143}