@@ -218,6 +218,113 @@ Duration Duration::from_half_sanitized(i64 seconds, i32 extra_seconds, u32 nanos
218218 return Duration { seconds + extra_seconds, nanoseconds };
219219}
220220
221+ ErrorOr<void > Formatter<Duration>::format(FormatBuilder& builder, Duration value)
222+ {
223+ if (value.m_nanoseconds >= 1'000'000'000 )
224+ return builder.put_string (" { INVALID }" sv);
225+
226+ auto align = m_align;
227+ if (align == FormatBuilder::Align::Default)
228+ align = FormatBuilder::Align::Right;
229+
230+ auto sign_mode = m_sign_mode;
231+ if (sign_mode == FormatBuilder::SignMode::Default)
232+ sign_mode = FormatBuilder::SignMode::OnlyIfNeeded;
233+
234+ auto align_width = m_width.value_or (0 );
235+
236+ u8 base;
237+ bool upper_case = false ;
238+ if (m_mode == Mode::Default || m_mode == Mode::FixedPoint) {
239+ base = 10 ;
240+ } else if (m_mode == Mode::Hexfloat) {
241+ base = 16 ;
242+ } else if (m_mode == Mode::HexfloatUppercase) {
243+ base = 16 ;
244+ upper_case = true ;
245+ } else if (m_mode == Mode::Binary) {
246+ base = 2 ;
247+ } else if (m_mode == Mode::BinaryUppercase) {
248+ base = 2 ;
249+ upper_case = true ;
250+ } else if (m_mode == Mode::Octal) {
251+ base = 8 ;
252+ } else {
253+ VERIFY_NOT_REACHED ();
254+ }
255+
256+ auto is_negative = value.m_seconds < 0 ;
257+ auto seconds = is_negative ? 0 - static_cast <u64 >(value.m_seconds ) : static_cast <u64 >(value.m_seconds );
258+ auto nanoseconds = value.m_nanoseconds ;
259+ if (is_negative && nanoseconds > 0 ) {
260+ seconds--;
261+ nanoseconds = 1'000'000'000 - nanoseconds;
262+ }
263+
264+ VERIFY (nanoseconds < 1'000'000'000 );
265+
266+ size_t integer_width = 1 ;
267+ if (seconds != 0 ) {
268+ auto remaining_seconds = seconds / 10 ;
269+ while (remaining_seconds != 0 ) {
270+ remaining_seconds /= base;
271+ integer_width++;
272+ }
273+ }
274+ if (sign_mode != FormatBuilder::SignMode::OnlyIfNeeded)
275+ integer_width++;
276+
277+ constexpr size_t nanoseconds_length = 9 ;
278+ size_t precision = 0 ;
279+ u64 nanoseconds_to_precision = nanoseconds;
280+ if (m_precision.has_value ()) {
281+ precision = min (m_precision.value (), nanoseconds_length);
282+ for (size_t i = nanoseconds_length; i > precision; i--)
283+ nanoseconds_to_precision /= base;
284+ } else if (nanoseconds_to_precision != 0 ) {
285+ auto trailing_zeroes = 0 ;
286+ while ((nanoseconds_to_precision % base) == 0 ) {
287+ nanoseconds_to_precision /= base;
288+ trailing_zeroes++;
289+ }
290+ precision = nanoseconds_length - trailing_zeroes;
291+ }
292+
293+ size_t non_integer_width = 0 ;
294+ if (precision != 0 )
295+ non_integer_width = precision + 1 ;
296+ if (m_alternative_form)
297+ non_integer_width++;
298+
299+ auto total_width = integer_width + non_integer_width;
300+
301+ size_t integer_align_width = 0 ;
302+ if (align == FormatBuilder::Align::Right)
303+ integer_align_width = Checked<size_t >::saturating_sub (align_width, non_integer_width);
304+ else if (align == FormatBuilder::Align::Center)
305+ integer_align_width = integer_width + Checked<size_t >::saturating_sub (align_width, total_width) / 2 ;
306+ TRY (builder.put_u64 (seconds, base, false , upper_case, m_zero_pad, m_use_separator, FormatBuilder::Align::Right, integer_align_width, m_fill, m_sign_mode, is_negative));
307+
308+ if (nanoseconds_to_precision != 0 ) {
309+ TRY (builder.builder ().try_append (' .' ));
310+ TRY (builder.put_u64 (nanoseconds_to_precision, base, false , upper_case, true , m_use_separator, FormatBuilder::Align::Right, precision));
311+ if (m_precision.has_value () && m_precision.value () > nanoseconds_length) {
312+ auto zeroes = m_precision.value () - nanoseconds_length;
313+ TRY (builder.put_padding (' 0' , zeroes));
314+ }
315+ }
316+
317+ if (m_alternative_form)
318+ TRY (builder.builder ().try_append (' s' ));
319+
320+ if (align_width > 0 && align != FormatBuilder::Align::Right) {
321+ auto padding_width = Checked<size_t >::saturating_sub (align_width, max (integer_width, integer_align_width) + non_integer_width);
322+ TRY (builder.builder ().try_append_repeated (m_fill, padding_width));
323+ }
324+
325+ return {};
326+ }
327+
221328namespace {
222329
223330#if defined(AK_OS_WINDOWS)
0 commit comments