use chrono::{DateTime, FixedOffset, NaiveDateTime};
pub fn parse_timestamp<'a>(
time: &'a str,
custom_format: Option<&'a str>,
verbose: bool,
) -> Result<DateTime<FixedOffset>, &'a str> {
if let Some(date_format) = custom_format {
if let Ok(dt) = DateTime::parse_from_str(time, date_format) {
return Ok(dt);
}
if let Ok(dt) = NaiveDateTime::parse_from_str(time, date_format) {
return Ok(dt.and_utc().into());
}
}
if let Ok(dt) = DateTime::parse_from_rfc3339(time) {
return Ok(dt);
}
if let Ok(dt) = DateTime::parse_from_str(time, "%Y-%m-%dT%H:%M:%S%z") {
return Ok(dt);
}
if let Ok(dt) = DateTime::parse_from_rfc2822(time) {
return Ok(dt);
}
if let Ok(dt) = NaiveDateTime::parse_from_str(time, "%F %T%.f") {
return Ok(dt.and_utc().into());
}
if let Ok(dt) = NaiveDateTime::parse_from_str(time, "%FT%T%.f") {
return Ok(dt.and_utc().into());
}
if let Ok(dt) = NaiveDateTime::parse_from_str(time, "%FT%T") {
return Ok(dt.and_utc().into());
}
if let Ok(dt) = NaiveDateTime::parse_from_str(time, "%F %T UTC") {
return Ok(dt.and_utc().into());
}
if let Ok((dt, _)) = DateTime::parse_and_remainder(time, "%Z %b %d %Y %T GMT%z") {
return Ok(dt);
}
if verbose {
eprintln!("Failed to parse timestamp: {time}");
}
Err("Unexpected timestamp format")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rfc3339() {
let result = parse_timestamp("2023-10-06T09:30:21+00:00", None, false);
assert!(result.is_ok());
}
#[test]
fn test_naive_datetime() {
let result = parse_timestamp("2023-10-06 09:30:21.890421", None, false);
assert!(result.is_ok());
}
#[test]
fn test_naive_iso() {
let result = parse_timestamp("2023-10-06T09:30:21", None, false);
assert!(result.is_ok());
}
#[test]
fn test_custom_format() {
let result = parse_timestamp("06/10/2023 09:30:21", Some("%d/%m/%Y %H:%M:%S"), false);
assert!(result.is_ok());
}
#[test]
fn test_gmt_format() {
let result = parse_timestamp(
"Mon Apr 03 2023 12:08:18 GMT+0200 (MitteleuropƤische Sommerzeit)",
None,
false,
);
assert!(result.is_ok());
}
}