Uma resposta inspirada na resposta de Lev Lukomsky tirando proveito de ActiveSupport :: Duration e lidando com milissegundos (útil para código de benchmark)
# duration in ms modulus number of ms in one second
milliseconds = duration.in_milliseconds % 1.second.in_milliseconds
# duration in seconds modulus number of seconds in one minute
seconds = (duration / 1.second) % (1.minute / 1.second)
# duration in minutes modulus number of minutes in one hour
minutes = (duration / 1.minute) % (1.hour / 1.minute)
# duration in hours modulus number of hours in one day
hours = (duration / 1.hour) % (1.day / 1.hour)
format("%02d:%02d:%02d:%03d", hours, minutes, seconds, milliseconds) #=> "12:05:00:001"
Claro que você pode estender isso facilmente com dias, meses, anos, etc, usando métodos ActiveSupport relacionados e repetindo a mesma estrutura.
Lembre-se de que para durações muito longas, isso pode ser impreciso, pois a duração de 1 mês não é fixada em número de dias, e não tenho certeza de como AS: Duration lida com isso.