/rust/registry/src/index.crates.io-1949cf8c6b5b557f/asn1-rs-0.5.2/src/datetime.rs
Line | Count | Source |
1 | | use crate::{Result, Tag}; |
2 | | use alloc::format; |
3 | | use alloc::string::ToString; |
4 | | use core::fmt; |
5 | | #[cfg(feature = "datetime")] |
6 | | use time::OffsetDateTime; |
7 | | |
8 | | #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] |
9 | | pub enum ASN1TimeZone { |
10 | | /// No timezone provided |
11 | | Undefined, |
12 | | /// Coordinated universal time |
13 | | Z, |
14 | | /// Local zone, with offset to coordinated universal time |
15 | | /// |
16 | | /// `(offset_hour, offset_minute)` |
17 | | Offset(i8, i8), |
18 | | } |
19 | | |
20 | | #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] |
21 | | pub struct ASN1DateTime { |
22 | | pub year: u32, |
23 | | pub month: u8, |
24 | | pub day: u8, |
25 | | pub hour: u8, |
26 | | pub minute: u8, |
27 | | pub second: u8, |
28 | | pub millisecond: Option<u16>, |
29 | | pub tz: ASN1TimeZone, |
30 | | } |
31 | | |
32 | | impl ASN1DateTime { |
33 | | #[allow(clippy::too_many_arguments)] |
34 | 14.1k | pub const fn new( |
35 | 14.1k | year: u32, |
36 | 14.1k | month: u8, |
37 | 14.1k | day: u8, |
38 | 14.1k | hour: u8, |
39 | 14.1k | minute: u8, |
40 | 14.1k | second: u8, |
41 | 14.1k | millisecond: Option<u16>, |
42 | 14.1k | tz: ASN1TimeZone, |
43 | 14.1k | ) -> Self { |
44 | 14.1k | ASN1DateTime { |
45 | 14.1k | year, |
46 | 14.1k | month, |
47 | 14.1k | day, |
48 | 14.1k | hour, |
49 | 14.1k | minute, |
50 | 14.1k | second, |
51 | 14.1k | millisecond, |
52 | 14.1k | tz, |
53 | 14.1k | } |
54 | 14.1k | } |
55 | | |
56 | | #[cfg(feature = "datetime")] |
57 | 6.86k | fn to_time_datetime( |
58 | 6.86k | &self, |
59 | 6.86k | ) -> core::result::Result<OffsetDateTime, time::error::ComponentRange> { |
60 | | use std::convert::TryFrom; |
61 | | use time::{Date, Month, PrimitiveDateTime, Time, UtcOffset}; |
62 | | |
63 | 6.86k | let month = Month::try_from(self.month)?; |
64 | 6.82k | let date = Date::from_calendar_date(self.year as i32, month, self.day)?; |
65 | 6.71k | let time = Time::from_hms_milli( |
66 | 6.71k | self.hour, |
67 | 6.71k | self.minute, |
68 | 6.71k | self.second, |
69 | 6.71k | self.millisecond.unwrap_or(0), |
70 | 0 | )?; |
71 | 6.71k | let primitive_date = PrimitiveDateTime::new(date, time); |
72 | 6.71k | let offset = match self.tz { |
73 | 0 | ASN1TimeZone::Offset(h, m) => UtcOffset::from_hms(h, m, 0)?, |
74 | 6.71k | ASN1TimeZone::Undefined | ASN1TimeZone::Z => UtcOffset::UTC, |
75 | | }; |
76 | 6.71k | Ok(primitive_date.assume_offset(offset)) |
77 | 6.86k | } |
78 | | |
79 | | #[cfg(feature = "datetime")] |
80 | 6.86k | pub fn to_datetime(&self) -> Result<OffsetDateTime> { |
81 | | use crate::Error; |
82 | | |
83 | 6.86k | self.to_time_datetime().map_err(|_| Error::InvalidDateTime) |
84 | 6.86k | } |
85 | | } |
86 | | |
87 | | impl fmt::Display for ASN1DateTime { |
88 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
89 | 0 | let fractional = match self.millisecond { |
90 | 0 | None => "".to_string(), |
91 | 0 | Some(v) => format!(".{}", v), |
92 | | }; |
93 | 0 | write!( |
94 | 0 | f, |
95 | 0 | "{:04}{:02}{:02}{:02}{:02}{:02}{}Z", |
96 | | self.year, self.month, self.day, self.hour, self.minute, self.second, fractional, |
97 | | ) |
98 | 0 | } |
99 | | } |
100 | | |
101 | | /// Decode 2-digit decimal value |
102 | 161k | pub(crate) fn decode_decimal(tag: Tag, hi: u8, lo: u8) -> Result<u8> { |
103 | 161k | if (b'0'..=b'9').contains(&hi) && (b'0'..=b'9').contains(&lo) { |
104 | 154k | Ok((hi - b'0') * 10 + (lo - b'0')) |
105 | | } else { |
106 | 6.60k | Err(tag.invalid_value("expected digit")) |
107 | | } |
108 | 161k | } |