pub fn parse_timezone_offset(tz: &str) -> crate::errors::GitResult { use crate::errors::GitError; if tz.len() != 5 { return Err(GitError::ParseError(format!( "invalid timezone format: {tz}" ))); } let sign: i32 = if tz.starts_with('+') { 1 } else if tz.starts_with('-') { -1 } else { return Err(GitError::ParseError(format!( "invalid timezone sign: {tz}" ))); }; let hours: i32 = tz[1..3].parse().map_err(|_| { GitError::ParseError(format!("invalid timezone hours: {tz}")) })?; let minutes: i32 = tz[3..5].parse().map_err(|_| { GitError::ParseError(format!("invalid timezone minutes: {tz}")) })?; Ok(sign * (hours * 60 + minutes)) } pub fn parse_iso_timezone(iso_date: &str) -> crate::errors::GitResult { let tz_part = iso_date.rsplit_once(' ').map(|(_, tz)| tz).ok_or_else(|| { crate::errors::GitError::ParseError(format!( "ISO date missing timezone: {iso_date}" )) })?; parse_timezone_offset(tz_part) } pub fn format_git_timestamp(secs: i64, offset_minutes: i32) -> String { let sign = if offset_minutes >= 0 { '+' } else { '-' }; let abs_offset = offset_minutes.abs(); let hours = abs_offset / 60; let mins = abs_offset % 60; format!("{} {}{:02}{:02}", secs, sign, hours, mins) }