1use std::{fmt::Write, time::Duration};
2
3use nu_ansi_term::Style;
4
5use crate::styled;
6
7pub trait FormatTime {
29 fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result;
30 fn style_timestamp(
31 &self,
32 ansi: bool,
33 elapsed: Duration,
34 w: &mut impl std::fmt::Write,
35 ) -> std::fmt::Result;
36}
37
38impl FormatTime for () {
42 fn format_time(&self, _w: &mut impl std::fmt::Write) -> std::fmt::Result {
43 Ok(())
44 }
45 fn style_timestamp(
46 &self,
47 _ansi: bool,
48 _elapsed: Duration,
49 _w: &mut impl std::fmt::Write,
50 ) -> std::fmt::Result {
51 Ok(())
52 }
53}
54
55#[cfg(feature = "time")]
59#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
60pub struct UtcDateTime {
61 pub higher_precision: bool,
63}
64
65#[cfg(feature = "time")]
66impl FormatTime for UtcDateTime {
67 fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result {
68 let time = time::OffsetDateTime::now_utc();
69 write!(w, "{} {}", time.date(), time.time())
70 }
71
72 fn style_timestamp(
73 &self,
74 ansi: bool,
75 elapsed: Duration,
76 w: &mut impl std::fmt::Write,
77 ) -> std::fmt::Result {
78 style_timestamp(ansi, self.higher_precision, elapsed, w)
79 }
80}
81
82#[cfg(feature = "time")]
95#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
96pub struct LocalDateTime {
97 pub higher_precision: bool,
99}
100
101#[cfg(feature = "time")]
102impl FormatTime for LocalDateTime {
103 fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result {
104 let time = time::OffsetDateTime::now_local().expect("time offset cannot be determined");
105 write!(w, "{}", time)
106 }
107 fn style_timestamp(
108 &self,
109 ansi: bool,
110 elapsed: Duration,
111 w: &mut impl std::fmt::Write,
112 ) -> std::fmt::Result {
113 style_timestamp(ansi, self.higher_precision, elapsed, w)
114 }
115}
116
117#[derive(Debug, Clone, Copy, Eq, PartialEq)]
124pub struct Uptime {
125 epoch: std::time::Instant,
126 pub higher_precision: bool,
128}
129
130impl Default for Uptime {
131 fn default() -> Self {
132 Uptime::from(std::time::Instant::now())
133 }
134}
135
136impl From<std::time::Instant> for Uptime {
137 fn from(epoch: std::time::Instant) -> Self {
138 Uptime {
139 epoch,
140 higher_precision: false,
141 }
142 }
143}
144
145impl FormatTime for Uptime {
146 fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result {
147 let e = self.epoch.elapsed();
148 write!(w, "{:4}.{:06}s", e.as_secs(), e.subsec_micros())
149 }
150 fn style_timestamp(
151 &self,
152 ansi: bool,
153 elapsed: Duration,
154 w: &mut impl std::fmt::Write,
155 ) -> std::fmt::Result {
156 style_timestamp(ansi, self.higher_precision, elapsed, w)
157 }
158}
159
160fn style_timestamp(
161 ansi: bool,
162 higher_precision: bool,
163 elapsed: Duration,
164 w: &mut impl Write,
165) -> std::fmt::Result {
166 if higher_precision {
167 format_timestamp_with_decimals(ansi, elapsed, w)
168 } else {
169 format_timestamp(ansi, elapsed, w)
170 }
171}
172
173fn format_timestamp(ansi: bool, elapsed: Duration, w: &mut impl Write) -> std::fmt::Result {
174 let millis = elapsed.as_millis();
175 let secs = elapsed.as_secs();
176
177 let (n, unit) = if millis < 1000 {
182 (millis as _, "ms")
183 } else if secs < 60 {
184 (secs, "s ")
185 } else {
186 (secs / 60, "m ")
187 };
188
189 let timestamp = format!("{n:>3}");
190 write_style_timestamp(ansi, timestamp, unit, w)
191}
192
193fn format_timestamp_with_decimals(
194 ansi: bool,
195 elapsed: Duration,
196 w: &mut impl Write,
197) -> std::fmt::Result {
198 let secs = elapsed.as_secs_f64();
199
200 let (n, unit) = if secs < 0.001 {
205 (secs * 1_000_000.0, "μs")
206 } else if secs < 1.0 {
207 (secs * 1_000.0, "ms")
208 } else {
209 (secs, "s ")
210 };
211
212 let timestamp = format!(" {n:.2}");
213 write_style_timestamp(ansi, timestamp, unit, w)
214}
215
216fn write_style_timestamp(
217 ansi: bool,
218 timestamp: String,
219 unit: &str,
220 w: &mut impl Write,
221) -> std::fmt::Result {
222 write!(
223 w,
224 "{timestamp}{unit}",
225 timestamp = styled(ansi, Style::new().dimmed(), timestamp),
226 unit = styled(ansi, Style::new().dimmed(), unit),
227 )
228}
229
230impl<'a, F> FormatTime for &'a F
233where
234 F: FormatTime,
235{
236 fn format_time(&self, w: &mut impl std::fmt::Write) -> std::fmt::Result {
237 F::format_time(self, w)
238 }
239 fn style_timestamp(
240 &self,
241 ansi: bool,
242 duration: Duration,
243 w: &mut impl std::fmt::Write,
244 ) -> std::fmt::Result {
245 F::style_timestamp(self, ansi, duration, w)
246 }
247}
248
249