use anyhow::*;
use chrono::TimeZone;
pub trait Git2TimeToChronoExt {
fn to_date_time(&self) -> anyhow::Result<chrono::DateTime<chrono::FixedOffset>>;
fn to_date_time_in<Tz: chrono::TimeZone>(
&self,
tz: &Tz,
) -> anyhow::Result<chrono::DateTime<Tz>>;
fn to_local_date_time(&self) -> anyhow::Result<chrono::DateTime<chrono::Local>>;
}
impl Git2TimeToChronoExt for git2::Time {
fn to_date_time(&self) -> anyhow::Result<chrono::DateTime<chrono::FixedOffset>> {
let tz = chrono::FixedOffset::east_opt(self.offset_minutes() * 60);
if tz.is_none() {
bail!("Invalid TimeZone {}", self.offset_minutes());
}
match tz.unwrap().timestamp_opt(self.seconds(), 0) {
chrono::MappedLocalTime::Single(datetime) => Ok(datetime),
chrono::MappedLocalTime::Ambiguous(_, latest) => Ok(latest),
chrono::MappedLocalTime::None => bail!(
"Time {} isn't mappable to {}",
self.seconds(),
self.offset_minutes()
),
}
}
fn to_date_time_in<Tz: chrono::TimeZone>(
&self,
tz: &Tz,
) -> anyhow::Result<chrono::DateTime<Tz>> {
self.to_date_time()
.map(|datetime| datetime.with_timezone(tz))
}
fn to_local_date_time(&self) -> anyhow::Result<chrono::DateTime<chrono::Local>> {
self.to_date_time_in(&chrono::Local)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn to_date_time_offset_invalid() {
let time = git2::Time::new(0, 100_000);
let datetime = time.to_date_time();
assert!(datetime.is_err());
assert_eq!(datetime.unwrap_err().to_string(), "Invalid TimeZone 100000");
}
}