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).




with Ada.Text_IO;
 
procedure Convert is
 
   type Time is range 0 .. 10_000*356*20*60*60; -- at most 10_000 years
   subtype Valid_Duration is Time range 1  .. 10_000*356*20*60*60;
   type Units is (WK, D, HR, MIN, SEC);
 
   package IO renames Ada.Text_IO;
 
   Divide_By: constant array(Units) of Time := (1_000*53, 7, 24, 60, 60);
   Split: array(Units) of Time;
   No_Comma: Units;
   X: Time;
 
   Test_Cases: array(Positive range <>) of Valid_Duration :=
     (6, 60, 3659, 7_259, 86_400, 6_000_000, 6_001_200, 6_001_230, 600_000_000);
 
begin
  for Test_Case of Test_Cases loop
     IO.Put(Time'Image(Test_Case) & " SECONDS =");
     X := Test_Case;
 
     -- split X up into weeks, days, ..., seconds
     No_Comma := Units'First;
     for Unit in reverse Units loop -- Unit = SEC, ..., WK (in that order)
	Split(Unit) := X mod Divide_By(Unit);
	X := X / Divide_By(Unit);
	if Unit > No_Comma and Split(Unit)>0 then
	   No_Comma := Unit;
	end if;
     end loop;
 
     -- ouput weeks, days, ..., seconds
     for Unit in Units loop -- Unit =  WK, .., SEC (in that order)
	if Split(Unit) > 0 then
	   IO.Put(Time'Image(Split(Unit)) & " " & Units'Image(Unit) & 
		    (if No_Comma > Unit then "," else ""));
	end if;
     end loop;
 
  IO.New_Line;
  end loop;
end Convert;