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

How to use `serde::format_description` with `format_description::well_known` ? #676

Open loganmzz opened 2 months ago

loganmzz commented 2 months ago

I wanna map "non-offset" strings against OffsetDatetime.

I tried (sorry not provided Rust Playground links, but seems it lacks some features):

use time;
time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);

But I get following errors:

error: expected one of `::`, `;`, or `as`, found `.`
 --> konfetti-sessionize/src/lib.rs:2:111
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  |                                                                                                               ^ expected one of `::`, `;`, or `as`

error: macro expansion ignores token `}` and any following
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ caused by the macro expansion here
  |
  = note: the usage of `time::serde::format_description!` is likely invalid in item context

error[E0433]: failed to resolve: there are too many leading `super` keywords
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ there are too many leading `super` keywords
  |
  = note: this error originates in the macro `time::serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0432]: unresolved import `super`
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no `description` in the root
  |
  = note: this error originates in the macro `time::serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0433]: failed to resolve: use of undeclared crate or module `__path_hack`
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared crate or module `__path_hack`
  |
  = note: this error originates in the macro `time::serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0412]: cannot find type `__TimeSerdeType` in this scope
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
  |
  = note: this error originates in the macro `time::serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0425]: cannot find function `description` in this scope
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
  |
note: function `crate::serde_datetime::description` exists but is inaccessible
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not accessible
  = note: this error originates in the macro `time::serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0433]: failed to resolve: use of undeclared crate or module `__TimeSerdeType`
 --> konfetti-sessionize/src/lib.rs:2:1
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601.DATE_TIME);
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ use of undeclared crate or module `__TimeSerdeType`
  |
  = note: this error originates in the macro `time::serde::format_description` (in Nightly builds, run with -Z macro-backtrace for more info)

Trying to replace Iso8601.DATE_TIME with Iso8601::DATE_TIME, blocks macro evaluation:

error[E0432]: unresolved import `time::format_description::well_known::Iso8601`
 --> konfetti-sessionize/src/lib.rs:2:104
  |
2 | time::serde::format_description!(serde_datetime, OffsetDateTime, time::format_description::well_known::Iso8601::DATE_TIME);
  |                                                                                                        ^^^^^^^ `Iso8601` is a struct, not a module
jhpratt commented 2 months ago

What feature flags do you have enabled?

loganmzz commented 2 months ago

I use: serde and serde-well-known

jhpratt commented 2 months ago

That can't be the case, as time::serde::format_description is enabled by the macros feature. Also note that the serde-well-known flag is deliberately undocumented, as it is deprecated in favor of using the documented flags directly (namely serde, formatting, and parsing).

Have you looked at the documentation for this macro? The final example shows how to use it with ISO 8601.

loganmzz commented 2 months ago

Ok, here is my test case.

[dependencies]
serde = { version = "1.0.198", features = ["derive"] }
time = { version = "0.3.36", features = ["formatting", "macros", "parsing", "serde"] }

[dev-dependencies]
serde_json = { version = "1.0.116" }
use time::{
    format_description::well_known::{iso8601, Iso8601},
    serde::format_description,
    OffsetDateTime,
};

const CONFIG: iso8601::EncodedConfig = iso8601::Config::DEFAULT
    .set_formatted_components(iso8601::FormattedComponents::DateTime)
    .encode();
const FORMAT: Iso8601<CONFIG> = Iso8601::<CONFIG>;
format_description!(serde_datetime, OffsetDateTime, FORMAT);

#[derive(serde::Deserialize, Debug, PartialEq)]
pub struct Container {
    #[serde(with="serde_datetime")]
    pub datetime: OffsetDateTime,
}
use time::{
    Date,
    Month,
    OffsetDateTime,
    Time,
};

#[test]
fn without_offset() {
    let json = serde_json::json!({
        "datetime": "2024-04-17T12:45:00.0"
    });

    let actual: Container = serde_json::from_value(json).unwrap();

    assert_eq!(
        actual,
        Container {
            datetime: OffsetDateTime::new_utc(
                Date::from_calendar_date(2024, Month::April, 17).unwrap(),
                Time::from_hms(12, 45, 0).unwrap(),
            ),
        },
    );
}

Then, I got:

---- tests::without_offset stdout ----
thread 'tests::without_offset' panicked at 'called `Result::unwrap()` on an `Err` value: Error("the `Parsed` struct did not include enough information to construct the type", line: 0, column: 0)', src/lib.rs:36:62
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Worth to mention that error isn't very explicit :/

jhpratt commented 2 months ago

The failure is as expected, as there is no UtcOffset present in the formatted string. As such, an OffsetDateTime cannot be constructed.

I will look into what can be done in terms of an error message, but I suspect there isn't much.