rhaiscript / rhai

Rhai - An embedded scripting language for Rust.
https://crates.io/crates/rhai
Apache License 2.0
3.8k stars 177 forks source link

serialize/de-serialize doesn't appear to work for timestamp #560

Closed garypen closed 2 years ago

garypen commented 2 years ago

This is rhai:1.6.1

I'm trying to serialize/de-serialize dynamic values and this works fine for strings and i64 (which I've tested). However, when I serialize a timestamp and try to de-serialize it, the value is de-serialized as a string.

Hard to put together a good example, but this illustratess what I'm doing:

                eprintln!("ABOUT TO INSERT, v: {:?}", value.type_name());
                x.insert(key, value)
                    .map(|v: Option<Dynamic>| v.unwrap_or_else(|| Dynamic::from(())))
                    .map_err(|e: BoxError| e.to_string())?;
                let raw: Dynamic = x
                    .get(key)
                    .map(|v: Option<Dynamic>| v.unwrap_or_else(|| Dynamic::from(())))
                    .map_err(|e: BoxError| e.to_string())?;
                eprintln!("JUST RETRIEVED, v: {:?}", raw.type_name());

Here's the output when I run something which exercises this code from rhai to insert as follows:

(INSERTING SOME STUFF)
    request.context["a"] = 42;
    request.context["b"] = "a string";
    request.context["c"] = timestamp();

(RETRIEVING SOME STUFF)
    let elapsed = response.context["a"];
    let elapsed = response.context["b"];
    let elapsed = response.context["c"];
ABOUT TO INSERT, v: "i64"
ABOUT TO INSERT, v: "string"
ABOUT TO INSERT, v: "timestamp"
JUST RETRIEVED, v: "i64"
JUST RETRIEVED, v: "string"
JUST RETRIEVED, v: "string" <= SHOULD BE timestamp
schungx commented 2 years ago

Yes, this is expected behavior. There is no standard text representation of a timestamp, so I believe it just serializes to "std::time::Instant", which will round-trip as a string.

As a timestamp is host-dependent, it is not possible to find a independent representation that would allow it to be serialized and deserialized on another host.

Timestamps are intended for "relative" operations (e.g. getting how many seconds elapsed). They are not intended for absolute date/time usage (use an ISO-formatted date/time string for that).

What you can do, however, is to keep a "time difference" as the number of seconds after a certain date. If you keep that date/time (which can be serialized), and the time difference, you essentially get the functionality of a timestamp, but you still cannot construct that timestamp back.

garypen commented 2 years ago

It's a shame that it has the confusing round-trip behaviour. It would be better if it failed, I think, but I can imagine that would be difficult to integrate with the string representation capabilities of rhai timestamps.

I'm trying to capture relative timings between multiple script invocations and so I have to externalise a timestamp. I'm interested in your alternative solution. I think you are suggesting that I could have a "start of time" Instant and then compare my timestamp().elapsed against that time and then use the differences of the two. Something like:

let start_of_time = timestamp();

let start_of_test = start_of_time.elapsed;
<blah...>
let end_of_test  = start_of_time.elapsed - start_of_test

That should probably work for me. Thank you.

schungx commented 2 years ago

Or you can simply put in a real date-time type like in chrono... They should serialize/deserialize fine...