tail-fin-common 0.7.5

Shared infrastructure for tail-fin: error types, page_fetch, cookies, CDP helpers
Documentation
/// Convert a Unix timestamp (f64) to a human-readable UTC string.
///
/// Format: "YYYY-MM-DD HH:MM:SS UTC"
/// No chrono dependency — manual calendar math.
pub fn unix_timestamp_to_string(ts: f64) -> String {
    let secs = ts as i64;
    if secs < 0 {
        return String::new();
    }

    let days = secs / 86400;
    let time_of_day = secs % 86400;
    let hours = time_of_day / 3600;
    let minutes = (time_of_day % 3600) / 60;
    let seconds = time_of_day % 60;

    // Civil date from days since epoch (1970-01-01)
    // Algorithm from http://howardhinnant.github.io/date_algorithms.html
    let z = days + 719468;
    let era = (if z >= 0 { z } else { z - 146096 }) / 146097;
    let doe = z - era * 146097;
    let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
    let y = yoe + era * 400;
    let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
    let mp = (5 * doy + 2) / 153;
    let d = doy - (153 * mp + 2) / 5 + 1;
    let m = if mp < 10 { mp + 3 } else { mp - 9 };
    let y = if m <= 2 { y + 1 } else { y };

    format!(
        "{:04}-{:02}-{:02} {:02}:{:02}:{:02} UTC",
        y, m, d, hours, minutes, seconds
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_unix_timestamp() {
        let s = unix_timestamp_to_string(1700000000.0);
        assert_eq!(s, "2023-11-14 22:13:20 UTC");
    }

    #[test]
    fn test_zero_timestamp() {
        let s = unix_timestamp_to_string(0.0);
        assert_eq!(s, "1970-01-01 00:00:00 UTC");
    }

    #[test]
    fn test_negative_timestamp() {
        let s = unix_timestamp_to_string(-1.0);
        assert_eq!(s, "");
    }

    #[test]
    fn test_known_date() {
        // 2024-01-01 00:00:00 UTC = 1704067200
        let s = unix_timestamp_to_string(1704067200.0);
        assert_eq!(s, "2024-01-01 00:00:00 UTC");
    }
}