Skip to content

Commit

Permalink
fmt: add APIs for skipping weekday checking
Browse files Browse the repository at this point in the history
In the course of doing some experiments with using Jiff in `gix-date`, I
discovered that it currently relies on the fact that parsing RFC 2822
datetimes (and similar) does *not* do error checking if the date and
weekday are inconsistent. Prior to this PR, Jiff required that the
weekday and date were consistent. This PR adds APIs for skipping this
check.

For RFC 2822, this adds a new `relaxed_weekday` configuration on the
`DateTimeParser` builder.

For the strtime APIs, we achieve this by adding more granular accessors
and mutators on `BrokenDownTime`. So now folks can do this:

```
let tm = BrokenDownTime::parse("%a, %F", "Wed, 2024-07-27")?;
tm.set_weekday(None);
assert_eq!(tm.to_date().unwrap(), jiff::civil::date(2024, 7, 27));
```

Where the above succeeds even though 2024-07-27 was a Saturday. It's a
little verbose, but my hope is that this is a rarely needed thing.
  • Loading branch information
BurntSushi committed Jul 28, 2024
1 parent a995d01 commit 70c6ca0
Show file tree
Hide file tree
Showing 3 changed files with 631 additions and 31 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Enhancements:

* [PR #52](https://github.com/BurntSushi/jiff/pull/52):
Improve documentation for `Span` getter methods.
* [PR #53](https://github.com/BurntSushi/jiff/pull/53):
Add support for skipping weekday checking when parsing datetimes.

Bug fixes:

Expand Down
44 changes: 40 additions & 4 deletions src/fmt/rfc2822.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,50 @@ pub fn parse(string: &str) -> Result<Zoned, Error> {
/// ```
#[derive(Debug)]
pub struct DateTimeParser {
// The RFC 2822 parser has no configuration at present.
_private: (),
relaxed_weekday: bool,
}

impl DateTimeParser {
/// Create a new RFC 2822 datetime parser with the default configuration.
pub const fn new() -> DateTimeParser {
DateTimeParser { _private: () }
DateTimeParser { relaxed_weekday: false }
}

/// When enabled, parsing will permit the weekday to be inconsistent with
/// the date. When enabled, the weekday is still parsed and can result in
/// an error if it isn't _a_ valid weekday. Only the error checking for
/// whether it is _the_ correct weekday for the parsed date is disabled.
///
/// This is sometimes useful for interaction with systems that don't do
/// strict error checking.
///
/// This is disabled by default. And note that RFC 2822 compliance requires
/// that the weekday is consistent with the date.
///
/// # Example
///
/// ```
/// use jiff::{civil::date, fmt::rfc2822};
///
/// let string = "Sun, 13 Jul 2024 15:09:59 -0400";
/// // The above normally results in an error, since 2024-07-13 is a
/// // Saturday:
/// assert!(rfc2822::parse(string).is_err());
/// // But we can relax the error checking:
/// static P: rfc2822::DateTimeParser = rfc2822::DateTimeParser::new()
/// .relaxed_weekday(true);
/// assert_eq!(
/// P.parse_zoned(string)?,
/// date(2024, 7, 13).at(15, 9, 59, 0).intz("America/New_York")?,
/// );
/// // But note that something that isn't recognized as a valid weekday
/// // will still result in an error:
/// assert!(P.parse_zoned("Wat, 13 Jul 2024 15:09:59 -0400").is_err());
///
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub const fn relaxed_weekday(self, yes: bool) -> DateTimeParser {
DateTimeParser { relaxed_weekday: yes, ..self }
}

/// Parse a datetime string into a [`Zoned`] value.
Expand Down Expand Up @@ -427,7 +463,7 @@ impl DateTimeParser {
);
let dt = DateTime::from_parts(date, time);
if let Some(wd) = wd {
if wd != dt.weekday() {
if !self.relaxed_weekday && wd != dt.weekday() {
return Err(err!(
"found parsed weekday of {parsed}, \
but parsed datetime of {dt} has weekday \
Expand Down
Loading

0 comments on commit 70c6ca0

Please sign in to comment.