Move ExcludeNewer into its own type (#3041)

## Summary

This makes it easier to add (e.g.) JSON Schema derivations to the type.

If we have support for other dates in the future, we can generalize it
to a `UserDate` or similar.
This commit is contained in:
Charlie Marsh 2024-04-15 16:24:08 -04:00 committed by GitHub
parent 37a43f4b48
commit 1f626bfc73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 96 additions and 61 deletions

View file

@ -0,0 +1,53 @@
use std::str::FromStr;
use chrono::{DateTime, Days, NaiveDate, NaiveTime, Utc};
/// A timestamp that excludes files newer than it.
#[derive(Debug, Copy, Clone)]
pub struct ExcludeNewer(DateTime<Utc>);
impl ExcludeNewer {
/// Returns the timestamp in milliseconds.
pub fn timestamp_millis(&self) -> i64 {
self.0.timestamp_millis()
}
}
impl From<DateTime<Utc>> for ExcludeNewer {
fn from(datetime: DateTime<Utc>) -> Self {
Self(datetime)
}
}
impl FromStr for ExcludeNewer {
type Err = String;
/// Parse an [`ExcludeNewer`] from a string.
///
/// Accepts both RFC 3339 timestamps (e.g., `2006-12-02T02:07:43Z`) and UTC dates in the same
/// format (e.g., `2006-12-02`).
fn from_str(input: &str) -> Result<Self, Self::Err> {
let date_err = match NaiveDate::from_str(input) {
Ok(date) => {
// Midnight that day is 00:00:00 the next day
return Ok(Self(
(date + Days::new(1)).and_time(NaiveTime::MIN).and_utc(),
));
}
Err(err) => err,
};
let datetime_err = match DateTime::parse_from_rfc3339(input) {
Ok(datetime) => return Ok(Self(datetime.with_timezone(&Utc))),
Err(err) => err,
};
Err(format!(
"`{input}` is neither a valid date ({date_err}) nor a valid datetime ({datetime_err})"
))
}
}
impl std::fmt::Display for ExcludeNewer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}