use core::fmt;
use core::time::Duration;
use der::asn1::{GeneralizedTime, UtcTime};
use der::{Choice, DateTime, Sequence, ValueOrd};
#[cfg(feature = "std")]
use std::time::SystemTime;
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Choice, Copy, Clone, Debug, Eq, PartialEq, ValueOrd)]
pub enum Time {
#[asn1(type = "UTCTime")]
UtcTime(UtcTime),
#[asn1(type = "GeneralizedTime")]
GeneralTime(GeneralizedTime),
}
impl Time {
pub const INFINITY: Time =
Time::GeneralTime(GeneralizedTime::from_date_time(DateTime::INFINITY));
pub fn to_unix_duration(self) -> Duration {
match self {
Time::UtcTime(t) => t.to_unix_duration(),
Time::GeneralTime(t) => t.to_unix_duration(),
}
}
pub fn to_date_time(&self) -> DateTime {
match self {
Time::UtcTime(t) => t.to_date_time(),
Time::GeneralTime(t) => t.to_date_time(),
}
}
#[cfg(feature = "std")]
pub fn to_system_time(&self) -> SystemTime {
match self {
Time::UtcTime(t) => t.to_system_time(),
Time::GeneralTime(t) => t.to_system_time(),
}
}
#[cfg(feature = "builder")]
pub(crate) fn rfc5280_adjust_utc_time(&mut self) -> der::Result<()> {
if let Time::GeneralTime(t) = self {
let date = t.to_date_time();
if date.year() <= UtcTime::MAX_YEAR {
*self = Time::UtcTime(UtcTime::from_date_time(date)?);
}
}
Ok(())
}
}
impl fmt::Display for Time {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_date_time())
}
}
impl From<UtcTime> for Time {
fn from(time: UtcTime) -> Time {
Time::UtcTime(time)
}
}
impl From<GeneralizedTime> for Time {
fn from(time: GeneralizedTime) -> Time {
Time::GeneralTime(time)
}
}
#[cfg(feature = "std")]
impl From<Time> for SystemTime {
fn from(time: Time) -> SystemTime {
time.to_system_time()
}
}
#[cfg(feature = "std")]
impl From<&Time> for SystemTime {
fn from(time: &Time) -> SystemTime {
time.to_system_time()
}
}
#[cfg(feature = "std")]
impl TryFrom<SystemTime> for Time {
type Error = der::Error;
fn try_from(time: SystemTime) -> der::Result<Time> {
Ok(GeneralizedTime::try_from(time)?.into())
}
}
#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct Validity {
pub not_before: Time,
pub not_after: Time,
}
impl Validity {
#[cfg(feature = "std")]
pub fn from_now(duration: Duration) -> der::Result<Self> {
let now = SystemTime::now();
let then = now + duration;
Ok(Self {
not_before: Time::try_from(now)?,
not_after: Time::try_from(then)?,
})
}
}