Coverage Report

Created: 2025-12-31 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}