Search code examples
rustrust-chrono

How can I test if a chrono::DateTime<Local> falls within certain times of day?


I want to compare the current local time to a constant time range, but my current solution seems more difficult than I'd expect.

I can construct a chrono::DateTime<Local> with Local::now(). I can then laboriously find out if now lies in a particular time range like so:

let current_hour = now.hour();
let current_minute = now.minute();

// see if `now` lies between 06:00 and 23:00
current_hour >= 6 && current_hour < 23

// note the inelegance of the syntax and the potential for fencepost errors

If I want to check the range from 06:12–23:15, the problem becomes much worse because I have to check if the hour is equal to 6 and then if the minutes are greater than 12 and then check — zzzzz...

That's boring. I can try string representations with parse_from_rfc2822, but then I have to first emit the current date and then edit in the time of day and then check for parsing errors and now I'm sleeping again.

I imagine I'm just reading the chrono documentation wrong. If I were to implement the library, I would try to build a TimeOfDay<Local> datatype which implements Ord, thereby allowing idiomatic range checking. I figure it's already there somewhere and I'm just missing it.


Solution

  • DateTime objects have a function called time(), which returns a NaiveTime object representing the time of day. NaiveTime implements PartialOrd, and has a factory function from_hms(hour, min, sec). Using from_hms, you can create an upper bound and lower bound NaiveTime, and then compare using standard operators.

    let low = NaiveTime::from_hms(6, 12, 0);
    let high = NaiveTime::from_hms(23, 15, 0);
    let time_of_day = Local::now().time();
    
    if (time_of_day > low) && (time_of_day < high) {
        // do stuff...
    } else {
        // do something else...
    };
    

    Playground link for completeness.