vibesql_types/temporal/
date.rs1use std::{cmp::Ordering, fmt, str::FromStr};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub struct Date {
11 pub year: i32,
12 pub month: u8, pub day: u8, }
15
16impl Date {
17 pub fn new(year: i32, month: u8, day: u8) -> Result<Self, String> {
19 if !(1..=12).contains(&month) {
20 return Err(format!("Invalid month: {}", month));
21 }
22 if !(1..=31).contains(&day) {
23 return Err(format!("Invalid day: {}", day));
24 }
25 Ok(Date { year, month, day })
26 }
27}
28
29impl FromStr for Date {
30 type Err = String;
31
32 fn from_str(s: &str) -> Result<Self, Self::Err> {
33 let parts: Vec<&str> = s.split('-').collect();
35 if parts.len() != 3 {
36 return Err(format!("Invalid date format: '{}' (expected YYYY-MM-DD)", s));
37 }
38
39 let year = parts[0].parse::<i32>().map_err(|_| format!("Invalid year: '{}'", parts[0]))?;
40 let month = parts[1].parse::<u8>().map_err(|_| format!("Invalid month: '{}'", parts[1]))?;
41 let day = parts[2].parse::<u8>().map_err(|_| format!("Invalid day: '{}'", parts[2]))?;
42
43 Date::new(year, month, day)
44 }
45}
46
47impl fmt::Display for Date {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day)
50 }
51}
52
53impl PartialOrd for Date {
54 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
55 Some(self.cmp(other))
56 }
57}
58
59impl Ord for Date {
60 fn cmp(&self, other: &Self) -> Ordering {
61 self.year
62 .cmp(&other.year)
63 .then_with(|| self.month.cmp(&other.month))
64 .then_with(|| self.day.cmp(&other.day))
65 }
66}