ledger_models/fintekkers/wrappers/models/utils/
date.rs1use chrono::naive::NaiveDate;
2use chrono::{DateTime, Datelike, TimeZone, Utc};
3use crate::fintekkers::models::util::LocalDateProto;
4use std::fmt;
5use std::str::FromStr;
6use crate::fintekkers::wrappers::models::utils::errors::Error;
7
8static DATE_FORMAT: &str = "%Y-%m-%d";
9
10pub struct DateWrapper {
11 proto: LocalDateProto,
12}
13
14impl AsRef<LocalDateProto> for DateWrapper {
15 fn as_ref(&self) -> &LocalDateProto {
16 &self.proto
17 }
18}
19
20impl DateWrapper {
21 pub fn new(proto: LocalDateProto) -> Self {
22 DateWrapper { proto }
23 }
24}
25
26#[derive(Debug)]
27pub enum ParseError {
28 NotValidFormat,
29}
30
31impl FromStr for DateWrapper {
32 type Err = ParseError;
33
34 fn from_str(value: &str) -> Result<Self, Self::Err> {
36 let naive_date = NaiveDate::parse_from_str(value, DATE_FORMAT)
37 .unwrap_or_else(
38 |_| panic!("Date must be in the format of {}. Received {}", DATE_FORMAT, value));
39
40 Ok(DateWrapper {
41 proto: LocalDateProto {
42 year: naive_date.year() as u32,
43 month: naive_date.month(),
44 day: naive_date.day(),
45 },
46 })
47 }
48}
49
50impl TryFrom<DateWrapper> for DateTime<Utc> {
51 type Error = Error;
52
53 fn try_from(value: DateWrapper) -> Result<DateTime<Utc>, Error> {
54 let year = value.proto.year as i32;
55 let month = value.proto.month;
56 let day = value.proto.day;
57
58 Utc.with_ymd_and_hms(year, month, day, 0, 0, 0)
59 .single()
60 .ok_or(Error::DateConversion)
61 }
62}
63
64
65impl TryFrom<DateWrapper> for NaiveDate {
66 type Error = Error;
67
68 fn try_from(value: DateWrapper) -> Result<NaiveDate, Error> {
69 let year = value.proto.year as i32;
70 let month = value.proto.month;
71 let day = value.proto.day;
72
73 NaiveDate::from_ymd_opt(year, month, day).ok_or(Error::DateConversion)
74 }
75}
76
77impl From<DateWrapper> for LocalDateProto {
78 fn from(value: DateWrapper) -> Self {
79 value.proto
80 }
81}
82
83impl fmt::Display for DateWrapper {
84 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
85 let date_str = &format!(
86 "{}-{}-{}",
87 &self.proto.year, &self.proto.month, &self.proto.day
88 );
89 fmt.write_str(date_str).unwrap();
90 Ok(())
91 }
92}
93
94#[cfg(test)]
95mod test {
96 use super::*;
97
98 #[test]
99 fn test_proto_to_date() {
100 let input = DateWrapper {
101 proto: LocalDateProto {
102 year: 2020,
103 month: 12,
104 day: 31,
105 },
106 };
107
108 let output: NaiveDate = input.try_into().expect("failed to convert date");
109
110 assert_eq!(output.to_string(), "2020-12-31");
111 }
112
113 #[test]
114 fn test_date_from_string() {
115 let date = DateWrapper::from_str("2023-10-28").unwrap();
116 assert_eq!(date.proto.year, 2023);
117 }
118}