package com.example.aiapp /** * A span of milliseconds, written the way somebody reads it. * * A tool's timeout arrives as `480000`, which nobody reads as eight minutes. The rule has two * halves, because a short span and a long one are read for different things. Under a minute the * question is "roughly how long", so only the largest unit is shown and a fraction carries the rest * -- `2.5s`. At a minute or more the question is "how long exactly", so every unit with something * in it is written out -- `5d 12h 4m`. Empty units are left out rather than written as zero. * * Sub-second precision is dropped past a minute: nothing that takes days is measured in * milliseconds. */ fun formatMillis(ms: Long): String { if (ms < 0) return "-" + formatMillis(-ms) if (ms < 1000) return "${ms}ms" if (ms < 60_000) { val tenths = (ms + 50) / 100 val whole = tenths / 10 val rest = tenths % 10 return if (rest == 0L) "${whole}s" else "$whole.${rest}s" } val seconds = ms / 1000 val parts = listOf( "d" to seconds / 86_400, "h" to seconds / 3600 % 24, "m" to seconds / 60 % 60, "s" to seconds % 60, ) return parts.filter { it.second > 0 }.joinToString(" ") { "${it.second}${it.first}" } } /** [text] as a span when it is a whole number of milliseconds, and unchanged when it is not. */ fun formatMillisText(text: String): String = text.trim().toLongOrNull()?.let { formatMillis(it) } ?: text