leenfetch_core/modules/linux/info/
uptime.rs

1use std::fmt::Write;
2use std::fs;
3
4use crate::modules::enums::UptimeShorthand;
5
6pub fn get_uptime(shorthand: UptimeShorthand) -> Option<String> {
7    let seconds = read_uptime_seconds()?;
8
9    Some(format_uptime(seconds, shorthand))
10}
11
12fn read_uptime_seconds() -> Option<u64> {
13    let contents = fs::read_to_string("/proc/uptime").ok()?;
14    let end = contents.find(' ')?; // Faster than split
15    let raw = contents.get(0..end)?;
16    let secs = raw.parse::<f64>().ok()?;
17    Some(secs.floor() as u64)
18}
19
20fn format_uptime(seconds: u64, shorthand: UptimeShorthand) -> String {
21    let days = seconds / 86400;
22    let hours = (seconds / 3600) % 24;
23    let minutes = (seconds / 60) % 60;
24
25    let mut buf = String::with_capacity(32);
26
27    match shorthand {
28        UptimeShorthand::Full => {
29            if days > 0 {
30                let _ = write!(buf, "{} day{}, ", days, if days != 1 { "s" } else { "" });
31            }
32            if hours > 0 {
33                let _ = write!(buf, "{} hour{}, ", hours, if hours != 1 { "s" } else { "" });
34            }
35            if minutes > 0 {
36                let _ = write!(
37                    buf,
38                    "{} minute{}",
39                    minutes,
40                    if minutes != 1 { "s" } else { "" }
41                );
42            }
43            if buf.is_empty() {
44                let _ = write!(buf, "{} seconds", seconds);
45            }
46        }
47        UptimeShorthand::Tiny => {
48            if days > 0 {
49                let _ = write!(buf, "{}d", days);
50            }
51            if hours > 0 {
52                if !buf.is_empty() {
53                    buf.push(' ');
54                }
55                let _ = write!(buf, "{}h", hours);
56            }
57            if minutes > 0 {
58                if !buf.is_empty() {
59                    buf.push(' ');
60                }
61                let _ = write!(buf, "{}m", minutes);
62            }
63            if buf.is_empty() {
64                let _ = write!(buf, "{}s", seconds);
65            }
66        }
67        UptimeShorthand::Seconds => {
68            let _ = write!(buf, "{}s", seconds);
69        }
70    }
71
72    buf.trim_end_matches([' ', ','].as_ref()).to_string()
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78
79    #[test]
80    fn formats_full_uptime() {
81        let result = format_uptime(86_400 + 3_600 + 120, UptimeShorthand::Full);
82        assert!(
83            result.contains("1 day") && result.contains("1 hour") && result.contains("2 minutes"),
84            "unexpected format: {result}"
85        );
86    }
87
88    #[test]
89    fn formats_tiny_uptime() {
90        let result = format_uptime(86_400 * 3 + 3_600 * 2 + 120, UptimeShorthand::Tiny);
91        assert!(result.contains("3d"));
92        assert!(result.contains("2h"));
93        assert!(result.contains("2m"));
94    }
95
96    #[test]
97    fn formats_seconds_uptime() {
98        let result = format_uptime(15, UptimeShorthand::Seconds);
99        assert_eq!(result, "15s");
100    }
101}