chronotope/chrono

DateTime.with_timezone() seems not working with chrono::offset::Local in wasm32

Closed this issue · 7 comments

Here is a simple test for native x86:

fn main() {
    let dt = chrono::DateTime::parse_from_rfc3339("2020-04-07T14:07:52+00:00").unwrap();

    println!("dt: {}", dt);
    println!("dt: {}", dt.with_timezone(&chrono::Local));
}

When I run it in my local timezone (UTC+2) it correctly prints:

dt: 2020-04-07 14:07:52 +00:00
dt: 2020-04-07 16:07:52 +02:00

But in a wasm project, this code:

        log!(d);
        log!(chrono::Local::now());
        log!(d.with_timezone(&chrono::FixedOffset::east(3600)));
        log!(d.with_timezone(&chrono::Local));

prints in Firefox:

2020-04-07T14:07:15+00:00
2020-04-10T15:36:23.396+02:00
2020-04-07T15:07:15+01:00
2020-04-07T14:07:15+00:00

You can see that with FixedOffset I get correct date, but not with Local.

Is this in a web browser or some other runtime? What runtime in particular is it?

@ip1981 let me know if my attached branch fixes the problem for you. I'm not terribly familiar with the wasm ecosystem so I need to expend some work to get a meaningful test for it, but it seems like it might work.

Is this in a web browser or some other runtime? What runtime in particular is it?

That's in Firefox.

@ip1981 let me know if my attached branch fixes the problem for you. I'm not terribly familiar with the wasm ecosystem so I need to expend some work to get a meaningful test for it, but it seems like it might work.

Yes, it works. I tested the PR with a small change (see my comment over there). And I used similar code as a workaround.

This works for creating a Local datetime from a Utc one, but not the other way around.

This:

Local.ymd(2020, 7, 26).and_hms(21, 22, 54);

// or alternately
let naive_date_time = NaiveDateTime::with_ymd(2020, 7, 26).and_hms(21, 22, 54);
Local.from_local_datetime(&naive_date_time).earliest();

still gives "+00:00" offset.

So the use-case of displaying a UTC time in local timezone (e.g. receiving a universal datetime from a server and rendering in browser) is supported, but taking a local datetime and converting to UTC (e.g. reading from a form input and sending to server) is still busted.

This seems to be a currently viable workaround:

// `offset` seems equivalent to how `Local` *should* behave
let offset = Local::now().offset().to_owned();

offset.ymd(2020, 7, 26).and_hms(21, 22, 54);

// or alternately
let naive_date_time = NaiveDateTime::with_ymd(2020, 7, 26).and_hms(21, 22, 54);
offset.from_local_datetime(&naive_date_time).earliest();

but the extra step of constantly using now is not ideal.

@EndilWayfare I just ran into this as well but was able to solve it by enabling chrono's wasmbind feature:

[target.'cfg(not(target_arch = "wasm32"))'.dependencies.chrono]
version = "0.4.19"

[target.'cfg(target_arch = "wasm32")'.dependencies.chrono]
version = "0.4.19"
features = ["wasmbind"]

See here for why this is required: https://docs.rs/chrono/0.4.19/src/chrono/offset/local.rs.html#150-169

If you're not using emscripten then I believe that wasmbind and the wasm-bindgen ecosystem is the best bet.