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