Version 12 of Splitting an amount in parts

Updated 2007-08-18 18:43:29 by MJ

MJ - A frequent question on the Tcl Chat is how to split the number of seconds in the number of days, minutes etc. The following proc provides this and allows you to specifiy the divisors of the different units, making it very flexible. The largest unit should not have a divider, this indicates that this unit should not be split any further (see examples below) The lead and inter parameters indicate whether amounts that are 0 should be displayed.

For example the following {a x b y c z d} would translate to: A d is z c's which are y b's consisting of x a's.

Note that this only works for integer amounts and dividers.

 proc split_amount {amount dividers {lead 0} {inter 1}} {
   set result {}
   foreach {unit divider} $dividers {
       if {!$lead && $amount==0} break;
       if {$divider eq {}} {
              set result "$amount$unit $result"
              break
       } 
       if {$inter || !($amount%$divider == 0)} {
          set result "[expr {$amount % $divider}]$unit $result"
       }
       set amount [expr {$amount/$divider}]
   }
   return $result
 }

Example usage:

 % split_amount [clock seconds] {s 60 m 60 h 24 d 365 y}
 37y 238d 13h 2m 59s    
 % split_amount [clock seconds] {{ seconds} 60 { minutes and} 60 { hours,} 24 { days,} 365 { years,}}
 37 years, 238 days, 13 hours, 4 minutes and 7 seconds
 % split_amount 2234141 {{ gram} 1000 { kilogram and} 1000 { tonne,}}
 2 tonne, 234 kilogram and 141 gram
 % split_amount 1200 {s 60 m 60 h 24 d 365 y}
 20m 0s 
 % split_amount 1200 {s 60 m 60 h 24 d 365 y} 1 1
 0y 0d 0h 20m 0s 
 % split_amount 1200 {s 60 m 60 h 24 d 365 y} 1 0
 0y 20m 
 % split_amount 1200 {s 60 m 60 h 24 d 365 y} 0 0
 20m