AzLearn

تمرين إعادة البناء

Deadline Planner

أعد كتابة مخطط مواعيد يرتب المهام حسب عدد الأيام المتبقية.

rust ~22 دقيقة متوسط
أعد بناء الكود Rebuild

هذا هو الكود. اكتبه بنفسك.

الكود المرجعي
use std::cmp::Ordering;
use std::env;
use std::fs;
use std::io;
use std::time::{SystemTime, UNIX_EPOCH};

#[derive(Debug)]
struct Task {
    name: String,
    due: Date,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Date {
    year: i32,
    month: u32,
    day: u32,
}

fn main() -> io::Result<()> {
    let path = env::args()
        .nth(1)
        .unwrap_or_else(|| "deadlines.csv".to_string());
    let data = fs::read_to_string(path).unwrap_or_else(|_| sample_deadlines());
    let today = today_utc();
    let mut tasks = parse_tasks(&data);

    tasks.sort_by(|a, b| a.due.cmp(&b.due));

    for task in tasks {
        let days = days_between(today, task.due);
        println!("{}: {} days", task.name, days);
    }

    Ok(())
}

fn parse_tasks(data: &str) -> Vec<Task> {
    data.lines()
        .skip(1)
        .filter_map(|line| {
            let (name, date) = line.split_once(',')?;
            Some(Task {
                name: name.trim().to_string(),
                due: parse_date(date.trim())?,
            })
        })
        .collect()
}

fn parse_date(text: &str) -> Option<Date> {
    let mut parts = text.split('-');
    Some(Date {
        year: parts.next()?.parse().ok()?,
        month: parts.next()?.parse().ok()?,
        day: parts.next()?.parse().ok()?,
    })
}

fn today_utc() -> Date {
    let days = SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap_or_default()
        .as_secs() as i64
        / 86_400;

    date_from_days(days)
}

fn days_between(start: Date, end: Date) -> i64 {
    days_from_date(end) - days_from_date(start)
}

fn days_from_date(date: Date) -> i64 {
    let year = date.year - (date.month <= 2) as i32;
    let era = (if year >= 0 { year } else { year - 399 }) / 400;
    let year_of_era = year - era * 400;
    let month = date.month as i32;
    let day_of_year = (153 * (month + if month > 2 { -3 } else { 9 }) + 2) / 5 + date.day as i32 - 1;
    let day_of_era = year_of_era * 365 + year_of_era / 4 - year_of_era / 100 + day_of_year;

    (era * 146_097 + day_of_era - 719_468) as i64
}

fn date_from_days(days: i64) -> Date {
    let days = days + 719_468;
    let era = (if days >= 0 { days } else { days - 146_096 }) / 146_097;
    let day_of_era = days - era * 146_097;
    let year_of_era = (day_of_era - day_of_era / 1460 + day_of_era / 36_524 - day_of_era / 146_096) / 365;
    let mut year = year_of_era as i32 + era as i32 * 400;
    let day_of_year = day_of_era - (365 * year_of_era + year_of_era / 4 - year_of_era / 100);
    let month_piece = (5 * day_of_year + 2) / 153;
    let day = day_of_year - (153 * month_piece + 2) / 5 + 1;
    let month = month_piece + if month_piece < 10 { 3 } else { -9 };
    year += (month <= 2) as i32;

    Date {
        year,
        month: month as u32,
        day: day as u32,
    }
}

impl Ord for Date {
    fn cmp(&self, other: &Self) -> Ordering {
        (self.year, self.month, self.day).cmp(&(other.year, other.month, other.day))
    }
}

impl PartialOrd for Date {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

fn sample_deadlines() -> String {
    "name,due\nRenew license,2026-05-10\nQuarterly report,2026-04-30\nTeam review,2026-05-03\n".to_string()
}
اكتب هنا