/*
Compare two dates in Rust
-------------------------
Rust’s standard library does not include a built‑in date type, so this program
implements a small, safe date parser and comparator using a custom struct.
Concepts:
- Parsing dates safely (YYYY‑MM‑DD)
- Representing dates with a struct
- Comparing dates lexicographically (year → month → day)
- Handling invalid formats
- Edge‑case testing
Architecture notes:
- A dedicated function handles parsing.
- Another function performs comparison.
- Main runs multiple predefined test cases.
- No external dependencies; only standard library.
Performance notes:
- Comparisons are O(1).
- Parsing is fast and predictable.
- Memory usage is minimal.
Pitfalls:
- Invalid date strings must be handled.
- Comparing raw strings is unsafe; always convert to a structured type.
- No timezone logic here; this is pure date comparison.
*/
#[derive(Debug)]
struct Date {
year: i32,
month: u32,
day: u32,
}
/*
Safely parse a date string in the format YYYY-MM-DD.
Error handling:
- Returns Result<Date, &'static str>
- Ensures month/day ranges are valid (basic checks)
*/
fn parse_date(s: &str) -> Result<Date, &'static str> {
let parts: Vec<&str> = s.split('-').collect();
if parts.len() != 3 {
return Err("invalid date format");
}
let year = parts[0].parse::<i32>().map_err(|_| "invalid date format")?;
let month = parts[1].parse::<u32>().map_err(|_| "invalid date format")?;
let day = parts[2].parse::<u32>().map_err(|_| "invalid date format")?;
if month < 1 || month > 12 {
return Err("invalid date format");
}
if day < 1 || day > 31 {
return Err("invalid date format");
}
Ok(Date { year, month, day })
}
/*
Compare two Date objects.
Returns:
- "earlier"
- "later"
- "equal"
*/
fn compare_dates(a: &Date, b: &Date) -> &'static str {
if a.year < b.year { return "earlier"; }
if a.year > b.year { return "later"; }
if a.month < b.month { return "earlier"; }
if a.month > b.month { return "later"; }
if a.day < b.day { return "earlier"; }
if a.day > b.day { return "later"; }
"equal"
}
/*
Run a single test case:
- Parse both dates
- Handle invalid input
- Compare if valid
*/
fn run_test_case(d1: &str, d2: &str) {
let a = parse_date(d1);
let b = parse_date(d2);
match (a, b) {
(Ok(da), Ok(db)) => {
println!("Compare '{}' vs '{}' → {}", d1, d2, compare_dates(&da, &db));
}
_ => {
println!("Compare '{}' vs '{}' → invalid date format", d1, d2);
}
}
}
/*
Main test suite:
- Multiple test cases
- Includes edge cases
- Prints results cleanly
*/
fn main() {
println!("Date comparison tests:\n");
let tests = [
["2024-01-01", "2024-01-02"], // earlier
["2024-01-02", "2024-01-01"], // later
["2024-01-01", "2024-01-01"], // equal
["1999-12-31", "2000-01-01"], // millennium boundary
["2024-02-29", "2024-03-01"], // leap year (not validated strictly)
["2024-02-29", "2023-02-28"], // leap vs non-leap
["2024-13-01", "2024-01-01"], // invalid month
["2024-00-10", "2024-01-01"], // invalid month
["2024-01-32", "2024-01-01"], // invalid day
["abcd-ef-gh", "2024-01-01"], // invalid format
["2024-01-01", "abcd-ef-gh"], // invalid format
];
for t in tests {
run_test_case(t[0], t[1]);
}
}
/*
run:
Date comparison tests:
Compare '2024-01-01' vs '2024-01-02' → earlier
Compare '2024-01-02' vs '2024-01-01' → later
Compare '2024-01-01' vs '2024-01-01' → equal
Compare '1999-12-31' vs '2000-01-01' → earlier
Compare '2024-02-29' vs '2024-03-01' → earlier
Compare '2024-02-29' vs '2023-02-28' → later
Compare '2024-13-01' vs '2024-01-01' → invalid date format
Compare '2024-00-10' vs '2024-01-01' → invalid date format
Compare '2024-01-32' vs '2024-01-01' → invalid date format
Compare 'abcd-ef-gh' vs '2024-01-01' → invalid date format
Compare '2024-01-01' vs 'abcd-ef-gh' → invalid date format
*/