How to calculate relative past time from a given date & time (e.g., 3 hours ago, 5 days ago, a month ago) in Rust

1 Answer

0 votes
use std::time::{SystemTime, Duration};

fn to_relative_past_time(past: SystemTime) -> String {
    let now = SystemTime::now();

    // Compute the time difference between `now` and `past`.
    // `duration_since()` returns a Result:
    //   - Ok(d):     `now` is after `past`, so the duration is valid.
    //   - Err(e):    `past` is actually in the future (or the clock moved backwards).
    //                In that case, `e.duration()` gives the absolute difference.
    // This ensures `delta` is always a positive Duration.
    let delta = match now.duration_since(past) {
        Ok(d) => d,
        Err(e) => e.duration(),
    };


    let seconds = delta.as_secs() as i64;
    let minutes = seconds / 60;
    let hours   = seconds / 3600;
    let days    = seconds / 86400;

    if seconds < 60 {
        return if seconds == 1 {
            "one second ago".to_string()
        } else {
            format!("{seconds} seconds ago")
        };
    }

    if seconds < 3600 {
        return if minutes == 1 {
            "a minute ago".to_string()
        } else {
            format!("{minutes} minutes ago")
        };
    }

    if seconds < 86400 {
        return if hours == 1 {
            "an hour ago".to_string()
        } else {
            format!("{hours} hours ago")
        };
    }

    if seconds < 2_592_000 { // 30 days
        return if days == 1 {
            "yesterday".to_string()
        } else {
            format!("{days} days ago")
        };
    }

    if seconds < 31_104_000 { // 12 months
        let months = days / 30;
        return if months <= 1 {
            "a month ago".to_string()
        } else {
            format!("{months} months ago")
        };
    }

    let years = days / 365;
    if years <= 1 {
        "a year ago".to_string()
    } else {
        format!("{years} years ago")
    }
}

fn test(hours_ago: f64) {
    let seconds_ago = (hours_ago * 3600.0).round() as u64;
    let past = SystemTime::now() - Duration::from_secs(seconds_ago);
    println!("{}", to_relative_past_time(past));
}

fn main() {
    test(0.01);    // 36 seconds ago
    test(0.2);     // 12 minutes ago
    test(3.0);     // 3 hours ago
    test(25.0);    // yesterday
    test(360.0);   // 15 days ago
    test(1239.0);  // a month ago
    test(2239.0);  // 3 months ago
    test(8760.0);  // a year ago
    test(98763.0); // 11 years ago
}


/*
run:

36 seconds ago
12 minutes ago
3 hours ago
yesterday
15 days ago
a month ago
3 months ago
a year ago
11 years ago

*/

 



answered Apr 13 by avibootz

Related questions

...