chronotope / chrono

Date and time library for Rust
Other
3.28k stars 515 forks source link

DelayedFormat: Panic in rendering #1588

Open behnam-oneschema opened 3 months ago

behnam-oneschema commented 3 months ago

This code:

use chrono::NaiveDateTime;

fn main() {
    let naive_date_time =
        NaiveDateTime::parse_from_str("2024-06-07T00:00:00+09:00", "%Y-%m-%dT%H:%M:%S%:z").unwrap();
    dbg!(&naive_date_time);

    let format = "%FT%T%:z";
    let delayed_format = naive_date_time.format(format);
    dbg!(&delayed_format);

    println!("{}", delayed_format);
}

Results in these debug outputs:

[src/main.rs:6:5] &naive_date_time = 2024-06-07T00:00:00
[src/main.rs:10:5] &delayed_format = DelayedFormat {
    date: Some(
        2024-06-07,
    ),
    time: Some(
        00:00:00,
    ),
    off: None,
    items: StrftimeItems {
        remainder: "%FT%T%:z",
        queue: [],
    },
    locale: Locale,
}

which seem to be all valid.

Then panics when trying to render the formatting to string:

thread 'main' panicked at library/std/src/io/stdio.rs:1088:9:
failed printing to stdout: formatter error
stack backtrace:
   0:        0x100245030 - std::backtrace_rs::backtrace::libunwind::trace::h6de1cbf3f672a4f8
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/../../backtrace/src/backtrace/libunwind.rs:105:5
   1:        0x100245030 - std::backtrace_rs::backtrace::trace_unsynchronized::hd0de2d5ef13b6f4d
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2:        0x100245030 - std::sys_common::backtrace::_print_fmt::h2a33510d9b3bb866
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/sys_common/backtrace.rs:68:5
   3:        0x100245030 - <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt::h01b2beffade888b2
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/sys_common/backtrace.rs:44:22
   4:        0x10025a610 - core::fmt::rt::Argument::fmt::h5ddc0f22b2928899
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/fmt/rt.rs:142:9
   5:        0x10025a610 - core::fmt::write::hbadb443a71b75f23
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/fmt/mod.rs:1153:17
   6:        0x100243338 - std::io::Write::write_fmt::hc09d7755e3ead5f0
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/mod.rs:1843:15
   7:        0x100244e88 - std::sys_common::backtrace::_print::h3cd1786cbb1caf0f
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/sys_common/backtrace.rs:47:5
   8:        0x100244e88 - std::sys_common::backtrace::print::h28349e5c25acbac7
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/sys_common/backtrace.rs:34:9
   9:        0x100246248 - std::panicking::default_hook::{{closure}}::hd24b6196784d991e
  10:        0x100245f2c - std::panicking::default_hook::hfcec80a2720c8c73
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:292:9
  11:        0x100246b3c - std::panicking::rust_panic_with_hook::h84760468187ddc85
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:779:13
  12:        0x100246528 - std::panicking::begin_panic_handler::{{closure}}::he666a5eb600a7203
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:657:13
  13:        0x1002454b4 - std::sys_common::backtrace::__rust_end_short_backtrace::h592f44d2bf9f843f
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/sys_common/backtrace.rs:171:18
  14:        0x1002462a0 - rust_begin_unwind
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:645:5
  15:        0x10026076c - core::panicking::panic_fmt::h98bbf7bdf4994454
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/panicking.rs:72:14
  16:        0x100242bc8 - std::io::stdio::print_to::h4b6256ffd4fd0562
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/stdio.rs:1088:9
  17:        0x100242bc8 - std::io::stdio::_print::hd9ffb3f73dfcc2b3
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/io/stdio.rs:1164:5
  18:        0x100208f14 - chrono_panic::main::h9483e9876fb5629c
                               at /Users/behnam/code/misc/chrono-panic/src/main.rs:12:5
  19:        0x10020a208 - core::ops::function::FnOnce::call_once::h5ae5a043b13877fa
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/ops/function.rs:250:5
  20:        0x10020a3ec - std::sys_common::backtrace::__rust_begin_short_backtrace::he612149a7c555640
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/sys_common/backtrace.rs:155:18
  21:        0x10020860c - std::rt::lang_start::{{closure}}::h2a0bca82aa73c2fc
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/rt.rs:166:18
  22:        0x100241084 - core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once::heaba8a29e0324069
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/core/src/ops/function.rs:284:13
  23:        0x100241084 - std::panicking::try::do_call::h6e5fac4f4884d97b
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:552:40
  24:        0x100241084 - std::panicking::try::h2b98e2f3cf76cd78
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:516:19
  25:        0x100241084 - std::panic::catch_unwind::hba9c97319335c08b
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panic.rs:146:14
  26:        0x100241084 - std::rt::lang_start_internal::{{closure}}::h18efdcfb68f002e8
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/rt.rs:148:48
  27:        0x100241084 - std::panicking::try::do_call::ha793e16770aada4d
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:552:40
  28:        0x100241084 - std::panicking::try::h8aa812e3e1310d12
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panicking.rs:516:19
  29:        0x100241084 - std::panic::catch_unwind::h38c4879f2623185e
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/panic.rs:146:14
  30:        0x100241084 - std::rt::lang_start_internal::h39923ab4c3913741
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/rt.rs:148:20
  31:        0x1002085d8 - std::rt::lang_start::h386185eb75fa91dd
                               at /rustc/9b00956e56009bab2aa15d7bff10916599e3d6d6/library/std/src/rt.rs:165:17
  32:        0x100208f6c - _main

I can repro this on both default features, as well as { version = "0.4.38", default-features = false, features = ["std"] }.

djc commented 3 months ago

You have a time zone specifier (%z) combined with a type (NaiveDateTime) that does not support time zones -- I think this is the problem. Unfortunately the format() method was not defined as fallible, so we don't have a good way of yielding an error -- although maybe we should deprecate format() in favor of try_format() in 0.4?

We have been working on making this better on the 0.5 branch, including hopefully making this sort of thing fail to compile.

behnam-oneschema commented 3 months ago

I see. My assumption was that if a formatting option is not supported, either DelayedFormat won't be instantiated, or the formatting option would be ignored (becoming a literal string).

Yeah, I would love to see a fallible API for this! Thanks!

Now that you mentioned the behavior, I understand the intention of the last paragraph of the doc: https://docs.rs/chrono/latest/chrono/naive/struct.NaiveDateTime.html#method.format . I think it might be useful to make these docs more explicit about the "fails" being a thread panic, either by updating the wording of the sentence, or maybe even adding a "Panics" section to the doc similar to the rust-lang docs (example)

Anyways, leaving it for you to decide if any it's useful to keep this issue open. Thanks again for the prompt response!

djc commented 3 months ago

I think it might be useful to make these docs more explicit about the "fails" being a thread panic, either by updating the wording of the sentence, or maybe even adding a "Panics" section to the doc similar to the rust-lang docs (example)

Would you be able to make a PR with a proposal? Would be much appreciated!

behnam-oneschema commented 3 months ago

Okay, submitted https://github.com/chronotope/chrono/pull/1590

lukas-loering commented 1 month ago

Unfortunately the format() method was not defined as fallible, so we don't have a good way of yielding an error -- although maybe we should deprecate format() in favor of try_format() in 0.4?

It would be amazing if a failable try_format API were made available.

Especially when chrono is used in other libraries (like polars in our case) it is quite annoying to get an unexpected panic in third party code. While this was a configuration error on our part, it was not easy to figure out what went wrong, as Rust does not provide an appropriate panic message either.