1use serde::{de, ser, Deserializer, Serializer};
2use std::fmt;
3
4pub trait TimeRepr
5where
6 Self: Sized,
7{
8 fn serialize<S>(
9 date: &Date<Self>,
10 serializer: S,
11 ) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
12 where
13 S: ser::Serializer;
14
15 fn deserialize<'de, D>(deserializer: D) -> Result<Date<Self>, <D as de::Deserializer<'de>>::Error>
16 where
17 D: de::Deserializer<'de>;
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct Date<TR: TimeRepr> {
23 year: u16,
24 month: u8,
25 day: u8,
26 hour: u8,
27 minute: u8,
28 second: u8,
29 _pd: std::marker::PhantomData<TR>,
30}
31
32impl<TR: TimeRepr> Date<TR> {
33 pub unsafe fn new_unchecked(year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> Date<TR> {
39 Self {
40 year,
41 month,
42 day,
43 hour,
44 minute,
45 second,
46 _pd: std::marker::PhantomData,
47 }
48 }
49
50 pub fn new(year: u16, month: u8, day: u8, hour: u8, minute: u8, second: u8) -> Option<Date<TR>> {
51 if (1..=12).contains(&month) && (1..=32).contains(&day) && hour < 24 && minute < 60 && second < 60 {
52 Some(Self {
53 year,
54 month,
55 day,
56 hour,
57 minute,
58 second,
59 _pd: std::marker::PhantomData,
60 })
61 } else {
62 None
63 }
64 }
65
66 pub fn year(&self) -> u16 {
67 self.year
68 }
69
70 pub fn month(&self) -> u8 {
71 self.month
72 }
73
74 pub fn day(&self) -> u8 {
75 self.day
76 }
77
78 pub fn hour(&self) -> u8 {
79 self.hour
80 }
81
82 pub fn minute(&self) -> u8 {
83 self.minute
84 }
85
86 pub fn second(&self) -> u8 {
87 self.second
88 }
89}
90
91impl<TR: TimeRepr> ser::Serialize for Date<TR> {
92 fn serialize<S>(&self, serializer: S) -> Result<<S as ser::Serializer>::Ok, <S as ser::Serializer>::Error>
93 where
94 S: ser::Serializer,
95 {
96 TR::serialize(self, serializer)
97 }
98}
99
100impl<'de, TR: TimeRepr> de::Deserialize<'de> for Date<TR> {
101 fn deserialize<D>(deserializer: D) -> Result<Self, <D as de::Deserializer<'de>>::Error>
102 where
103 D: de::Deserializer<'de>,
104 {
105 TR::deserialize(deserializer)
106 }
107}
108
109trait DateDigitReader {
110 fn read_digit(&self, idx: usize) -> u8;
111
112 #[inline]
113 fn read_and_merge_with_next(&self, idx: usize) -> u8 {
114 self.read_digit(idx) * 10 + self.read_digit(idx + 1)
115 }
116}
117
118impl DateDigitReader for [u8] {
119 #[inline]
120 fn read_digit(&self, idx: usize) -> u8 {
121 self[idx] & 0x0F
122 }
123}
124
125#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
126pub struct UTCTimeRepr;
127pub type UTCTime = Date<UTCTimeRepr>;
128
129impl TimeRepr for UTCTimeRepr {
130 fn serialize<S>(date: &Date<UTCTimeRepr>, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
131 where
132 S: ser::Serializer,
133 {
134 let mut encoded = [
135 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
136 ];
137
138 let year = if date.year() >= 2000 {
139 date.year() - 2000
140 } else {
141 date.year() - 1900
142 };
143
144 encoded[0] |= (year / 10) as u8;
145 encoded[1] |= (year % 10) as u8;
146 encoded[2] |= date.month() / 10;
147 encoded[3] |= date.month() % 10;
148 encoded[4] |= date.day() / 10;
149 encoded[5] |= date.day() % 10;
150 encoded[6] |= date.hour() / 10;
151 encoded[7] |= date.hour() % 10;
152 encoded[8] |= date.minute() / 10;
153 encoded[9] |= date.minute() % 10;
154 encoded[10] |= date.second() / 10;
155 encoded[11] |= date.second() % 10;
156
157 serializer.serialize_bytes(&encoded)
158 }
159
160 fn deserialize<'de, D>(deserializer: D) -> Result<Date<UTCTimeRepr>, <D as Deserializer<'de>>::Error>
161 where
162 D: de::Deserializer<'de>,
163 {
164 struct Visitor;
165
166 impl<'de> de::Visitor<'de> for Visitor {
167 type Value = Date<UTCTimeRepr>;
168
169 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
170 formatter.write_str("a valid buffer representing an Asn1 UTCTime")
171 }
172
173 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
174 where
175 E: de::Error,
176 {
177 if v.len() != 13 {
178 return Err(E::invalid_value(
179 de::Unexpected::Other("unsupported date format"),
180 &"a valid buffer representing an Asn1 UTCTime (exactly 13 bytes required)",
181 ));
182 }
183
184 let yyyy = {
185 let yy = v.read_and_merge_with_next(0) as u16;
186 if yy >= 50 {
187 1900 + yy
188 } else {
189 2000 + yy
190 }
191 };
192 let month = v.read_and_merge_with_next(2);
193 let day = v.read_and_merge_with_next(4);
194 let hour = v.read_and_merge_with_next(6);
195 let minute = v.read_and_merge_with_next(8);
196 let second = v.read_and_merge_with_next(10);
197 let dt = Date::new(yyyy, month, day, hour, minute, second).ok_or_else(|| {
198 E::invalid_value(
199 de::Unexpected::Other("invalid parameters provided to Date constructor"),
200 &"valid parameters for Date",
201 )
202 })?;
203
204 Ok(dt)
205 }
206 }
207
208 deserializer.deserialize_bytes(Visitor)
209 }
210}
211
212#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
213pub struct GeneralizedTimeRepr;
214pub type GeneralizedTime = Date<GeneralizedTimeRepr>;
215
216impl TimeRepr for GeneralizedTimeRepr {
217 fn serialize<S>(
218 date: &Date<GeneralizedTimeRepr>,
219 serializer: S,
220 ) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
221 where
222 S: ser::Serializer,
223 {
224 let mut encoded = [
225 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A,
226 ];
227
228 encoded[0] |= (date.year() / 1000) as u8;
229 encoded[1] |= ((date.year() % 1000) / 100) as u8;
230 encoded[2] |= ((date.year() % 100) / 10) as u8;
231 encoded[3] |= (date.year() % 10) as u8;
232 encoded[4] |= date.month() / 10;
233 encoded[5] |= date.month() % 10;
234 encoded[6] |= date.day() / 10;
235 encoded[7] |= date.day() % 10;
236 encoded[8] |= date.hour() / 10;
237 encoded[9] |= date.hour() % 10;
238 encoded[10] |= date.minute() / 10;
239 encoded[11] |= date.minute() % 10;
240 encoded[12] |= date.second() / 10;
241 encoded[13] |= date.second() % 10;
242
243 serializer.serialize_bytes(&encoded)
244 }
245
246 fn deserialize<'de, D>(deserializer: D) -> Result<Date<GeneralizedTimeRepr>, <D as Deserializer<'de>>::Error>
247 where
248 D: de::Deserializer<'de>,
249 {
250 struct Visitor;
251
252 impl<'de> de::Visitor<'de> for Visitor {
253 type Value = Date<GeneralizedTimeRepr>;
254
255 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
256 formatter.write_str("a valid buffer representing an Asn1 GeneralizedTime")
257 }
258
259 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
260 where
261 E: de::Error,
262 {
263 if v.len() != 15 {
264 return Err(E::invalid_value(
265 de::Unexpected::Other("unsupported date format"),
266 &"a valid buffer representing an Asn1 GeneralizedTime (exactly 15 bytes required)",
267 ));
268 }
269
270 let yyyy = v.read_and_merge_with_next(0) as u16 * 100 + v.read_and_merge_with_next(2) as u16;
271 let month = v.read_and_merge_with_next(4);
272 let day = v.read_and_merge_with_next(6);
273 let hour = v.read_and_merge_with_next(8);
274 let minute = v.read_and_merge_with_next(10);
275 let second = v.read_and_merge_with_next(12);
276 let dt = Date::new(yyyy, month, day, hour, minute, second).ok_or_else(|| {
277 E::invalid_value(
278 de::Unexpected::Other("invalid parameters provided to Date constructor"),
279 &"valid parameters for Date",
280 )
281 })?;
282
283 Ok(dt)
284 }
285 }
286
287 deserializer.deserialize_bytes(Visitor)
288 }
289}
290
291#[cfg(feature = "time_conversion")]
292mod time_convert {
293 use super::*;
294 use time::{OffsetDateTime, PrimitiveDateTime};
295
296 impl<TR: TimeRepr> From<PrimitiveDateTime> for Date<TR> {
297 fn from(d: PrimitiveDateTime) -> Self {
298 Self::from(d.assume_utc())
299 }
300 }
301
302 impl<TR: TimeRepr> TryFrom<Date<TR>> for PrimitiveDateTime {
303 type Error = time::error::ComponentRange;
304
305 fn try_from(d: Date<TR>) -> Result<Self, Self::Error> {
306 let date = time::Date::from_calendar_date(i32::from(d.year), time::Month::try_from(d.month)?, d.day)?;
307 let time = time::Time::from_hms(d.hour, d.minute, d.second)?;
308 Ok(Self::new(date, time))
309 }
310 }
311
312 impl<TR: TimeRepr> From<OffsetDateTime> for Date<TR> {
313 fn from(d: OffsetDateTime) -> Self {
314 Self {
315 year: u16::try_from(d.year()).unwrap(),
316 month: u8::from(d.month()),
317 day: d.day(),
318 hour: d.hour(),
319 minute: d.minute(),
320 second: d.second(),
321 _pd: std::marker::PhantomData,
322 }
323 }
324 }
325
326 impl<TR: TimeRepr> TryFrom<Date<TR>> for OffsetDateTime {
327 type Error = time::error::ComponentRange;
328
329 fn try_from(d: Date<TR>) -> Result<Self, Self::Error> {
330 Ok(PrimitiveDateTime::try_from(d)?.assume_utc())
331 }
332 }
333}
334
335#[cfg(feature = "chrono_conversion")]
336mod chrono_convert {
337 use super::*;
338 use chrono::naive::NaiveDateTime;
339 use chrono::{DateTime, Datelike, NaiveDate, Timelike, Utc};
340
341 impl<TR: TimeRepr> From<NaiveDateTime> for Date<TR> {
342 fn from(d: NaiveDateTime) -> Self {
343 Self {
344 year: u16::try_from(d.year()).unwrap(),
345 month: u8::try_from(d.month()).unwrap(),
346 day: u8::try_from(d.day()).unwrap(),
347 hour: u8::try_from(d.hour()).unwrap(),
348 minute: u8::try_from(d.minute()).unwrap(),
349 second: u8::try_from(d.second()).unwrap(),
350 _pd: std::marker::PhantomData,
351 }
352 }
353 }
354
355 impl<TR: TimeRepr> From<Date<TR>> for NaiveDateTime {
356 fn from(date: Date<TR>) -> Self {
357 NaiveDate::from_ymd_opt(i32::from(date.year), u32::from(date.month), u32::from(date.day))
358 .unwrap()
359 .and_hms_opt(u32::from(date.hour), u32::from(date.minute), u32::from(date.second))
360 .unwrap()
361 }
362 }
363
364 impl<TR: TimeRepr> From<DateTime<Utc>> for Date<TR> {
365 fn from(d: DateTime<Utc>) -> Self {
366 Self {
367 year: u16::try_from(d.year()).unwrap(),
368 month: u8::try_from(d.month()).unwrap(),
369 day: u8::try_from(d.day()).unwrap(),
370 hour: u8::try_from(d.hour()).unwrap(),
371 minute: u8::try_from(d.minute()).unwrap(),
372 second: u8::try_from(d.second()).unwrap(),
373 _pd: std::marker::PhantomData,
374 }
375 }
376 }
377
378 impl<TR: TimeRepr> From<Date<TR>> for DateTime<Utc> {
379 fn from(date: Date<TR>) -> Self {
380 DateTime::<Utc>::from_naive_utc_and_offset(date.into(), Utc)
381 }
382 }
383}