Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace chrono with time #1307

Merged
merged 15 commits into from
Mar 21, 2022

Conversation

uklotzde
Copy link
Contributor

@uklotzde uklotzde commented Mar 9, 2022

Fixes #1304.

BREAKING API CHANGE: The type DateTime is no longer (re-)exported. Instead you need to use time::OffsetDateTime explicitly.

Remarks:

  • Please check the error handling and mappings. time returns results instead of panicking like chrono does. For the FastValue impl I had to use `.expect("valid UNIX timestamp").
  • I had to adjust some debug strings in tests that are used for matching test results. Copy&paste from the failed test outputs. Not very handy, please verify.

TODO:

  • Add changelog entry

src/error.rs Outdated Show resolved Hide resolved
src/error.rs Outdated Show resolved Hide resolved
src/error.rs Outdated Show resolved Hide resolved
src/lib.rs Show resolved Hide resolved
Copy link
Collaborator

@fulmicoton fulmicoton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome! Thank you!

Can you re-add the re-export or make the case against it on the ticket? I commented there?
Also can you add your contribution on CHANGELOG.md. Don't forget to put your github username.
Make sure to highlight the breaking changes:
chrono -> time
timestamp -> unix_timestamp <---- I'm not sure that one is useful tbh.

@codecov-commenter
Copy link

codecov-commenter commented Mar 10, 2022

Codecov Report

Merging #1307 (ef80c27) into main (46d5de9) will decrease coverage by 0.02%.
The diff coverage is 82.24%.

@@            Coverage Diff             @@
##             main    #1307      +/-   ##
==========================================
- Coverage   94.25%   94.22%   -0.03%     
==========================================
  Files         232      232              
  Lines       40801    40856      +55     
==========================================
+ Hits        38457    38498      +41     
- Misses       2344     2358      +14     
Impacted Files Coverage Δ
query-grammar/src/query_grammar.rs 99.64% <ø> (ø)
src/error.rs 22.03% <0.00%> (-2.50%) ⬇️
src/fastfield/multivalued/mod.rs 96.96% <ø> (ø)
src/fastfield/readers.rs 86.66% <ø> (ø)
src/query/more_like_this/more_like_this.rs 67.54% <0.00%> (ø)
src/schema/document.rs 95.48% <ø> (ø)
src/schema/term.rs 84.45% <50.00%> (ø)
src/lib.rs 97.61% <75.75%> (-1.21%) ⬇️
src/collector/histogram_collector.rs 98.99% <83.33%> (-0.51%) ⬇️
src/schema/field_type.rs 84.04% <84.00%> (+0.70%) ⬆️
... and 13 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 46d5de9...ef80c27. Read the comment docs.

@uklotzde uklotzde force-pushed the replace-chrono-with-time branch from c8718ce to 431a901 Compare March 10, 2022 10:23
@uklotzde
Copy link
Contributor Author

I decided against introducing a type alias DateTime for time::OffsetDateTime. The code is more concise and less confusing when explicitly using the actual types from crate::time. Re-exporting the crate as a module should be sufficient.

@uklotzde
Copy link
Contributor Author

@fulmicoton I am still unsure if it would be better to use PrimitiveDateTime instead of OffsetDateTime in the public API? Since the time zone information gets lost when storing an OffsetDateTime I consider PrimitiveDateTime more appropriate. The time zone UTC is implicit and only matters for the internal integer conversions.

@uklotzde
Copy link
Contributor Author

I am convinced that storing PrimitiveDateTime instead of OffsetDateTime is the right choice and prevents inconsistent behavior.

For convenience impl From<OffsetDateTime> for Value is provided that performs the conversion to UTC. In the opposite direction you have to invoke PrimitiveDateTime::assume_utc() explicitly to get back an OffsetDateTime.

Please verify: 304013f

@fulmicoton
Copy link
Collaborator

I am convinced that storing PrimitiveDateTime instead of OffsetDateTime is the right choice and prevents inconsistent behavior.

Haha, I noticed that yesterday before going to sleep
I'm glad you already made the change.

CHANGELOG.md Outdated Show resolved Hide resolved
@uklotzde uklotzde marked this pull request as draft March 13, 2022 12:17
@uklotzde uklotzde changed the title Replace chrono with time [WiP] Replace chrono with time Mar 13, 2022
@uklotzde
Copy link
Contributor Author

Converted to draft because there are still some API inconsistencies that need to be resolved. Moreover all time zone conversions should be explicit, not implicit.

@fulmicoton fulmicoton marked this pull request as ready for review March 14, 2022 04:55
@fulmicoton fulmicoton marked this pull request as draft March 14, 2022 04:56
@fulmicoton
Copy link
Collaborator

@uklotzde Understood! Please let me know when I should resume the review.

@uklotzde
Copy link
Contributor Author

uklotzde commented Mar 14, 2022

@fulmicoton Done. Please see the commit messages for a summary of the changes.

I would also like to drop the convenient but lossy impl From<OffsetDateTime> for Value and replace it with an explicit conversion function Value::date_utc() that resembles the newly added Document::add_date_utc(). But unfortunately that would break the doc! macro for OffsetDateTime (e.g. used by many tests) and I don't know how to fix that easily.

@uklotzde uklotzde marked this pull request as ready for review March 14, 2022 09:15
@uklotzde
Copy link
Contributor Author

A simple extension of the time API would serve us well: time-rs/time#454

@uklotzde
Copy link
Contributor Author

More and more I come to the conclusion that using a dedicated newtype with conversion functions would be the correct approach. Using PrimitiveDateTime/OffsetDateTime is unsound because storing those values is lossy by implicitly reducing the precision to seconds.

@uklotzde uklotzde marked this pull request as draft March 14, 2022 21:56
@uklotzde uklotzde changed the title Replace chrono with time [WiP] Replace chrono with time Mar 14, 2022
@uklotzde
Copy link
Contributor Author

Phew, that escalated quickly.

Fortunately, introducing the newtype revealed how scattered the conversion logic was. All conversions are now implemented by dedicated functions of DateTime.

@uklotzde uklotzde changed the title [WiP] Replace chrono with time Replace chrono with time Mar 15, 2022
@uklotzde uklotzde marked this pull request as ready for review March 15, 2022 10:32
@uklotzde
Copy link
Contributor Author

Ready again. Hopefully I didn't mess anything up. Especially the FastValue conversions to_u64() and as_64() are easy to confuse. A less generic and more distinctive naming would help.

/// functions and not by implementing any `From`/`Into` traits
/// to prevent unintended usage.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct DateTime {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a nicer implem of Debug showing Rfc3339?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the timestamp 2019-10-12T05:20:50.52Z or like DateTime { 2019-10-12T05:20:50.52Z }?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just the date is ok I think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

d6b46a3

The documentation of the DateTime wrapper now mentions the internal UTC representation, because that leaks not only for debugging but also when serializing as a JSON value.

I have noticed that the query parser is not tested with explicit time zone offsets, only with UTC? But that's unrelated and a different task.

@fulmicoton
Copy link
Collaborator

I agree with your change (introducing a DateTime object)... Chrono was nice for this.

@uklotzde
Copy link
Contributor Author

I agree with your change (introducing a DateTime object)... Chrono was nice for this.

Nevertheless using the chrono type directly was unsound because of the precision loss when storing those values.

@fulmicoton
Copy link
Collaborator

Thank you @uklotzde for the very solid work.

@fulmicoton fulmicoton merged commit 125707d into quickwit-oss:main Mar 21, 2022
@uklotzde
Copy link
Contributor Author

@fulmicoton Please double check once again that I didn't miss anything. Especially, if the explicit truncation to seconds inside the newtype is viable and doesn't break existing use cases. Formerly this truncation code was scattered at various places. I am still not completely familiar with when and how values are transformed and stored.

@fulmicoton
Copy link
Collaborator

It should be ok @uklotzde

PSeitz pushed a commit that referenced this pull request May 3, 2022
For date values `chrono` has been replaced with `time` 
- The `time` crate is re-exported as `tantivy::time` instead of `tantivy::chrono`.
- The type alias `tantivy::DateTime` has been removed.
- `Value::Date` wraps `time::PrimitiveDateTime` without time zone information.
- Internally date/time values are stored as seconds since UNIX epoch in UTC.
- Converting a `time::OffsetDateTime` to `Value::Date` implicitly converts the value into UTC.
If this is not desired do the time zone conversion yourself and use `time::PrimitiveDateTime`
directly instead.

Closes #1304
This was referenced Jan 13, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Replace chrono with time
3 participants