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




:- use_module(library(clpfd)).
 
% helper to perform the operation with just a number.
compound_time(N) :-
    times(N, R),
    format('~p: ', N),
    write_times(R).
 
% write out the results in the 'special' format.
write_times([[Tt, Val]|T]) :-
    dif(T, []),
    format('~w ~w, ', [Val, Tt]),
    write_times(T).
write_times([[Tt, Val]|[]]) :-
    format('~w ~w~n', [Val, Tt]).
 
 
% this predicate is the main predicate, it takes either N
% or a list of split values to get N, or both.
times(N, R) :-
    findall(T, time_type(T,_), TTs),
    times(TTs, N, R).
 
% do the split, if there is a 1 or greater add to a list of results.
times([], _, []).
times([Tt|T], N, Rest) :-
    time_type(Tt, Div),
    Val #= N // Div,
    Val #< 1,
    times(T, N, Rest).
times([Tt|T], N, [[Tt,Val]|Rest]) :-
    time_type(Tt, Div),
    Val #= N // Div,
    Val #>= 1,
    Rem #= N mod Div,
    times(T, Rem, Rest).
 
 
% specifify the different time split types
time_type(wk, 60 * 60 * 24 * 7).
time_type(d, 60 * 60 * 24).
time_type(hr, 60 * 60).
time_type(min, 60).
time_type(sec, 1).