Task

Write a function or program which:

   takes a positive integer representing a duration in seconds as input (e.g., 100), and
   returns a string which shows the same duration decomposed into:
   weeks,
   days, 
   hours, 
   minutes,   and 
   seconds.
This is detailed below (e.g., "2 hr, 59 sec").



Demonstrate that it passes the following three test-cases:

Test Cases


 input number

 output string


 7259

 2 hr, 59 sec


 86400

 1 d


 6000000

 9 wk, 6 d, 10 hr, 40 min

Details
The following five units should be used:



 unit

 suffix used in output

 conversion


 week

 wk

 1 week = 7 days


 day

 d

 1 day = 24 hours


 hour

 hr

 1 hour = 60 minutes


 minute

 min

 1 minute = 60 seconds


 second

 sec



However, only include quantities with non-zero values in the output (e.g., return "1 d" and not "0 wk, 1 d, 0 hr, 0 min, 0 sec").

Give larger units precedence over smaller ones as much as possible (e.g., return 2 min, 10 sec and not 1 min, 70 sec or 130 sec)

Mimic the formatting shown in the test-cases (quantities sorted from largest unit to smallest and separated by comma+space; value and unit of each quantity separated by space).




begin
    % record structure to hold a compound duration %
    record Duration ( integer weeks, days, hours, minutes, seconds );
 
    % returns seconds converted to a Duration %
    reference(Duration) procedure toDuration( integer value secs ) ;
    begin
        integer  time;
        reference(Duration) d;
        time := secs;
        d    := Duration( 0, 0, 0, 0, 0 );
        seconds(d) := time rem 60;
        time       := time div 60;
        minutes(d) := time rem 60;
        time       := time div 60;
        hours(d)   := time rem 24;
        time       := time div 24;
        days(d)    := time rem  7;
        time       := time div  7;
        weeks(d)   := time;
        d
    end toDuration ;
 
    % returns a readable form of the DURATION %
    string(80) procedure durationToString ( reference(Duration) value d ) ;
    begin
        % appends an element of the compound duration to text %
        procedure add ( integer   value componentValue
                      ; string(6) value componentName
                      ; integer   value nameLength
                      ) ;
        begin
            string(9) vStr;
            integer   v, vPos;
            if needSeparator then begin
                % must separate this component from the previous %
                text( textPos // 2 ) := ", ";
                textPos:= textPos + 2
             end if_needSepartator ;
             % add the value %
             % construct a string representaton of the value with the digits reversed %
             % as this routine isn't called if componentValue is 0 or -ve, we don't need to handle %
             % the componentVaue <= 0 case %
             v    := componentValue;
             vStr := "";
             vPos := 0;
             while v > 0 do begin
                 vStr( vPos // 1 ) := code( decode( "0" ) + ( v rem 10 ) );
                 vPos              := vPos + 1;
                 v                 := v div 10
             end while_v_gt_0 ;
             % add the digits in the correct order %
             while vPos > 0 do begin
                 vPos                 := vPos - 1;
                 text( textPos // 1 ) := vStr( vPos // 1 );
                 textPos              := textPos + 1
             end while_vPos_gt_0 ;
             % add the component name %
             text( textPos // 6 ) := componentName;
             textPos := textPos + nameLength;
             % if there is another component, we'll need a separator %
             needSeparator := true
        end add ;
 
        string(80) text;
        logical    needSeparator;
        integer    textPos;
        textPos       := 0;
        text          := "";
        needSeparator := false;
        if   weeks(d) not = 0 then add(   weeks(d), " wk",  3 );
        if    days(d) not = 0 then add(    days(d), " d",   2 );
        if   hours(d) not = 0 then add(   hours(d), " hr",  3 );
        if minutes(d) not = 0 then add( minutes(d), " min", 4 );
        if seconds(d) not = 0 then add( seconds(d), " sec", 4 );
        if text = "" then begin
            % duration is 0 %
            text := "0 sec"
        end if_text_is_blank ;
        text
   end % durationToString % ;
 
    % test cases %
    write( durationToString( toDuration(    7259 ) ) );
    write( durationToString( toDuration(   86400 ) ) );
    write( durationToString( toDuration( 6000000 ) ) )
end.