time-rs / time

The most used Rust library for date and time handling.
https://time-rs.github.io
Apache License 2.0
1.06k stars 261 forks source link

Sub-millisecond component inaccuracy in OffsetDateTime conversion from js_sys::Date #635

Open trrk opened 8 months ago

trrk commented 8 months ago

When generating an OffsetDateTime from a js_sys::Date, there are cases where the sub-millisecond components are not set to zero. This behavior is unexpected and can lead to inaccuracies in the resulting OffsetDateTime.

Steps to Reproduce

  1. Use the following code to reproduce the issue:
    
    let millis = 1699083911579i64; // 2023-11-04T07:45:11.579Z
    let js_date = js_sys::Date::new(&JsValue::from_f64(millis as f64));
    let datetime = OffsetDateTime::from(js_date);

println!("{}", datetime); // => 2023-11-04 7:45:11.579000064 +00:00:00



## Reason for Considering It a Bug

The precision of `js_sys::Date` is limited to milliseconds. Therefore, when converting it to an `OffsetDateTime`, we expect the sub-millisecond components to be set to zero for consistency and accuracy.

## Cause
https://github.com/time-rs/time/blob/72f03e05073621f713dead88f16c227187afd6f9/time/src/date_time.rs#L1226-L1233
The issue stems from the conversion process of milliseconds to nanoseconds. It appears that the code converts milliseconds to nanoseconds using `f64`, and subsequently converts it to `i128`, which can introduce inaccuracies and prevent sub-millisecond components from being zeroed out.

## Proposed Solution

To address this issue, consider converting milliseconds to i128 first and then perform the conversion to nanoseconds. This approach should maintain accuracy and ensure that sub-millisecond components are set to zero.

## Additional Information

I encountered this issue while using `OffsetDateTime::now_utc()` in a WASM environment.
jhpratt commented 8 months ago

Without even looking into this, I am confident that the multiplication magnifies the inherent error of representing decimal values in floating point numbers. I'm happy to accept your proposed solution as a PR, as I'm sure it'll fix the issue.