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