Repository: sharkdp/fd
File: src/filter/time.rs (Rust)

Code before:
use chrono::{DateTime, Local, NaiveDate, NaiveDateTime};
use jiff::{Span, Zoned};

use std::time::SystemTime;

/// Filter based on time ranges.
#[derive(Debug, PartialEq, Eq)]
pub enum TimeFilter {
    Before(SystemTime),
    After(SystemTime),
}

impl TimeFilter {
    fn from_str(ref_time: &SystemTime, s: &str) -> Option<SystemTime> {
        s.parse::<Span>()
            .and_then(|duration| {
                Zoned::try_from(*ref_time).and_then(|zoned| zoned.checked_sub(duration))
            })
            .map(SystemTime::from)
            .ok()
            .or_else(|| {
                DateTime::parse_from_rfc3339(s)
                    .map(|dt| dt.into())
                    .ok()
                    .or_else(|| {
                        NaiveDate::parse_from_str(s, "%F")
                            .ok()?
                            .and_hms_opt(0, 0, 0)?
                            .and_local_timezone(Local)
                            .latest()
                    })
                    .or_else(|| {
                        NaiveDateTime::parse_from_str(s, "%F %T")
                            .ok()?
                            .and_local_timezone(Local)
                            .latest()
                    })
                    .or_else(|| {
                        let timestamp_secs = s.strip_prefix('@')?.parse().ok()?;
                        DateTime::from_timestamp(timestamp_secs, 0).map(Into::into)
                    })
                    .map(|dt| dt.into())
            })
    }

    pub fn before(ref_time: &SystemTime, s: &str) -> Option<TimeFilter> {
        TimeFilter::from_str(ref_time, s).map(TimeFilter::Before)

Review comment (suggestion):
Could we replace the `chrono` with `jiff` as well? 

If you don't want to do that as part of this PR, I could try doing that when I have some time.

Code after:
use jiff::{civil::DateTime, tz::TimeZone, Span, Timestamp, Zoned};

use std::time::SystemTime;

/// Filter based on time ranges.
#[derive(Debug, PartialEq, Eq)]
pub enum TimeFilter {
    Before(SystemTime),
    After(SystemTime),
}

impl TimeFilter {
    fn from_str(ref_time: &SystemTime, s: &str) -> Option<SystemTime> {
        s.parse::<Span>()
            .and_then(|duration| {
                Zoned::try_from(*ref_time).and_then(|zdt| zdt.checked_sub(duration))
            })
            .ok()
            .or_else(|| {
                let local_tz = TimeZone::system();
                s.parse::<Timestamp>()
                    .map(|ts| ts.to_zoned(TimeZone::UTC))
                    .ok()
                    .or_else(|| {
                        s.parse::<DateTime>()
                            .map(|dt| local_tz.to_ambiguous_zoned(dt))
                            .and_then(|zdt| zdt.later())
                            .ok()
                    })
                    .or_else(|| {
                        let timestamp_secs = s.strip_prefix('@')?.parse().ok()?;
                        Timestamp::from_second(timestamp_secs)
                            .map(|ts| ts.to_zoned(TimeZone::UTC))
                            .ok()
                    })
            })
            .map(SystemTime::from)
    }

    pub fn before(ref_time: &SystemTime, s: &str) -> Option<TimeFilter> {
        TimeFilter::from_str(ref_time, s).map(TimeFilter::Before)
    }

    pub fn after(ref_time: &SystemTime, s: &str) -> Option<TimeFilter> {
        TimeFilter::from_str(ref_time, s).map(TimeFilter::After)
    }