use crate::git::GitRepo;
use chrono::{DateTime, NaiveDate, TimeZone, Utc};
use regex::Regex;
use std::path::Path;
use std::sync::LazyLock;
static DATE_PREFIX_REGEX: LazyLock<Regex> =
LazyLock::new(|| Regex::new(r"^(\d{4}-\d{2}-\d{2})-").unwrap());
pub fn extract_date(path: &Path, git_repo: Option<&GitRepo>) -> Option<DateTime<Utc>> {
if let Some(date) = extract_date_from_filename(path) {
return Some(date);
}
if let Some(repo) = git_repo {
if let Some(date) = repo.last_modified(path) {
return Some(date);
}
}
extract_date_from_mtime(path)
}
fn extract_date_from_filename(path: &Path) -> Option<DateTime<Utc>> {
let filename = path.file_name()?.to_str()?;
if let Some(captures) = DATE_PREFIX_REGEX.captures(filename) {
let date_str = captures.get(1)?.as_str();
if let Ok(date) = NaiveDate::parse_from_str(date_str, "%Y-%m-%d") {
return Some(Utc.from_utc_datetime(&date.and_hms_opt(0, 0, 0)?));
}
}
None
}
fn extract_date_from_mtime(path: &Path) -> Option<DateTime<Utc>> {
let metadata = std::fs::metadata(path).ok()?;
let modified = metadata.modified().ok()?;
Some(DateTime::from(modified))
}
pub fn strip_date_prefix(filename: &str) -> &str {
if let Some(captures) = DATE_PREFIX_REGEX.captures(filename) {
let full_match = captures.get(0).unwrap();
&filename[full_match.end()..]
} else {
filename
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extract_date_from_filename() {
let path = Path::new("2024-01-15-my-post.md");
let date = extract_date_from_filename(path).unwrap();
assert_eq!(date.format("%Y-%m-%d").to_string(), "2024-01-15");
}
#[test]
fn test_extract_date_no_prefix() {
let path = Path::new("my-post.md");
assert!(extract_date_from_filename(path).is_none());
}
#[test]
fn test_strip_date_prefix() {
assert_eq!(strip_date_prefix("2024-01-15-my-post.md"), "my-post.md");
assert_eq!(strip_date_prefix("my-post.md"), "my-post.md");
}
}