chj_rustbin/time/
naive_date_time_without_year.rs1use std::convert::TryInto;
2use std::fmt::Display;
3
4use crate::parse::parse_error::{
5 Backing, IntoOwningBacking, NoContext, ParseContext, ParseError,
6 StringParseContext,
7};
8use crate::parse_error;
9use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike};
10
11#[derive(Debug, Clone)]
12pub struct NaiveDateTimeWithoutYear<C: ParseContext> {
13 pub context: C,
14 pub month: u8,
15 pub day: u8,
16 pub hour: u8,
17 pub minute: u8,
18 pub second: u8,
19}
20
21impl<'s, B: Backing> IntoOwningBacking<B::Owned>
30 for NaiveDateTimeWithoutYear<StringParseContext<&'s B>>
31where
32 &'s B: Backing,
33 B::Owned: Backing,
34{
35 type Owning = NaiveDateTimeWithoutYear<StringParseContext<B::Owned>>;
36
37 fn into_owning_backing(self) -> Self::Owning {
38 let Self {
39 context,
40 month,
41 day,
42 hour,
43 minute,
44 second,
45 } = self;
46 NaiveDateTimeWithoutYear {
47 context: context.into_owning_backing(),
48 month,
49 day,
50 hour,
51 minute,
52 second,
53 }
54 }
55}
56
57impl<C: ParseContext> NaiveDateTimeWithoutYear<C> {
58 pub fn with_year(self, year: i32) -> Result<NaiveDateTime, ParseError<C>> {
59 let NaiveDateTimeWithoutYear {
60 context,
61 month,
62 day,
63 hour,
64 minute,
65 second,
66 } = self;
67 (|| -> Result<NaiveDateTime, String> {
68 let nd = NaiveDate::from_ymd_opt(year, month.into(), day.into())
69 .ok_or_else(|| format!("invalid month/day in year {year}"))?;
70 let nt = NaiveTime::from_hms_opt(
71 hour.into(),
72 minute.into(),
73 second.into(),
74 )
75 .ok_or_else(|| {
76 format!("invalid hh:mm:ss numbers {hour}:{minute}:{second}")
77 })?;
78 Ok(NaiveDateTime::new(nd, nt))
79 })()
80 .map_err(|message| {
81 parse_error! {
82 message, context
83 }
84 })
85 }
86
87 pub fn into_naive_date_time(
88 self,
89 ) -> anyhow::Result<NaiveDateTime, ParseError<C>> {
90 Err(
91 parse_error! { message: "date is missing year".into(), context: self.context },
92 )
93 }
94
95 pub fn compare<C2: ParseContext>(
103 &self,
104 other: &NaiveDateTimeWithoutYear<C2>,
105 ) -> std::cmp::Ordering {
106 self.month.cmp(&other.month).then(
107 self.day.cmp(&other.day).then(
108 self.hour.cmp(&other.hour).then(
109 self.minute
110 .cmp(&other.minute)
111 .then(self.second.cmp(&other.second)),
112 ),
113 ),
114 )
115 }
116}
117
118impl<C: ParseContext> Display for NaiveDateTimeWithoutYear<C> {
119 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
120 let Self {
121 context: _,
122 month,
123 day,
124 hour,
125 minute,
126 second,
127 } = self;
128 f.write_fmt(format_args!(
129 "{month:02}-{day:02} {hour:02}:{minute:02}:{second:02}"
130 ))
131 }
132}
133
134impl From<&NaiveDateTime> for NaiveDateTimeWithoutYear<NoContext> {
136 fn from(value: &NaiveDateTime) -> Self {
137 Self {
138 context: NoContext,
139 month: value.month().try_into().expect("always fits"),
140 day: value.day().try_into().expect("always fits"),
141 hour: value.hour().try_into().expect("always fits"),
142 minute: value.minute().try_into().expect("always fits"),
143 second: value.second().try_into().expect("always fits"),
144 }
145 }
146}