Skip to main content

flow_server/
helpers.rs

1use std::time::Duration;
2
3/// Format a `Duration` as ISO 8601 timestamp
4#[allow(clippy::cast_possible_wrap)]
5pub fn format_system_time(duration: Duration) -> String {
6    let secs = duration.as_secs();
7    let millis = duration.subsec_millis();
8
9    // Simple ISO 8601 formatting without chrono dependency
10    let days_since_epoch = secs / 86400;
11    let time_of_day = secs % 86400;
12    let hours = time_of_day / 3600;
13    let minutes = (time_of_day % 3600) / 60;
14    let seconds = time_of_day % 60;
15
16    // Calculate date from days since epoch (1970-01-01)
17    let (year, month, day) = days_to_date(days_since_epoch as i64);
18
19    format!(
20        "{year:04}-{month:02}-{day:02}T{hours:02}:{minutes:02}:{seconds:02}.{millis:03}Z"
21    )
22}
23
24/// Convert days since epoch to (year, month, day)
25/// Algorithm from <http://howardhinnant.github.io/date_algorithms.html>
26#[allow(
27    clippy::cast_possible_wrap,
28    clippy::cast_sign_loss,
29    clippy::cast_possible_truncation,
30    clippy::missing_const_for_fn
31)]
32pub fn days_to_date(mut days: i64) -> (i64, u32, u32) {
33    days += 719_468;
34    let era = if days >= 0 { days } else { days - 146_096 } / 146_097;
35    let doe = (days - era * 146_097) as u32;
36    let yoe = (doe - doe / 1460 + doe / 36_524 - doe / 146_096) / 365;
37    #[allow(clippy::cast_lossless)]
38    let year = yoe as i64 + era * 400;
39    let day_of_year = doe - (365 * yoe + yoe / 4 - yoe / 100);
40    let mp = (5 * day_of_year + 2) / 153;
41    let day = day_of_year - (153 * mp + 2) / 5 + 1;
42    let month = if mp < 10 { mp + 3 } else { mp - 9 };
43    let year = if month <= 2 { year + 1 } else { year };
44    (year, month, day)
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn test_format_system_time() {
53        // Test epoch (1970-01-01 00:00:00)
54        let duration = Duration::from_secs(0);
55        assert_eq!(format_system_time(duration), "1970-01-01T00:00:00.000Z");
56
57        // Test a known timestamp (2024-01-01 12:00:00)
58        let duration = Duration::from_secs(1704110400);
59        assert_eq!(format_system_time(duration), "2024-01-01T12:00:00.000Z");
60    }
61
62    #[test]
63    fn test_days_to_date() {
64        // Epoch
65        assert_eq!(days_to_date(0), (1970, 1, 1));
66
67        // Known dates
68        assert_eq!(days_to_date(365), (1971, 1, 1));
69        assert_eq!(days_to_date(19723), (2024, 1, 1));
70    }
71}