Skip to content

Commit

Permalink
Make datetime.format() return Result
Browse files Browse the repository at this point in the history
  • Loading branch information
jaggededgedjustice committed Dec 9, 2022
1 parent 74ca661 commit a8fe63d
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 88 deletions.
15 changes: 12 additions & 3 deletions src/datetime/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -753,14 +753,18 @@ where
/// use chrono::prelude::*;
///
/// let date_time: DateTime<Utc> = 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<StrftimeItems<'a>> {
self.format_with_items(StrftimeItems::new(fmt))
pub fn format<'a>(&self, fmt: &'a str) -> Result<DelayedFormat<StrftimeItems<'a>>, String> {
let items = StrftimeItems::new(fmt);
match items.into_iter().all(|i| i != Item::Error) {
true => Ok(self.format_with_items(items)),
false => Err(format!("Invalid format string: {}", fmt)),
}
}

/// Formats the combined date and time with the specified formatting items and locale.
Expand Down Expand Up @@ -1331,3 +1335,8 @@ fn test_decodable_json<FUtc, FFixed, FLocal, E>(
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());
}
13 changes: 8 additions & 5 deletions src/datetime/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,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]
Expand Down Expand Up @@ -579,25 +582,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));
Expand Down
2 changes: 1 addition & 1 deletion src/format/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")?;
Expand Down
2 changes: 1 addition & 1 deletion src/format/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,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));
Expand Down
157 changes: 80 additions & 77 deletions src/format/strftime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ static D_T_FMT: &[Item<'static>] = &[
static T_FMT: &[Item<'static>] = &[num0!(Hour), lit!(":"), num0!(Minute), lit!(":"), num0!(Second)];

/// Parsing iterator for `strftime`-like format strings.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Copy)]
pub struct StrftimeItems<'a> {
/// Remaining portion of the string.
remainder: &'a str,
Expand Down Expand Up @@ -570,69 +570,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(), "28");
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(), "28");
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!(
Expand All @@ -649,15 +652,15 @@ 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(), "%");
}

#[cfg(feature = "unstable-locales")]
Expand All @@ -672,27 +675,27 @@ 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"
);
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
//! ```
//!
Expand Down

0 comments on commit a8fe63d

Please sign in to comment.