1#[allow(unused_imports)]
15#[cfg(feature = "_float_f64")]
16use crate::ExtFloat;
17#[cfg(feature = "alloc")]
18use crate::{format, String};
19#[cfg(feature = "_str_u8")]
20use crate::{format_buf, Ascii, StringU8};
21use crate::{NoTime, TimeSplit, TimeSplitHourNano};
22
23pub struct Timecode;
36
37impl Timecode {
38 #[must_use]
46 #[cfg(any(feature = "std", feature = "_float_f64"))]
47 #[cfg_attr(feature = "nightly_doc", doc(cfg(any(feature = "std", feature = "_float_f64"))))]
48 pub fn split_secs_f64(seconds: f64) -> TimeSplitHourNano<u32, u8, u8, u16, NoTime, NoTime> {
49 let ms = (seconds.fract() * 1000.) as u16;
50 let mut ts = seconds.trunc() as u64;
51 let h = (ts / 3600) as u32;
52 ts %= 3600;
53 let m = (ts / 60) as u8;
54 let s = (ts % 60) as u8;
55 TimeSplit::new_hour_nano(h, m, s, ms, (), ())
56 }
57
58 #[must_use]
64 pub const fn split_nanos_u64(
65 nanos: u64,
66 ) -> TimeSplitHourNano<NoTime, NoTime, u32, u16, u16, u16> {
67 let (us_tmp, ns) = (nanos / 1000, (nanos % 1000) as u16);
68 let (ms_tmp, us) = (us_tmp / 1000, (us_tmp % 1000) as u16);
69 let (s, ms) = ((ms_tmp / 1000) as u32, (ms_tmp % 1000) as u16);
70 TimeSplit::new_hour_nano((), (), s, ms, us, ns)
71 }
72
73 #[must_use]
79 pub const fn split_nanos_u32(
80 nanos: u32,
81 ) -> TimeSplitHourNano<NoTime, NoTime, u8, u16, u16, u16> {
82 let (us_tmp, ns) = (nanos / 1000, (nanos % 1000) as u16);
83 let (ms_tmp, us) = (us_tmp / 1000, (us_tmp % 1000) as u16);
84 let (s, ms) = ((ms_tmp / 1000) as u8, (ms_tmp % 1000) as u16);
85 TimeSplit::new_hour_nano((), (), s, ms, us, ns)
86 }
87
88 #[cfg(any(feature = "std", feature = "_float_f64"))]
97 #[cfg_attr(feature = "nightly_doc", doc(cfg(any(feature = "std", feature = "_float_f64"))))]
98 #[cfg(feature = "_str_u8")]
99 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "_str_u8")))]
100 pub fn secs_f64(seconds: f64) -> StringU8<12> {
101 let TimeSplitHourNano { h, m, s, ms, .. } = Self::split_secs_f64(seconds);
102 let m = Ascii(m as u32).digits_str(2);
103 let s = Ascii(s as u32).digits_str(2);
104 let ms = Ascii(ms as u32).digits_str(3);
105
106 let mut buf = [0; 12];
107 let mut buf_len = 12;
108
109 if h > 0 {
110 let h = Ascii(h.min(99)).digits_str(2);
111 let _str = format_buf![&mut buf, "{h}:{m}:{s}.{ms}"];
112 } else {
113 buf_len = 9;
114 let _str = format_buf![&mut buf, "{m}:{s}.{ms}"];
115 }
116
117 #[cfg(any(feature = "safe_time", not(feature = "unsafe_str")))]
118 return StringU8::<12>::from_bytes_nleft(buf, buf_len).unwrap();
119
120 #[cfg(all(not(feature = "safe_time"), feature = "unsafe_str"))]
121 unsafe {
123 StringU8::<12>::from_bytes_nleft_unchecked(buf, buf_len)
124 }
125 }
126
127 #[cfg(feature = "alloc")]
131 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
132 pub fn nanos_u64_alloc(ns: u64) -> String {
134 let (us, ns_rem) = (ns / 1_000, ns % 1_000);
135 let (ms, us_rem) = (us / 1_000, us % 1_000);
136 let (s, ms_rem) = (ms / 1_000, ms % 1_000);
137 let s = s.min(999);
138
139 if s > 0 {
140 format!["{s}s {ms_rem:03}ms {us_rem:03}µs {ns_rem:03}ns"]
141 } else if ms > 0 {
142 format!["{ms_rem}ms {us_rem:03}µs {ns_rem:03}ns"]
143 } else if us > 0 {
144 format!["{us_rem}µs {ns_rem:03}ns"]
145 } else {
146 format!["{ns_rem:03}ns"]
147 }
148 }
149
150 #[cfg(feature = "_str_u8")]
155 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "_str_u8")))]
156 pub fn nanos_u64(nanos: u64) -> StringU8<23> {
157 let TimeSplitHourNano { s, ms, us, ns, .. } = Self::split_nanos_u64(nanos);
158 let s_str = Ascii(s.min(999)).digits_str(3);
159 let ms_str = Ascii(ms as u32).digits_str(3);
160 let us_str = Ascii(us as u32).digits_str(3);
161 let ns_str = Ascii(ns as u32).digits_str(3);
162
163 let mut buf = [0; 23];
164 let mut buf_len = 23; if s > 0 {
167 let _ = format_buf![&mut buf, "{s_str}s {ms_str}ms {us_str}µs {ns_str}ns"];
168 } else if ms > 0 {
169 buf_len = 18; let _ = format_buf![&mut buf, "{ms_str}ms {us_str}µs {ns_str}ns"];
171 } else if us > 0 {
172 buf_len = 12; let _ = format_buf![&mut buf, "{us_str}µs {ns_str}ns"];
174 } else {
175 buf_len = 5; let _ = format_buf![&mut buf, "{ns_str}ns"];
177 }
178
179 #[cfg(any(feature = "safe_time", not(feature = "unsafe_str")))]
180 return StringU8::<23>::from_bytes_nleft(buf, buf_len).unwrap();
181
182 #[cfg(all(not(feature = "safe_time"), feature = "unsafe_str"))]
183 unsafe {
185 StringU8::<23>::from_bytes_nleft_unchecked(buf, buf_len)
186 }
187 }
188}
189
190#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 #[cfg(any(feature = "std", feature = "_float_f64"))]
196 fn timecode_split_secs_f64() {
197 let result = Timecode::split_secs_f64(3661.500);
198 assert_eq!(8, size_of_val(&result)); assert_eq!(result, TimeSplit::new_hour_nano(1, 1, 1, 500, (), ()));
200 }
201
202 #[test]
203 fn timecode_split_nanos_u64() {
204 let result = Timecode::split_nanos_u64(1_002_003_004);
205 assert_eq!(12, size_of_val(&result));
206 assert_eq!(result, TimeSplit::new_hour_nano((), (), 1, 2, 3, 4));
207 }
208
209 #[test]
210 fn timecode_split_nanos_u32() {
211 let result = Timecode::split_nanos_u32(1_002_003);
212 assert_eq!(8, size_of_val(&result));
213 assert_eq!(result, TimeSplit::new_hour_nano((), (), 0, 1, 2, 3));
214 }
215
216 #[test]
217 #[cfg(feature = "_str_u8")]
218 #[cfg(any(feature = "std", feature = "_float_f64"))]
219 fn timecode_secs_f64() {
220 let formatted = Timecode::secs_f64(3661.5);
221 assert_eq!(formatted, "01:01:01.500");
222 }
223
224 #[test]
225 #[cfg(feature = "alloc")]
226 fn timecode_nanos_u64_alloc() {
227 let formatted = Timecode::nanos_u64_alloc(1_002_003_004);
228 assert_eq!(formatted, "1s 002ms 003µs 004ns");
229 }
230
231 #[test]
232 #[cfg(feature = "_str_u8")]
233 fn timecode_nanos_u64() {
234 let formatted = Timecode::nanos_u64(1_002_003_004);
235 assert_eq!(formatted, "001s 002ms 003µs 004ns");
236 }
237}