From 97c48e956a098881737820d0efed8a7e8a8389e7 Mon Sep 17 00:00:00 2001 From: James Robson Date: Fri, 9 Dec 2022 12:48:37 +0000 Subject: [PATCH] Make creating a SrtftimeItems return a Result --- src/date.rs | 9 +- src/datetime/mod.rs | 17 ++- src/datetime/tests.rs | 13 ++- src/format/mod.rs | 2 +- src/format/parse.rs | 2 +- src/format/strftime.rs | 216 ++++++++++++++++++++---------------- src/lib.rs | 10 +- src/naive/date.rs | 105 ++++++++++++------ src/naive/datetime/mod.rs | 20 ++-- src/naive/datetime/tests.rs | 14 +-- src/naive/isoweek.rs | 4 +- src/naive/time/mod.rs | 28 ++--- src/naive/time/tests.rs | 35 +++--- src/offset/mod.rs | 2 +- tests/dateutils.rs | 2 +- 15 files changed, 273 insertions(+), 206 deletions(-) diff --git a/src/date.rs b/src/date.rs index ea9a9f4bd0..3c63b3314b 100644 --- a/src/date.rs +++ b/src/date.rs @@ -21,6 +21,7 @@ use crate::naive::{IsoWeek, NaiveDate, NaiveTime}; use crate::offset::{TimeZone, Utc}; use crate::time_delta::TimeDelta; use crate::DateTime; +use crate::ParseError; use crate::{Datelike, Weekday}; /// ISO 8601 calendar date with time zone. @@ -329,8 +330,8 @@ where #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { - self.format_with_items(StrftimeItems::new(fmt)) + pub fn format<'a>(&self, fmt: &'a str) -> Result>, ParseError> { + Ok(self.format_with_items(StrftimeItems::new(fmt)?)) } /// Formats the date with the specified formatting items and locale. @@ -365,8 +366,8 @@ where &self, fmt: &'a str, locale: Locale, - ) -> DelayedFormat> { - self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale) + ) -> Result>, ParseError> { + Ok(self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale)?, locale)) } } diff --git a/src/datetime/mod.rs b/src/datetime/mod.rs index 8f84ab1bf3..fea7ca02eb 100644 --- a/src/datetime/mod.rs +++ b/src/datetime/mod.rs @@ -583,7 +583,7 @@ impl DateTime { /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult> { let mut parsed = Parsed::new(); - parse(&mut parsed, s, StrftimeItems::new(fmt))?; + parse(&mut parsed, s, StrftimeItems::new(fmt)?)?; parsed.to_datetime() } } @@ -758,14 +758,14 @@ where /// use chrono::prelude::*; /// /// let date_time: DateTime = Utc.with_ymd_and_hms(2017, 04, 02, 12, 50, 32).unwrap(); - /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M")); + /// let formatted = format!("{}", date_time.format("%d/%m/%Y %H:%M").unwrap()); /// assert_eq!(formatted, "02/04/2017 12:50"); /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { - self.format_with_items(StrftimeItems::new(fmt)) + pub fn format<'a>(&self, fmt: &'a str) -> Result>, ParseError> { + Ok(self.format_with_items(StrftimeItems::new(fmt)?)) } /// Formats the combined date and time with the specified formatting items and locale. @@ -803,8 +803,8 @@ where &self, fmt: &'a str, locale: Locale, - ) -> DelayedFormat> { - self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale) + ) -> Result>, ParseError> { + Ok(self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale)?, locale)) } } @@ -1336,3 +1336,8 @@ fn test_decodable_json( assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err()); } + +#[test] +fn test_invalid_format() { + assert!(Utc::now().format("%").is_err()); +} diff --git a/src/datetime/tests.rs b/src/datetime/tests.rs index 3e8a871f98..be77d75d95 100644 --- a/src/datetime/tests.rs +++ b/src/datetime/tests.rs @@ -1549,7 +1549,10 @@ fn test_to_string_round_trip_with_local() { fn test_datetime_format_with_local() { // if we are not around the year boundary, local and UTC date should have the same year let dt = Local::now().with_month(5).unwrap(); - assert_eq!(dt.format("%Y").to_string(), dt.with_timezone(&Utc).format("%Y").to_string()); + assert_eq!( + dt.format("%Y").unwrap().to_string(), + dt.with_timezone(&Utc).format("%Y").unwrap().to_string() + ); } #[test] @@ -1740,25 +1743,25 @@ fn test_datetime_format_alignment() { let datetime = Utc.with_ymd_and_hms(2007, 1, 2, 0, 0, 0).unwrap(); // Item::Literal - let percent = datetime.format("%%"); + let percent = datetime.format("%%").unwrap(); assert_eq!(" %", format!("{:>3}", percent)); assert_eq!("% ", format!("{:<3}", percent)); assert_eq!(" % ", format!("{:^3}", percent)); // Item::Numeric - let year = datetime.format("%Y"); + let year = datetime.format("%Y").unwrap(); assert_eq!(" 2007", format!("{:>6}", year)); assert_eq!("2007 ", format!("{:<6}", year)); assert_eq!(" 2007 ", format!("{:^6}", year)); // Item::Fixed - let tz = datetime.format("%Z"); + let tz = datetime.format("%Z").unwrap(); assert_eq!(" UTC", format!("{:>5}", tz)); assert_eq!("UTC ", format!("{:<5}", tz)); assert_eq!(" UTC ", format!("{:^5}", tz)); // [Item::Numeric, Item::Space, Item::Literal, Item::Space, Item::Numeric] - let ymd = datetime.format("%Y %B %d"); + let ymd = datetime.format("%Y %B %d").unwrap(); let ymd_formatted = "2007 January 02"; assert_eq!(format!(" {}", ymd_formatted), format!("{:>17}", ymd)); assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd)); diff --git a/src/format/mod.rs b/src/format/mod.rs index 726ae2e909..49200fa8f1 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -22,7 +22,7 @@ //! //! let date_time = Utc.with_ymd_and_hms(2020, 11, 10, 0, 1, 32).unwrap(); //! -//! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S")); +//! let formatted = format!("{}", date_time.format("%Y-%m-%d %H:%M:%S").unwrap()); //! assert_eq!(formatted, "2020-11-10 00:01:32"); //! //! let parsed = Utc.datetime_from_str(&formatted, "%Y-%m-%d %H:%M:%S")?; diff --git a/src/format/parse.rs b/src/format/parse.rs index fa9b781ecd..d61b4032a0 100644 --- a/src/format/parse.rs +++ b/src/format/parse.rs @@ -1419,7 +1419,7 @@ fn parse_rfc850() { let dt = Utc.with_ymd_and_hms(1994, 11, 6, 8, 49, 37).unwrap(); // Check that the format is what we expect - assert_eq!(dt.format(RFC850_FMT).to_string(), dt_str); + assert_eq!(dt.format(RFC850_FMT).unwrap().to_string(), dt_str); // Check that it parses correctly assert_eq!(Ok(dt), Utc.datetime_from_str("Sunday, 06-Nov-94 08:49:37 GMT", RFC850_FMT)); diff --git a/src/format/strftime.rs b/src/format/strftime.rs index 5bfd1aa759..e64db82c29 100644 --- a/src/format/strftime.rs +++ b/src/format/strftime.rs @@ -174,6 +174,8 @@ Notes: China Daylight Time. */ +use crate::format::{ParseError, BAD_FORMAT}; + #[cfg(feature = "unstable-locales")] extern crate alloc; @@ -227,19 +229,33 @@ pub struct StrftimeItems<'a> { impl<'a> StrftimeItems<'a> { /// Creates a new parsing iterator from the `strftime`-like format string. - pub fn new(s: &'a str) -> StrftimeItems<'a> { - Self::with_remainer(s) + pub fn new(s: &'a str) -> Result, ParseError> { + let strftime = Self::with_remainer(s); + if strftime.clone().any(|i| i == Item::Error) { + return Err(BAD_FORMAT); + } + Ok(strftime) } /// Creates a new parsing iterator from the `strftime`-like format string. #[cfg(feature = "unstable-locales")] #[cfg_attr(docsrs, doc(cfg(feature = "unstable-locales")))] - pub fn new_with_locale(s: &'a str, locale: Locale) -> StrftimeItems<'a> { - let d_fmt = StrftimeItems::new(locales::d_fmt(locale)).collect(); - let d_t_fmt = StrftimeItems::new(locales::d_t_fmt(locale)).collect(); - let t_fmt = StrftimeItems::new(locales::t_fmt(locale)).collect(); - - StrftimeItems { remainder: s, recons: Vec::new(), d_fmt, d_t_fmt, t_fmt } + pub fn new_with_locale(s: &'a str, locale: Locale) -> Result, ParseError> { + let d_fmt = StrftimeItems::new(locales::d_fmt(locale)) + .expect("ERROR: No date format defined for given format") + .collect(); + let d_t_fmt = StrftimeItems::new(locales::d_t_fmt(locale)) + .expect("ERROR: No datetime format for the given locale") + .collect(); + let t_fmt = StrftimeItems::new(locales::t_fmt(locale)) + .expect("ERROR: No time format gor the given locale") + .collect(); + + let strftime = StrftimeItems { remainder: s, recons: Vec::new(), d_fmt, d_t_fmt, t_fmt }; + if strftime.clone().any(|i| i == Item::Error) { + return Err(BAD_FORMAT); + } + return Ok(strftime); } #[cfg(not(feature = "unstable-locales"))] @@ -506,9 +522,10 @@ fn test_strftime_items() { fn parse_and_collect(s: &str) -> Vec> { // map any error into `[Item::Error]`. useful for easy testing. eprintln!("test_strftime_items: parse_and_collect({:?})", s); - let items = StrftimeItems::new(s); - let items = items.map(|spec| if spec == Item::Error { None } else { Some(spec) }); - items.collect::>>().unwrap_or_else(|| vec![Item::Error]) + match StrftimeItems::new(s) { + Err(_) => vec![Item::Error], + Ok(items) => items.into_iter().collect(), + } } assert_eq!(parse_and_collect(""), []); @@ -645,69 +662,72 @@ fn test_strftime_docs() { .unwrap(); // date specifiers - assert_eq!(dt.format("%Y").to_string(), "2001"); - assert_eq!(dt.format("%C").to_string(), "20"); - assert_eq!(dt.format("%y").to_string(), "01"); - assert_eq!(dt.format("%m").to_string(), "07"); - assert_eq!(dt.format("%b").to_string(), "Jul"); - assert_eq!(dt.format("%B").to_string(), "July"); - assert_eq!(dt.format("%h").to_string(), "Jul"); - assert_eq!(dt.format("%d").to_string(), "08"); - assert_eq!(dt.format("%e").to_string(), " 8"); - assert_eq!(dt.format("%e").to_string(), dt.format("%_d").to_string()); - assert_eq!(dt.format("%a").to_string(), "Sun"); - assert_eq!(dt.format("%A").to_string(), "Sunday"); - assert_eq!(dt.format("%w").to_string(), "0"); - assert_eq!(dt.format("%u").to_string(), "7"); - assert_eq!(dt.format("%U").to_string(), "27"); - assert_eq!(dt.format("%W").to_string(), "27"); - assert_eq!(dt.format("%G").to_string(), "2001"); - assert_eq!(dt.format("%g").to_string(), "01"); - assert_eq!(dt.format("%V").to_string(), "27"); - assert_eq!(dt.format("%j").to_string(), "189"); - assert_eq!(dt.format("%D").to_string(), "07/08/01"); - assert_eq!(dt.format("%x").to_string(), "07/08/01"); - assert_eq!(dt.format("%F").to_string(), "2001-07-08"); - assert_eq!(dt.format("%v").to_string(), " 8-Jul-2001"); + assert_eq!(dt.format("%Y").unwrap().to_string(), "2001"); + assert_eq!(dt.format("%C").unwrap().to_string(), "20"); + assert_eq!(dt.format("%y").unwrap().to_string(), "01"); + assert_eq!(dt.format("%m").unwrap().to_string(), "07"); + assert_eq!(dt.format("%b").unwrap().to_string(), "Jul"); + assert_eq!(dt.format("%B").unwrap().to_string(), "July"); + assert_eq!(dt.format("%h").unwrap().to_string(), "Jul"); + assert_eq!(dt.format("%d").unwrap().to_string(), "08"); + assert_eq!(dt.format("%e").unwrap().to_string(), " 8"); + assert_eq!(dt.format("%e").unwrap().to_string(), dt.format("%_d").unwrap().to_string()); + assert_eq!(dt.format("%a").unwrap().to_string(), "Sun"); + assert_eq!(dt.format("%A").unwrap().to_string(), "Sunday"); + assert_eq!(dt.format("%w").unwrap().to_string(), "0"); + assert_eq!(dt.format("%u").unwrap().to_string(), "7"); + assert_eq!(dt.format("%U").unwrap().to_string(), "27"); + assert_eq!(dt.format("%W").unwrap().to_string(), "27"); + assert_eq!(dt.format("%G").unwrap().to_string(), "2001"); + assert_eq!(dt.format("%g").unwrap().to_string(), "01"); + assert_eq!(dt.format("%V").unwrap().to_string(), "27"); + assert_eq!(dt.format("%j").unwrap().to_string(), "189"); + assert_eq!(dt.format("%D").unwrap().to_string(), "07/08/01"); + assert_eq!(dt.format("%x").unwrap().to_string(), "07/08/01"); + assert_eq!(dt.format("%F").unwrap().to_string(), "2001-07-08"); + assert_eq!(dt.format("%v").unwrap().to_string(), " 8-Jul-2001"); // time specifiers - assert_eq!(dt.format("%H").to_string(), "00"); - assert_eq!(dt.format("%k").to_string(), " 0"); - assert_eq!(dt.format("%k").to_string(), dt.format("%_H").to_string()); - assert_eq!(dt.format("%I").to_string(), "12"); - assert_eq!(dt.format("%l").to_string(), "12"); - assert_eq!(dt.format("%l").to_string(), dt.format("%_I").to_string()); - assert_eq!(dt.format("%P").to_string(), "am"); - assert_eq!(dt.format("%p").to_string(), "AM"); - assert_eq!(dt.format("%M").to_string(), "34"); - assert_eq!(dt.format("%S").to_string(), "60"); - assert_eq!(dt.format("%f").to_string(), "026490708"); - assert_eq!(dt.format("%.f").to_string(), ".026490708"); - assert_eq!(dt.with_nanosecond(1_026_490_000).unwrap().format("%.f").to_string(), ".026490"); - assert_eq!(dt.format("%.3f").to_string(), ".026"); - assert_eq!(dt.format("%.6f").to_string(), ".026490"); - assert_eq!(dt.format("%.9f").to_string(), ".026490708"); - assert_eq!(dt.format("%3f").to_string(), "026"); - assert_eq!(dt.format("%6f").to_string(), "026490"); - assert_eq!(dt.format("%9f").to_string(), "026490708"); - assert_eq!(dt.format("%R").to_string(), "00:34"); - assert_eq!(dt.format("%T").to_string(), "00:34:60"); - assert_eq!(dt.format("%X").to_string(), "00:34:60"); - assert_eq!(dt.format("%r").to_string(), "12:34:60 AM"); + assert_eq!(dt.format("%H").unwrap().to_string(), "00"); + assert_eq!(dt.format("%k").unwrap().to_string(), " 0"); + assert_eq!(dt.format("%k").unwrap().to_string(), dt.format("%_H").unwrap().to_string()); + assert_eq!(dt.format("%I").unwrap().to_string(), "12"); + assert_eq!(dt.format("%l").unwrap().to_string(), "12"); + assert_eq!(dt.format("%l").unwrap().to_string(), dt.format("%_I").unwrap().to_string()); + assert_eq!(dt.format("%P").unwrap().to_string(), "am"); + assert_eq!(dt.format("%p").unwrap().to_string(), "AM"); + assert_eq!(dt.format("%M").unwrap().to_string(), "34"); + assert_eq!(dt.format("%S").unwrap().to_string(), "60"); + assert_eq!(dt.format("%f").unwrap().to_string(), "026490708"); + assert_eq!(dt.format("%.f").unwrap().to_string(), ".026490708"); + assert_eq!( + dt.with_nanosecond(1_026_490_000).unwrap().format("%.f").unwrap().to_string(), + ".026490" + ); + assert_eq!(dt.format("%.3f").unwrap().to_string(), ".026"); + assert_eq!(dt.format("%.6f").unwrap().to_string(), ".026490"); + assert_eq!(dt.format("%.9f").unwrap().to_string(), ".026490708"); + assert_eq!(dt.format("%3f").unwrap().to_string(), "026"); + assert_eq!(dt.format("%6f").unwrap().to_string(), "026490"); + assert_eq!(dt.format("%9f").unwrap().to_string(), "026490708"); + assert_eq!(dt.format("%R").unwrap().to_string(), "00:34"); + assert_eq!(dt.format("%T").unwrap().to_string(), "00:34:60"); + assert_eq!(dt.format("%X").unwrap().to_string(), "00:34:60"); + assert_eq!(dt.format("%r").unwrap().to_string(), "12:34:60 AM"); // time zone specifiers - //assert_eq!(dt.format("%Z").to_string(), "ACST"); - assert_eq!(dt.format("%z").to_string(), "+0930"); - assert_eq!(dt.format("%:z").to_string(), "+09:30"); - assert_eq!(dt.format("%::z").to_string(), "+09:30:00"); - assert_eq!(dt.format("%:::z").to_string(), "+09"); + //assert_eq!(dt.format("%Z").unwrap().to_string(), "ACST"); + assert_eq!(dt.format("%z").unwrap().to_string(), "+0930"); + assert_eq!(dt.format("%:z").unwrap().to_string(), "+09:30"); + assert_eq!(dt.format("%::z").unwrap().to_string(), "+09:30:00"); + assert_eq!(dt.format("%:::z").unwrap().to_string(), "+09"); // date & time specifiers - assert_eq!(dt.format("%c").to_string(), "Sun Jul 8 00:34:60 2001"); - assert_eq!(dt.format("%+").to_string(), "2001-07-08T00:34:60.026490708+09:30"); + assert_eq!(dt.format("%c").unwrap().to_string(), "Sun Jul 8 00:34:60 2001"); + assert_eq!(dt.format("%+").unwrap().to_string(), "2001-07-08T00:34:60.026490708+09:30"); assert_eq!( - dt.with_timezone(&Utc).format("%+").to_string(), + dt.with_timezone(&Utc).format("%+").unwrap().to_string(), "2001-07-07T15:04:60.026490708+00:00" ); assert_eq!( @@ -724,20 +744,20 @@ fn test_strftime_docs() { ); assert_eq!( - dt.with_nanosecond(1_026_490_000).unwrap().format("%+").to_string(), + dt.with_nanosecond(1_026_490_000).unwrap().format("%+").unwrap().to_string(), "2001-07-08T00:34:60.026490+09:30" ); - assert_eq!(dt.format("%s").to_string(), "994518299"); + assert_eq!(dt.format("%s").unwrap().to_string(), "994518299"); // special specifiers - assert_eq!(dt.format("%t").to_string(), "\t"); - assert_eq!(dt.format("%n").to_string(), "\n"); - assert_eq!(dt.format("%%").to_string(), "%"); + assert_eq!(dt.format("%t").unwrap().to_string(), "\t"); + assert_eq!(dt.format("%n").unwrap().to_string(), "\n"); + assert_eq!(dt.format("%%").unwrap().to_string(), "%"); // complex format specifiers - assert_eq!(dt.format(" %Y%d%m%%%%%t%H%M%S\t").to_string(), " 20010807%%\t003460\t"); + assert_eq!(dt.format(" %Y%d%m%%%%%t%H%M%S\t").unwrap().to_string(), " 20010807%%\t003460\t"); assert_eq!( - dt.format(" %Y%d%m%%%%%t%H:%P:%M%S%:::z\t").to_string(), + dt.format(" %Y%d%m%%%%%t%H:%P:%M%S%:::z\t").unwrap().to_string(), " 20010807%%\t00:am:3460+09\t" ); } @@ -754,40 +774,40 @@ fn test_strftime_docs_localized() { .unwrap(); // date specifiers - assert_eq!(dt.format_localized("%b", Locale::fr_BE).to_string(), "jui"); - assert_eq!(dt.format_localized("%B", Locale::fr_BE).to_string(), "juillet"); - assert_eq!(dt.format_localized("%h", Locale::fr_BE).to_string(), "jui"); - assert_eq!(dt.format_localized("%a", Locale::fr_BE).to_string(), "dim"); - assert_eq!(dt.format_localized("%A", Locale::fr_BE).to_string(), "dimanche"); - assert_eq!(dt.format_localized("%D", Locale::fr_BE).to_string(), "07/08/01"); - assert_eq!(dt.format_localized("%x", Locale::fr_BE).to_string(), "08/07/01"); - assert_eq!(dt.format_localized("%F", Locale::fr_BE).to_string(), "2001-07-08"); - assert_eq!(dt.format_localized("%v", Locale::fr_BE).to_string(), " 8-jui-2001"); + assert_eq!(dt.format_localized("%b", Locale::fr_BE).unwrap().to_string(), "jui"); + assert_eq!(dt.format_localized("%B", Locale::fr_BE).unwrap().to_string(), "juillet"); + assert_eq!(dt.format_localized("%h", Locale::fr_BE).unwrap().to_string(), "jui"); + assert_eq!(dt.format_localized("%a", Locale::fr_BE).unwrap().to_string(), "dim"); + assert_eq!(dt.format_localized("%A", Locale::fr_BE).unwrap().to_string(), "dimanche"); + assert_eq!(dt.format_localized("%D", Locale::fr_BE).unwrap().to_string(), "07/08/01"); + assert_eq!(dt.format_localized("%x", Locale::fr_BE).unwrap().to_string(), "08/07/01"); + assert_eq!(dt.format_localized("%F", Locale::fr_BE).unwrap().to_string(), "2001-07-08"); + assert_eq!(dt.format_localized("%v", Locale::fr_BE).unwrap().to_string(), " 8-jui-2001"); // time specifiers - assert_eq!(dt.format_localized("%P", Locale::fr_BE).to_string(), ""); - assert_eq!(dt.format_localized("%p", Locale::fr_BE).to_string(), ""); - assert_eq!(dt.format_localized("%R", Locale::fr_BE).to_string(), "00:34"); - assert_eq!(dt.format_localized("%T", Locale::fr_BE).to_string(), "00:34:60"); - assert_eq!(dt.format_localized("%X", Locale::fr_BE).to_string(), "00:34:60"); - assert_eq!(dt.format_localized("%r", Locale::fr_BE).to_string(), "12:34:60 "); + assert_eq!(dt.format_localized("%P", Locale::fr_BE).unwrap().to_string(), ""); + assert_eq!(dt.format_localized("%p", Locale::fr_BE).unwrap().to_string(), ""); + assert_eq!(dt.format_localized("%R", Locale::fr_BE).unwrap().to_string(), "00:34"); + assert_eq!(dt.format_localized("%T", Locale::fr_BE).unwrap().to_string(), "00:34:60"); + assert_eq!(dt.format_localized("%X", Locale::fr_BE).unwrap().to_string(), "00:34:60"); + assert_eq!(dt.format_localized("%r", Locale::fr_BE).unwrap().to_string(), "12:34:60 "); // date & time specifiers assert_eq!( - dt.format_localized("%c", Locale::fr_BE).to_string(), + dt.format_localized("%c", Locale::fr_BE).unwrap().to_string(), "dim 08 jui 2001 00:34:60 +09:30" ); let nd = NaiveDate::from_ymd_opt(2001, 7, 8).unwrap(); // date specifiers - assert_eq!(nd.format_localized("%b", Locale::de_DE).to_string(), "Jul"); - assert_eq!(nd.format_localized("%B", Locale::de_DE).to_string(), "Juli"); - assert_eq!(nd.format_localized("%h", Locale::de_DE).to_string(), "Jul"); - assert_eq!(nd.format_localized("%a", Locale::de_DE).to_string(), "So"); - assert_eq!(nd.format_localized("%A", Locale::de_DE).to_string(), "Sonntag"); - assert_eq!(nd.format_localized("%D", Locale::de_DE).to_string(), "07/08/01"); - assert_eq!(nd.format_localized("%x", Locale::de_DE).to_string(), "08.07.2001"); - assert_eq!(nd.format_localized("%F", Locale::de_DE).to_string(), "2001-07-08"); - assert_eq!(nd.format_localized("%v", Locale::de_DE).to_string(), " 8-Jul-2001"); + assert_eq!(nd.format_localized("%b", Locale::de_DE).unwrap().to_string(), "Jul"); + assert_eq!(nd.format_localized("%B", Locale::de_DE).unwrap().to_string(), "Juli"); + assert_eq!(nd.format_localized("%h", Locale::de_DE).unwrap().to_string(), "Jul"); + assert_eq!(nd.format_localized("%a", Locale::de_DE).unwrap().to_string(), "So"); + assert_eq!(nd.format_localized("%A", Locale::de_DE).unwrap().to_string(), "Sonntag"); + assert_eq!(nd.format_localized("%D", Locale::de_DE).unwrap().to_string(), "07/08/01"); + assert_eq!(nd.format_localized("%x", Locale::de_DE).unwrap().to_string(), "08.07.2001"); + assert_eq!(nd.format_localized("%F", Locale::de_DE).unwrap().to_string(), "2001-07-08"); + assert_eq!(nd.format_localized("%v", Locale::de_DE).unwrap().to_string(), " 8-Jul-2001"); } diff --git a/src/lib.rs b/src/lib.rs index d108b73eaf..02139f4a7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -208,11 +208,11 @@ //! # #[cfg(feature = "unstable-locales")] //! # fn test() { //! let dt = Utc.with_ymd_and_hms(2014, 11, 28, 12, 0, 9).unwrap(); -//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2014-11-28 12:00:09"); -//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), "Fri Nov 28 12:00:09 2014"); -//! assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).to_string(), "vendredi 28 novembre 2014, 12:00:09"); +//! assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").unwrap().to_string(), "2014-11-28 12:00:09"); +//! assert_eq!(dt.format("%a %b %e %T %Y").unwrap().to_string(), "Fri Nov 28 12:00:09 2014"); +//! assert_eq!(dt.format_localized("%A %e %B %Y, %T", Locale::fr_BE).unwrap().to_string(), "vendredi 28 novembre 2014, 12:00:09"); //! -//! assert_eq!(dt.format("%a %b %e %T %Y").to_string(), dt.format("%c").to_string()); +//! assert_eq!(dt.format("%a %b %e %T %Y").unwrap().to_string(), dt.format("%c").unwrap().to_string()); //! assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC"); //! assert_eq!(dt.to_rfc2822(), "Fri, 28 Nov 2014 12:00:09 +0000"); //! assert_eq!(dt.to_rfc3339(), "2014-11-28T12:00:09+00:00"); @@ -329,7 +329,7 @@ //! //! assert_eq!(Utc.ymd_opt(2014, 11, 28).unwrap().weekday(), Weekday::Fri); //! assert_eq!(Utc.ymd_opt(2014, 11, 31), LocalResult::None); -//! assert_eq!(NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_milli_opt(7, 8, 9, 10).unwrap().and_local_timezone(Utc).unwrap().format("%H%M%S").to_string(), +//! assert_eq!(NaiveDate::from_ymd_opt(2014, 11, 28).unwrap().and_hms_milli_opt(7, 8, 9, 10).unwrap().and_local_timezone(Utc).unwrap().format("%H%M%S").unwrap().to_string(), //! "070809"); //! ``` //! diff --git a/src/naive/date.rs b/src/naive/date.rs index 4271145e2b..159648fcfc 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -528,7 +528,7 @@ impl NaiveDate { /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { let mut parsed = Parsed::new(); - parse(&mut parsed, s, StrftimeItems::new(fmt))?; + parse(&mut parsed, s, StrftimeItems::new(fmt)?)?; parsed.to_naive_date() } @@ -1096,10 +1096,10 @@ impl NaiveDate { /// use chrono::NaiveDate; /// use chrono::format::strftime::StrftimeItems; /// - /// let fmt = StrftimeItems::new("%Y-%m-%d"); + /// let fmt = StrftimeItems::new("%Y-%m-%d").unwrap(); /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); /// assert_eq!(d.format_with_items(fmt.clone()).to_string(), "2015-09-05"); - /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); + /// assert_eq!(d.format("%Y-%m-%d").unwrap().to_string(), "2015-09-05"); /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -1107,7 +1107,7 @@ impl NaiveDate { /// ``` /// # use chrono::NaiveDate; /// # use chrono::format::strftime::StrftimeItems; - /// # let fmt = StrftimeItems::new("%Y-%m-%d").clone(); + /// # let fmt = StrftimeItems::new("%Y-%m-%d").unwrap().clone(); /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); /// assert_eq!(format!("{}", d.format_with_items(fmt)), "2015-09-05"); /// ``` @@ -1142,8 +1142,8 @@ impl NaiveDate { /// use chrono::NaiveDate; /// /// let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); - /// assert_eq!(d.format("%Y-%m-%d").to_string(), "2015-09-05"); - /// assert_eq!(d.format("%A, %-d %B, %C%y").to_string(), "Saturday, 5 September, 2015"); + /// assert_eq!(d.format("%Y-%m-%d").unwrap().to_string(), "2015-09-05"); + /// assert_eq!(d.format("%A, %-d %B, %C%y").unwrap().to_string(), "Saturday, 5 September, 2015"); /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -1151,14 +1151,14 @@ impl NaiveDate { /// ``` /// # use chrono::NaiveDate; /// # let d = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap(); - /// assert_eq!(format!("{}", d.format("%Y-%m-%d")), "2015-09-05"); - /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y")), "Saturday, 5 September, 2015"); + /// assert_eq!(format!("{}", d.format("%Y-%m-%d").unwrap()), "2015-09-05"); + /// assert_eq!(format!("{}", d.format("%A, %-d %B, %C%y").unwrap()), "Saturday, 5 September, 2015"); /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { - self.format_with_items(StrftimeItems::new(fmt)) + pub fn format<'a>(&self, fmt: &'a str) -> Result>, ParseError> { + Ok(self.format_with_items(StrftimeItems::new(fmt)?)) } /// Formats the date with the specified formatting items and locale. @@ -1188,8 +1188,8 @@ impl NaiveDate { &self, fmt: &'a str, locale: Locale, - ) -> DelayedFormat> { - self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale), locale) + ) -> Result>, ParseError> { + Ok(self.format_localized_with_items(StrftimeItems::new_with_locale(fmt, locale)?, locale)) } /// Returns an iterator that steps by days across all representable dates. @@ -2839,43 +2839,78 @@ mod tests { #[test] fn test_date_format() { let d = NaiveDate::from_ymd_opt(2012, 3, 4).unwrap(); - assert_eq!(d.format("%Y,%C,%y,%G,%g").to_string(), "2012,20,12,2012,12"); - assert_eq!(d.format("%m,%b,%h,%B").to_string(), "03,Mar,Mar,March"); - assert_eq!(d.format("%d,%e").to_string(), "04, 4"); - assert_eq!(d.format("%U,%W,%V").to_string(), "10,09,09"); - assert_eq!(d.format("%a,%A,%w,%u").to_string(), "Sun,Sunday,0,7"); - assert_eq!(d.format("%j").to_string(), "064"); // since 2012 is a leap year - assert_eq!(d.format("%D,%x").to_string(), "03/04/12,03/04/12"); - assert_eq!(d.format("%F").to_string(), "2012-03-04"); - assert_eq!(d.format("%v").to_string(), " 4-Mar-2012"); - assert_eq!(d.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); + assert_eq!(d.format("%Y,%C,%y,%G,%g").unwrap().to_string(), "2012,20,12,2012,12"); + assert_eq!(d.format("%m,%b,%h,%B").unwrap().to_string(), "03,Mar,Mar,March"); + assert_eq!(d.format("%d,%e").unwrap().to_string(), "04, 4"); + assert_eq!(d.format("%U,%W,%V").unwrap().to_string(), "10,09,09"); + assert_eq!(d.format("%a,%A,%w,%u").unwrap().to_string(), "Sun,Sunday,0,7"); + assert_eq!(d.format("%j").unwrap().to_string(), "064"); // since 2012 is a leap year + assert_eq!(d.format("%D,%x").unwrap().to_string(), "03/04/12,03/04/12"); + assert_eq!(d.format("%F").unwrap().to_string(), "2012-03-04"); + assert_eq!(d.format("%v").unwrap().to_string(), " 4-Mar-2012"); + assert_eq!(d.format("%t%n%%%n%t").unwrap().to_string(), "\t\n%\n\t"); // non-four-digit years assert_eq!( - NaiveDate::from_ymd_opt(12345, 1, 1).unwrap().format("%Y").to_string(), + NaiveDate::from_ymd_opt(12345, 1, 1).unwrap().format("%Y").unwrap().to_string(), "+12345" ); - assert_eq!(NaiveDate::from_ymd_opt(1234, 1, 1).unwrap().format("%Y").to_string(), "1234"); - assert_eq!(NaiveDate::from_ymd_opt(123, 1, 1).unwrap().format("%Y").to_string(), "0123"); - assert_eq!(NaiveDate::from_ymd_opt(12, 1, 1).unwrap().format("%Y").to_string(), "0012"); - assert_eq!(NaiveDate::from_ymd_opt(1, 1, 1).unwrap().format("%Y").to_string(), "0001"); - assert_eq!(NaiveDate::from_ymd_opt(0, 1, 1).unwrap().format("%Y").to_string(), "0000"); - assert_eq!(NaiveDate::from_ymd_opt(-1, 1, 1).unwrap().format("%Y").to_string(), "-0001"); - assert_eq!(NaiveDate::from_ymd_opt(-12, 1, 1).unwrap().format("%Y").to_string(), "-0012"); - assert_eq!(NaiveDate::from_ymd_opt(-123, 1, 1).unwrap().format("%Y").to_string(), "-0123"); - assert_eq!(NaiveDate::from_ymd_opt(-1234, 1, 1).unwrap().format("%Y").to_string(), "-1234"); assert_eq!( - NaiveDate::from_ymd_opt(-12345, 1, 1).unwrap().format("%Y").to_string(), + NaiveDate::from_ymd_opt(1234, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "1234" + ); + assert_eq!( + NaiveDate::from_ymd_opt(123, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "0123" + ); + assert_eq!( + NaiveDate::from_ymd_opt(12, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "0012" + ); + assert_eq!( + NaiveDate::from_ymd_opt(1, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "0001" + ); + assert_eq!( + NaiveDate::from_ymd_opt(0, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "0000" + ); + assert_eq!( + NaiveDate::from_ymd_opt(-1, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "-0001" + ); + assert_eq!( + NaiveDate::from_ymd_opt(-12, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "-0012" + ); + assert_eq!( + NaiveDate::from_ymd_opt(-123, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "-0123" + ); + assert_eq!( + NaiveDate::from_ymd_opt(-1234, 1, 1).unwrap().format("%Y").unwrap().to_string(), + "-1234" + ); + assert_eq!( + NaiveDate::from_ymd_opt(-12345, 1, 1).unwrap().format("%Y").unwrap().to_string(), "-12345" ); // corner cases assert_eq!( - NaiveDate::from_ymd_opt(2007, 12, 31).unwrap().format("%G,%g,%U,%W,%V").to_string(), + NaiveDate::from_ymd_opt(2007, 12, 31) + .unwrap() + .format("%G,%g,%U,%W,%V") + .unwrap() + .to_string(), "2008,08,52,53,01" ); assert_eq!( - NaiveDate::from_ymd_opt(2010, 1, 3).unwrap().format("%G,%g,%U,%W,%V").to_string(), + NaiveDate::from_ymd_opt(2010, 1, 3) + .unwrap() + .format("%G,%g,%U,%W,%V") + .unwrap() + .to_string(), "2009,09,01,00,53" ); } diff --git a/src/naive/datetime/mod.rs b/src/naive/datetime/mod.rs index f324ed4a90..bbc58836af 100644 --- a/src/naive/datetime/mod.rs +++ b/src/naive/datetime/mod.rs @@ -315,7 +315,7 @@ impl NaiveDateTime { ///``` pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { let mut parsed = Parsed::new(); - parse(&mut parsed, s, StrftimeItems::new(fmt))?; + parse(&mut parsed, s, StrftimeItems::new(fmt)?)?; parsed.to_naive_datetime_with_offset(0) // no offset adjustment } @@ -812,10 +812,10 @@ impl NaiveDateTime { /// use chrono::NaiveDate; /// use chrono::format::strftime::StrftimeItems; /// - /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S"); + /// let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").unwrap(); /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); /// assert_eq!(dt.format_with_items(fmt.clone()).to_string(), "2015-09-05 23:56:04"); - /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04"); + /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").unwrap().to_string(), "2015-09-05 23:56:04"); /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -823,7 +823,7 @@ impl NaiveDateTime { /// ``` /// # use chrono::NaiveDate; /// # use chrono::format::strftime::StrftimeItems; - /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").clone(); + /// # let fmt = StrftimeItems::new("%Y-%m-%d %H:%M:%S").unwrap().clone(); /// # let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); /// assert_eq!(format!("{}", dt.format_with_items(fmt)), "2015-09-05 23:56:04"); /// ``` @@ -858,8 +858,8 @@ impl NaiveDateTime { /// use chrono::NaiveDate; /// /// let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); - /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").to_string(), "2015-09-05 23:56:04"); - /// assert_eq!(dt.format("around %l %p on %b %-d").to_string(), "around 11 PM on Sep 5"); + /// assert_eq!(dt.format("%Y-%m-%d %H:%M:%S").unwrap().to_string(), "2015-09-05 23:56:04"); + /// assert_eq!(dt.format("around %l %p on %b %-d").unwrap().to_string(), "around 11 PM on Sep 5"); /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -867,14 +867,14 @@ impl NaiveDateTime { /// ``` /// # use chrono::NaiveDate; /// # let dt = NaiveDate::from_ymd_opt(2015, 9, 5).unwrap().and_hms_opt(23, 56, 4).unwrap(); - /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S")), "2015-09-05 23:56:04"); - /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d")), "around 11 PM on Sep 5"); + /// assert_eq!(format!("{}", dt.format("%Y-%m-%d %H:%M:%S").unwrap()), "2015-09-05 23:56:04"); + /// assert_eq!(format!("{}", dt.format("around %l %p on %b %-d").unwrap()), "around 11 PM on Sep 5"); /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { - self.format_with_items(StrftimeItems::new(fmt)) + pub fn format<'a>(&self, fmt: &'a str) -> Result>, ParseError> { + Ok(self.format_with_items(StrftimeItems::new(fmt)?)) } /// Converts the `NaiveDateTime` into the timezone-aware `DateTime` diff --git a/src/naive/datetime/tests.rs b/src/naive/datetime/tests.rs index c07c00f659..be9df12916 100644 --- a/src/naive/datetime/tests.rs +++ b/src/naive/datetime/tests.rs @@ -20,7 +20,7 @@ fn test_datetime_from_timestamp_millis() { for (timestamp_millis, formatted) in valid_map.iter().copied() { let naive_datetime = NaiveDateTime::from_timestamp_millis(timestamp_millis); assert_eq!(timestamp_millis, naive_datetime.unwrap().timestamp_millis()); - assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted); + assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").unwrap().to_string(), formatted); } let invalid = [i64::MAX, i64::MIN]; @@ -57,7 +57,7 @@ fn test_datetime_from_timestamp_micros() { for (timestamp_micros, formatted) in valid_map.iter().copied() { let naive_datetime = NaiveDateTime::from_timestamp_micros(timestamp_micros); assert_eq!(timestamp_micros, naive_datetime.unwrap().timestamp_micros()); - assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").to_string(), formatted); + assert_eq!(naive_datetime.unwrap().format("%F %T%.9f").unwrap().to_string(), formatted); } let invalid = [i64::MAX, i64::MIN]; @@ -329,15 +329,15 @@ fn test_datetime_parse_from_str() { #[test] fn test_datetime_format() { let dt = NaiveDate::from_ymd_opt(2010, 9, 8).unwrap().and_hms_milli_opt(7, 6, 54, 321).unwrap(); - assert_eq!(dt.format("%c").to_string(), "Wed Sep 8 07:06:54 2010"); - assert_eq!(dt.format("%s").to_string(), "1283929614"); - assert_eq!(dt.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); + assert_eq!(dt.format("%c").unwrap().to_string(), "Wed Sep 8 07:06:54 2010"); + assert_eq!(dt.format("%s").unwrap().to_string(), "1283929614"); + assert_eq!(dt.format("%t%n%%%n%t").unwrap().to_string(), "\t\n%\n\t"); // a horror of leap second: coming near to you. let dt = NaiveDate::from_ymd_opt(2012, 6, 30).unwrap().and_hms_milli_opt(23, 59, 59, 1_000).unwrap(); - assert_eq!(dt.format("%c").to_string(), "Sat Jun 30 23:59:60 2012"); - assert_eq!(dt.format("%s").to_string(), "1341100799"); // not 1341100800, it's intentional. + assert_eq!(dt.format("%c").unwrap().to_string(), "Sat Jun 30 23:59:60 2012"); + assert_eq!(dt.format("%s").unwrap().to_string(), "1341100799"); // not 1341100800, it's intentional. } #[test] diff --git a/src/naive/isoweek.rs b/src/naive/isoweek.rs index 45c2a81ede..2c416f4999 100644 --- a/src/naive/isoweek.rs +++ b/src/naive/isoweek.rs @@ -158,12 +158,12 @@ mod tests { assert_eq!(minweek.year(), internals::MIN_YEAR); assert_eq!(minweek.week(), 1); assert_eq!(minweek.week0(), 0); - assert_eq!(format!("{:?}", minweek), NaiveDate::MIN.format("%G-W%V").to_string()); + assert_eq!(format!("{:?}", minweek), NaiveDate::MIN.format("%G-W%V").unwrap().to_string()); assert_eq!(maxweek.year(), internals::MAX_YEAR + 1); assert_eq!(maxweek.week(), 1); assert_eq!(maxweek.week0(), 0); - assert_eq!(format!("{:?}", maxweek), NaiveDate::MAX.format("%G-W%V").to_string()); + assert_eq!(format!("{:?}", maxweek), NaiveDate::MAX.format("%G-W%V").unwrap().to_string()); } #[test] diff --git a/src/naive/time/mod.rs b/src/naive/time/mod.rs index 863e21b198..a0bd515bb4 100644 --- a/src/naive/time/mod.rs +++ b/src/naive/time/mod.rs @@ -465,7 +465,7 @@ impl NaiveTime { /// ``` pub fn parse_from_str(s: &str, fmt: &str) -> ParseResult { let mut parsed = Parsed::new(); - parse(&mut parsed, s, StrftimeItems::new(fmt))?; + parse(&mut parsed, s, StrftimeItems::new(fmt)?)?; parsed.to_naive_time() } @@ -674,10 +674,10 @@ impl NaiveTime { /// use chrono::NaiveTime; /// use chrono::format::strftime::StrftimeItems; /// - /// let fmt = StrftimeItems::new("%H:%M:%S"); + /// let fmt = StrftimeItems::new("%H:%M:%S").unwrap(); /// let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap(); /// assert_eq!(t.format_with_items(fmt.clone()).to_string(), "23:56:04"); - /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); + /// assert_eq!(t.format("%H:%M:%S").unwrap().to_string(), "23:56:04"); /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -685,7 +685,7 @@ impl NaiveTime { /// ``` /// # use chrono::NaiveTime; /// # use chrono::format::strftime::StrftimeItems; - /// # let fmt = StrftimeItems::new("%H:%M:%S").clone(); + /// # let fmt = StrftimeItems::new("%H:%M:%S").unwrap().clone(); /// # let t = NaiveTime::from_hms_opt(23, 56, 4).unwrap(); /// assert_eq!(format!("{}", t.format_with_items(fmt)), "23:56:04"); /// ``` @@ -720,9 +720,9 @@ impl NaiveTime { /// use chrono::NaiveTime; /// /// let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(t.format("%H:%M:%S").to_string(), "23:56:04"); - /// assert_eq!(t.format("%H:%M:%S%.6f").to_string(), "23:56:04.012345"); - /// assert_eq!(t.format("%-I:%M %p").to_string(), "11:56 PM"); + /// assert_eq!(t.format("%H:%M:%S").unwrap().to_string(), "23:56:04"); + /// assert_eq!(t.format("%H:%M:%S%.6f").unwrap().to_string(), "23:56:04.012345"); + /// assert_eq!(t.format("%-I:%M %p").unwrap().to_string(), "11:56 PM"); /// ``` /// /// The resulting `DelayedFormat` can be formatted directly via the `Display` trait. @@ -730,15 +730,15 @@ impl NaiveTime { /// ``` /// # use chrono::NaiveTime; /// # let t = NaiveTime::from_hms_nano_opt(23, 56, 4, 12_345_678).unwrap(); - /// assert_eq!(format!("{}", t.format("%H:%M:%S")), "23:56:04"); - /// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f")), "23:56:04.012345"); - /// assert_eq!(format!("{}", t.format("%-I:%M %p")), "11:56 PM"); + /// assert_eq!(format!("{}", t.format("%H:%M:%S").unwrap()), "23:56:04"); + /// assert_eq!(format!("{}", t.format("%H:%M:%S%.6f").unwrap()), "23:56:04.012345"); + /// assert_eq!(format!("{}", t.format("%-I:%M %p").unwrap()), "11:56 PM"); /// ``` #[cfg(any(feature = "alloc", feature = "std", test))] #[cfg_attr(docsrs, doc(cfg(any(feature = "alloc", feature = "std"))))] #[inline] - pub fn format<'a>(&self, fmt: &'a str) -> DelayedFormat> { - self.format_with_items(StrftimeItems::new(fmt)) + pub fn format<'a>(&self, fmt: &'a str) -> Result>, ParseError> { + Ok(self.format_with_items(StrftimeItems::new(fmt)?)) } /// Returns a triple of the hour, minute and second numbers. @@ -803,7 +803,7 @@ impl Timelike for NaiveTime { /// # use chrono::{NaiveTime, Timelike}; /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap(); /// assert_eq!(leap.second(), 59); - /// assert_eq!(leap.format("%H:%M:%S").to_string(), "23:59:60"); + /// assert_eq!(leap.format("%H:%M:%S").unwrap().to_string(), "23:59:60"); /// ``` #[inline] fn second(&self) -> u32 { @@ -831,7 +831,7 @@ impl Timelike for NaiveTime { /// # use chrono::{NaiveTime, Timelike}; /// let leap = NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap(); /// assert_eq!(leap.nanosecond(), 1_000_000_000); - /// assert_eq!(leap.format("%H:%M:%S%.9f").to_string(), "23:59:60.000000000"); + /// assert_eq!(leap.format("%H:%M:%S%.9f").unwrap().to_string(), "23:59:60.000000000"); /// ``` #[inline] fn nanosecond(&self) -> u32 { diff --git a/src/naive/time/tests.rs b/src/naive/time/tests.rs index 4aba43434b..ac9e92e77b 100644 --- a/src/naive/time/tests.rs +++ b/src/naive/time/tests.rs @@ -348,31 +348,34 @@ fn test_time_parse_from_str() { #[test] fn test_time_format() { let t = NaiveTime::from_hms_nano_opt(3, 5, 7, 98765432).unwrap(); - assert_eq!(t.format("%H,%k,%I,%l,%P,%p").to_string(), "03, 3,03, 3,am,AM"); - assert_eq!(t.format("%M").to_string(), "05"); - assert_eq!(t.format("%S,%f,%.f").to_string(), "07,098765432,.098765432"); - assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".098,.098765,.098765432"); - assert_eq!(t.format("%R").to_string(), "03:05"); - assert_eq!(t.format("%T,%X").to_string(), "03:05:07,03:05:07"); - assert_eq!(t.format("%r").to_string(), "03:05:07 AM"); - assert_eq!(t.format("%t%n%%%n%t").to_string(), "\t\n%\n\t"); + assert_eq!(t.format("%H,%k,%I,%l,%P,%p").unwrap().to_string(), "03, 3,03, 3,am,AM"); + assert_eq!(t.format("%M").unwrap().to_string(), "05"); + assert_eq!(t.format("%S,%f,%.f").unwrap().to_string(), "07,098765432,.098765432"); + assert_eq!(t.format("%.3f,%.6f,%.9f").unwrap().to_string(), ".098,.098765,.098765432"); + assert_eq!(t.format("%R").unwrap().to_string(), "03:05"); + assert_eq!(t.format("%T,%X").unwrap().to_string(), "03:05:07,03:05:07"); + assert_eq!(t.format("%r").unwrap().to_string(), "03:05:07 AM"); + assert_eq!(t.format("%t%n%%%n%t").unwrap().to_string(), "\t\n%\n\t"); let t = NaiveTime::from_hms_micro_opt(3, 5, 7, 432100).unwrap(); - assert_eq!(t.format("%S,%f,%.f").to_string(), "07,432100000,.432100"); - assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".432,.432100,.432100000"); + assert_eq!(t.format("%S,%f,%.f").unwrap().to_string(), "07,432100000,.432100"); + assert_eq!(t.format("%.3f,%.6f,%.9f").unwrap().to_string(), ".432,.432100,.432100000"); let t = NaiveTime::from_hms_milli_opt(3, 5, 7, 210).unwrap(); - assert_eq!(t.format("%S,%f,%.f").to_string(), "07,210000000,.210"); - assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".210,.210000,.210000000"); + assert_eq!(t.format("%S,%f,%.f").unwrap().to_string(), "07,210000000,.210"); + assert_eq!(t.format("%.3f,%.6f,%.9f").unwrap().to_string(), ".210,.210000,.210000000"); let t = NaiveTime::from_hms_opt(3, 5, 7).unwrap(); - assert_eq!(t.format("%S,%f,%.f").to_string(), "07,000000000,"); - assert_eq!(t.format("%.3f,%.6f,%.9f").to_string(), ".000,.000000,.000000000"); + assert_eq!(t.format("%S,%f,%.f").unwrap().to_string(), "07,000000000,"); + assert_eq!(t.format("%.3f,%.6f,%.9f").unwrap().to_string(), ".000,.000000,.000000000"); // corner cases - assert_eq!(NaiveTime::from_hms_opt(13, 57, 9).unwrap().format("%r").to_string(), "01:57:09 PM"); assert_eq!( - NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap().format("%X").to_string(), + NaiveTime::from_hms_opt(13, 57, 9).unwrap().format("%r").unwrap().to_string(), + "01:57:09 PM" + ); + assert_eq!( + NaiveTime::from_hms_milli_opt(23, 59, 59, 1_000).unwrap().format("%X").unwrap().to_string(), "23:59:60" ); } diff --git a/src/offset/mod.rs b/src/offset/mod.rs index 09d0714e98..87d1e56802 100644 --- a/src/offset/mod.rs +++ b/src/offset/mod.rs @@ -435,7 +435,7 @@ pub trait TimeZone: Sized + Clone { /// parsed [`FixedOffset`]. fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult> { let mut parsed = Parsed::new(); - parse(&mut parsed, s, StrftimeItems::new(fmt))?; + parse(&mut parsed, s, StrftimeItems::new(fmt)?)?; parsed.to_datetime_with_timezone(self) } diff --git a/tests/dateutils.rs b/tests/dateutils.rs index aabab29a78..a9b2d566e2 100644 --- a/tests/dateutils.rs +++ b/tests/dateutils.rs @@ -110,7 +110,7 @@ fn verify_against_date_command_format_local(path: &'static str, dt: NaiveDateTim let ldt = Local .from_local_datetime(&date.and_hms_opt(dt.hour(), dt.minute(), dt.second()).unwrap()) .unwrap(); - let formated_date = format!("{}\n", ldt.format(required_format)); + let formated_date = format!("{}\n", ldt.format(required_format).unwrap()); assert_eq!(date_command_str, formated_date); }