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




#lang racket/base
(require racket/string
         racket/list)
 
(define (seconds->compound-durations s)
  (define-values (w d.h.m.s)
    (for/fold ((prev-q s) (rs (list))) ((Q (in-list (list 60 60 24 7))))
      (define-values (q r) (quotient/remainder prev-q Q))
      (values q (cons r rs))))
  (cons w d.h.m.s))
 
(define (maybe-suffix v n)
  (and (positive? v)
       (format "~a ~a" v n)))
 
(define (seconds->compound-duration-string s)
  (string-join (filter-map maybe-suffix
                           (seconds->compound-durations s)
                           '("wk" "d" "hr" "min" "sec"))
               ", "))
 
(module+ test
  (require rackunit)
  (check-equal? (seconds->compound-durations 7259)    (list 0 0  2  0 59))
  (check-equal? (seconds->compound-durations 86400)   (list 0 1  0  0  0))
  (check-equal? (seconds->compound-durations 6000000) (list 9 6 10 40  0))
 
  (check-equal? (seconds->compound-duration-string 7259)    "2 hr, 59 sec")
  (check-equal? (seconds->compound-duration-string 86400)   "1 d")
  (check-equal? (seconds->compound-duration-string 6000000) "9 wk, 6 d, 10 hr, 40 min"))
 
;; Tim Brown 2015-07-21