Convert seconds to compound duration: Difference between revisions
→{{header|AppleScript}}: Simpler closures, updated primitives |
Langurmonkey (talk | contribs) |
||
(140 intermediate revisions by 52 users not shown) | |||
Line 1: | Line 1: | ||
{{task}} |
{{task}} |
||
[[Category:Date and time]] |
|||
;Task: |
;Task: |
||
Write a function or program which: |
Write a function or program which: |
||
* takes a positive integer representing a duration in seconds as input (e.g., <code>100</code>), and |
* takes a positive integer representing a duration in seconds as input (e.g., <code>100</code>), and |
||
* returns a string which shows the same duration decomposed into |
* returns a string which shows the same duration decomposed into: |
||
:::* weeks, |
|||
:::* days, |
|||
:::* hours, |
|||
:::* minutes, and |
|||
:::* seconds. |
|||
This is detailed below (e.g., "<code>2 hr, 59 sec</code>"). |
|||
<br> |
|||
Demonstrate that it passes the following three test-cases: |
Demonstrate that it passes the following three test-cases: |
||
<p style="font-size:115%; margin:1em 0 0.5em 0">'''''Test Cases'''''</p> |
<p style="font-size:115%; margin:1em 0 0.5em 0">'''''Test Cases'''''</p> |
||
{| class="wikitable" |
:::::{| class="wikitable" |
||
|- |
|- |
||
! input number |
! input number |
||
Line 28: | Line 36: | ||
<p style="font-size:115%; margin:1em 0 0.5em 0">'''''Details'''''</p> |
<p style="font-size:115%; margin:1em 0 0.5em 0">'''''Details'''''</p> |
||
The following five units should be used: |
|||
<ul> |
|||
:::::{| class="wikitable" |
|||
<li>The following five units should be used: |
|||
{| class="wikitable" |
|||
|- |
|- |
||
! unit |
! unit |
||
Line 50: | Line 57: | ||
| minute |
| minute |
||
| <code style="background:#eee">min</code> |
| <code style="background:#eee">min</code> |
||
| 1 |
| 1 minute = 60 seconds |
||
|- |
|- |
||
| second |
| second |
||
Line 56: | Line 63: | ||
| |
| |
||
|} |
|} |
||
</li> |
|||
However, '''only''' include quantities with non-zero values in the output (e.g., return "<code>1 d</code>" and not "<code>0 wk, 1 d, 0 hr, 0 min, 0 sec</code>"). |
|||
Give larger units precedence over smaller ones as much as possible (e.g., return <code>2 min, 10 sec</code> and not <code>1 min, 70 sec</code> or <code>130 sec</code>) |
|||
<li>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).</li> |
|||
</ul> |
|||
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). |
|||
<hr style="margin:1em 0;"/> |
<hr style="margin:1em 0;"/> |
||
<br><br> |
<br><br> |
||
=={{header|11l}}== |
|||
{{trans|Julia}} |
|||
<syntaxhighlight lang="11l">F duration(=sec) |
|||
[Int] t |
|||
L(dm) [60, 60, 24, 7] |
|||
Int m |
|||
(sec, m) = (sec I/ dm, sec % dm) |
|||
t.insert(0, m) |
|||
t.insert(0, sec) |
|||
R zip(t, [‘wk’, ‘d’, ‘hr’, ‘min’, ‘sec’]).filter(num_unit -> num_unit[0] > 0).map(num_unit -> num_unit[0]‘ ’num_unit[1]).join(‘, ’) |
|||
print(duration(7259)) |
|||
print(duration(86400)) |
|||
print(duration(6000000))</syntaxhighlight> |
|||
=={{header|Action!}}== |
|||
{{libheader|Action! Tool Kit}} |
|||
{{libheader|Action! Real Math}} |
|||
<syntaxhighlight lang="action!">INCLUDE "H6:REALMATH.ACT" |
|||
DEFINE PTR="CARD" |
|||
TYPE Time=[BYTE s,m,h,d,w] |
|||
CARD ARRAY units(5) |
|||
PROC Convert(REAL POINTER seconds Time POINTER t) |
|||
BYTE ARRAY b,duration=[60 60 24 7] |
|||
BYTE i |
|||
REAL r,n |
|||
b=t |
|||
FOR i=0 TO 3 |
|||
DO |
|||
IntToReal(duration(i),n) |
|||
RealMod(seconds,n,r) |
|||
b(i)=RealToInt(r) |
|||
RealDivInt(seconds,n,r) |
|||
RealAssign(r,seconds) |
|||
OD |
|||
b(4)=RealToInt(seconds) |
|||
RETURN |
|||
PROC PrintTime(Time POINTER t) |
|||
INT i |
|||
BYTE first,n |
|||
BYTE ARRAY b |
|||
b=t i=4 first=1 |
|||
WHILE i>=0 |
|||
DO |
|||
n=b(i) |
|||
IF n>0 THEN |
|||
IF first=0 THEN |
|||
Print(", ") |
|||
ELSE |
|||
first=0 |
|||
FI |
|||
PrintF("%B %S",n,units(i)) |
|||
FI |
|||
i==-1 |
|||
OD |
|||
RETURN |
|||
PROC Test(CHAR ARRAY s) |
|||
REAL seconds |
|||
Time t |
|||
ValR(s,seconds) |
|||
PrintR(seconds) Print(" -> ") |
|||
Convert(seconds,t) |
|||
PrintTime(t) PutE() |
|||
RETURN |
|||
PROC Main() |
|||
Put(125) PutE() ;clear the screen |
|||
MathInit() |
|||
units(0)="sec" units(1)="min" |
|||
units(2)="hr" units(3)="d" |
|||
units(4)="wk" |
|||
Test("7259") |
|||
Test("86400") |
|||
Test("6000000") |
|||
RETURN |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Convert_seconds_to_compound_duration.png Screenshot from Atari 8-bit computer] |
|||
<pre> |
|||
259 -> 2 hr, 59 sec |
|||
86400 -> 1 d |
|||
6000000 -> 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
< |
<syntaxhighlight lang="ada">with Ada.Text_IO; |
||
procedure Convert is |
procedure Convert is |
||
Line 112: | Line 207: | ||
IO.New_Line; |
IO.New_Line; |
||
end loop; |
end loop; |
||
end Convert;</ |
end Convert;</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 125: | Line 220: | ||
6001230 SECONDS = 9 WK, 6 D, 11 HR, 30 SEC |
6001230 SECONDS = 9 WK, 6 D, 11 HR, 30 SEC |
||
600000000 SECONDS = 992 WK, 10 HR, 40 MIN</pre> |
600000000 SECONDS = 992 WK, 10 HR, 40 MIN</pre> |
||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
||
< |
<syntaxhighlight lang="algol68"># MODE to hold the compound duration # |
||
MODE DURATION = STRUCT( INT weeks, days, hours, minutes, seconds ); |
MODE DURATION = STRUCT( INT weeks, days, hours, minutes, seconds ); |
||
Line 170: | Line 264: | ||
print( ( TOSTRING TODURATION 7259, newline ) ); |
print( ( TOSTRING TODURATION 7259, newline ) ); |
||
print( ( TOSTRING TODURATION 86400, newline ) ); |
print( ( TOSTRING TODURATION 86400, newline ) ); |
||
print( ( TOSTRING TODURATION 6000000, newline ) )</ |
print( ( TOSTRING TODURATION 6000000, newline ) )</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 178: | Line 272: | ||
</pre> |
</pre> |
||
=={{header| |
=={{header|ALGOL W}}== |
||
Based on Algol 68 but Algol W does not have dynamic string handling which makes this more complex. |
|||
<syntaxhighlight lang="algolw">begin |
|||
% record structure to hold a compound duration % |
|||
record Duration ( integer weeks, days, hours, minutes, seconds ); |
|||
% returns seconds converted to a Duration % |
|||
{{Trans|JavaScript}} |
|||
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 % |
|||
<lang AppleScript>on run |
|||
string(80) procedure durationToString ( reference(Duration) value d ) ; |
|||
begin |
|||
-- test :: Int -> String |
|||
% appends an element of the compound duration to text % |
|||
script test |
|||
procedure add ( integer value componentValue |
|||
on lambda(intSeconds) |
|||
; string(6) value componentName |
|||
; integer value nameLength |
|||
end lambda |
|||
) ; |
|||
end script |
|||
begin |
|||
string(9) vStr; |
|||
intercalate(linefeed, ¬ |
|||
integer v, vPos; |
|||
if needSeparator then begin |
|||
% must separate this component from the previous % |
|||
end run |
|||
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; |
|||
-- DURATION STRINGS |
|||
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 % |
|||
-- angloDuration :: Int -> String |
|||
write( durationToString( toDuration( 7259 ) ) ); |
|||
on angloDuration(intSeconds) |
|||
write( durationToString( toDuration( 86400 ) ) ); |
|||
-- weekParts Int -> [Int] |
|||
write( durationToString( toDuration( 6000000 ) ) ) |
|||
script mf |
|||
end.</syntaxhighlight> |
|||
on weekParts(intSeconds) |
|||
{{out}} |
|||
unitParts(intSeconds, [missing value, 7, 24, 60, 60]) |
|||
<pre> |
|||
end weekParts |
|||
2 hr, 59 sec |
|||
end script |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|APL}}== |
|||
{{works with|Dyalog APL}} |
|||
<syntaxhighlight lang="apl">duration←{ |
|||
names←'wk' 'd' 'hr' 'min' 'sec' |
|||
parts←0 7 24 60 60⊤⍵ |
|||
fmt←⍕¨(parts≠0)/parts,¨names |
|||
¯2↓∊fmt,¨⊂', ' |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> duration 7259 |
|||
2 hr, 59 sec |
|||
duration 86400 |
|||
1 d |
|||
duration 6000000 |
|||
9 wk, 6 d, 10 hr, 40 min</pre> |
|||
=={{header|AppleScript}}== |
|||
===Functional=== |
|||
<syntaxhighlight lang="applescript"> |
|||
-------------------- COMPOUND DURATIONS ------------------ |
|||
-- weekParts Int -> [Int] |
|||
on weekParts(intSeconds) |
|||
unitParts(intSeconds, [missing value, 7, 24, 60, 60]) |
|||
end weekParts |
|||
-- localCompoundDuration :: Int -> String |
|||
on localCompoundDuration(localNames, intSeconds) |
|||
-- [String] -> (Int, String) -> [String] |
-- [String] -> (Int, String) -> [String] |
||
script formatted |
script formatted |
||
on |
on |λ|(lstPair, a) |
||
set q to item 1 of lstPair |
set q to item 1 of lstPair |
||
if q > 0 then |
if q > 0 then |
||
Line 216: | Line 407: | ||
a |
a |
||
end if |
end if |
||
end |
end |λ| |
||
end script |
end script |
||
intercalate(", ", ¬ |
intercalate(", ", ¬ |
||
foldr(formatted, [], ¬ |
foldr(formatted, [], ¬ |
||
zip(weekParts(intSeconds) |
zip(weekParts(intSeconds), localNames))) |
||
end localCompoundDuration |
|||
["wk", "d", "hr", "min", "sec"]))) |
|||
end angloDuration |
|||
-- INTEGER DECOMPOSITION |
------------------ INTEGER DECOMPOSITION ----------------- |
||
-- unitParts :: Int -> [maybe Int] -> [Int] |
-- unitParts :: Int -> [maybe Int] -> [Int] |
||
Line 232: | Line 421: | ||
-- partList :: Record -> Int -> Record |
-- partList :: Record -> Int -> Record |
||
script partList |
script partList |
||
on |
on |λ|(x, a) |
||
set intRest to remaining of a |
set intRest to remaining of a |
||
Line 244: | Line 433: | ||
{remaining:(intRest - intMod) div d, parts:{intMod} & parts of a} |
{remaining:(intRest - intMod) div d, parts:{intMod} & parts of a} |
||
end |
end |λ| |
||
end script |
end script |
||
Line 251: | Line 440: | ||
end unitParts |
end unitParts |
||
--------------------------- TEST ------------------------- |
|||
on run |
|||
script angloNames |
|||
on |λ|(n) |
|||
(n as string) & " -> " & ¬ |
|||
localCompoundDuration(["wk", "d", "hr", "min", "sec"], n) |
|||
end |λ| |
|||
end script |
|||
unlines(map(angloNames, [7259, 86400, 6000000])) |
|||
end run |
|||
-- GENERIC FUNCTIONS |
-------------------- GENERIC FUNCTIONS ------------------- |
||
-- foldr :: (a -> b -> |
-- foldr :: (a -> b -> b) -> b -> [a] -> b |
||
on foldr(f, startValue, xs) |
on foldr(f, startValue, xs) |
||
tell mReturn(f) |
|||
set v to startValue |
|||
set |
set lng to length of xs |
||
repeat with i from lng to 1 by -1 |
|||
set v to |λ|(item i of xs, v, i, xs) |
|||
end repeat |
|||
set v to mf's lambda(v, item i of xs, i, xs) |
|||
return v |
|||
end tell |
|||
end foldr |
end foldr |
||
-- intercalate :: String -> [String] -> String |
|||
on intercalate(delim, xs) |
|||
set {dlm, my text item delimiters} to ¬ |
|||
{my text item delimiters, delim} |
|||
set s to xs as text |
|||
set my text item delimiters to dlm |
|||
s |
|||
end intercalate |
|||
-- map :: (a -> b) -> [a] -> [b] |
-- map :: (a -> b) -> [a] -> [b] |
||
on map(f, xs) |
on map(f, xs) |
||
-- The list obtained by applying f |
|||
set mf to mReturn(f) |
|||
-- to each element of xs. |
|||
tell mReturn(f) |
|||
set lng to length of xs |
|||
set |
set lst to {} |
||
repeat with i from 1 to lng |
|||
set end of lst to |λ|(item i of xs, i, xs) |
|||
return lst |
|||
end repeat |
|||
return lst |
|||
end tell |
|||
end map |
end map |
||
-- zip :: [a] -> [b] -> [(a, b)] |
|||
-- min :: Ord a => a -> a -> a |
|||
on zip(xs, ys) |
|||
on min(x, y) |
|||
script pair |
|||
if y < x then |
|||
y |
|||
end lambda |
|||
end script |
|||
if length of xs = length of ys then |
|||
map(pair, xs) |
|||
else |
else |
||
x |
|||
end if |
end if |
||
end |
end min |
||
-- intercalate :: Text -> [Text] -> Text |
|||
on intercalate(strText, lstText) |
|||
set {dlm, my text item delimiters} to {my text item delimiters, strText} |
|||
set strJoined to lstText as text |
|||
set my text item delimiters to dlm |
|||
return strJoined |
|||
end intercalate |
|||
-- |
-- mReturn :: First-class m => (a -> b) -> m (a -> b) |
||
-- mReturn :: Handler -> Script |
|||
on mReturn(f) |
on mReturn(f) |
||
-- 2nd class handler function lifted into 1st class script wrapper. |
|||
if script is class of f then |
|||
f |
f |
||
else |
else |
||
script |
script |
||
property |
property |λ| : f |
||
end script |
end script |
||
end if |
end if |
||
end mReturn |
end mReturn |
||
</lang> |
|||
-- unlines :: [String] -> String |
|||
on unlines(xs) |
|||
-- A single string formed by the intercalation |
|||
-- of a list of strings with the newline character. |
|||
set {dlm, my text item delimiters} to ¬ |
|||
{my text item delimiters, linefeed} |
|||
set s to xs as text |
|||
set my text item delimiters to dlm |
|||
s |
|||
end unlines |
|||
-- zip :: [a] -> [b] -> [(a, b)] |
|||
on zip(xs, ys) |
|||
-- A list of step-wise pairs drawn from xs and ys |
|||
-- up to the length of the shorter of those lists. |
|||
set lng to min(length of xs, length of ys) |
|||
set zs to {} |
|||
repeat with i from 1 to lng |
|||
set end of zs to {item i of xs, item i of ys} |
|||
end repeat |
|||
return zs |
|||
end zip</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>7259 -> 2 hr, 59 sec |
<pre>7259 -> 2 hr, 59 sec |
||
86400 -> 1 d |
86400 -> 1 d |
||
6000000 -> 9 wk, 6 d, 10 hr, 40 min</pre> |
6000000 -> 9 wk, 6 d, 10 hr, 40 min</pre> |
||
---- |
|||
===Straightforward=== |
|||
<syntaxhighlight lang="applescript">on secondsToCompoundDuration(sec) |
|||
if ((sec's class is not integer) or (sec < 0)) then ¬ |
|||
error "secondsToCompoundDuration() handler only accepts positive integers." |
|||
-- The task description notwithstanding, return "0 sec" if the input is 0. |
|||
if (sec = 0) then return "0 sec" |
|||
-- Otherwise perform the described task. |
|||
set units to {weeks, days, hours, minutes, 1} |
|||
set suffixes to {" wk, ", " d, ", " hr, ", " min, ", " sec, "} |
|||
set output to "" |
|||
repeat with i from 1 to 5 |
|||
set unit to units's item i |
|||
set unitValue to sec div unit |
|||
if (unitValue > 0) then set output to output & unitValue & suffixes's item i |
|||
set sec to sec mod unit |
|||
if (sec = 0) then exit repeat |
|||
end repeat |
|||
return output's text 1 thru -3 |
|||
end secondsToCompoundDuration |
|||
return secondsToCompoundDuration(7259) & linefeed & ¬ |
|||
secondsToCompoundDuration(86400) & linefeed & ¬ |
|||
secondsToCompoundDuration(6000000)</syntaxhighlight> |
|||
{{output}} |
|||
<syntaxhighlight lang="applescript">"2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min"</syntaxhighlight> |
|||
=={{header|Applesoft BASIC}}== |
=={{header|Applesoft BASIC}}== |
||
< |
<syntaxhighlight lang="applesoftbasic">100 DATA604800,WK,86400,D,3600,HR,60,MIN,1,SEC |
||
110 FOR I = 0 TO 4 |
110 FOR I = 0 TO 4 |
||
120 READ M(I), U$(I) |
120 READ M(I), U$(I) |
||
Line 340: | Line 597: | ||
270 END |
270 END |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|Arturo}}== |
|||
{{trans|Nim}} |
|||
<syntaxhighlight lang="rebol">Units: [" wk", " d", " hr", " min", " sec"] |
|||
Quantities: @[7 * 24 * 60 * 60, 24 * 60 * 60, 60 * 60, 60, 1] |
|||
durationString: function [d][ |
|||
dur: d |
|||
idx: 0 |
|||
result: new [] |
|||
while [not? zero? dur][ |
|||
q: dur / Quantities\[idx] |
|||
if not? zero? q [ |
|||
dur: dur % Quantities\[idx] |
|||
'result ++ ~{|q||Units\[idx]|} |
|||
] |
|||
idx: idx +1 |
|||
] |
|||
return join.with:", " result |
|||
] |
|||
loop [7259 86400 6000000] 't [ |
|||
print [t "s => " durationString t] |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre>7259 s => 2 hr, 59 sec |
|||
86400 s => 1 d |
|||
6000000 s => 9 wk, 6 d, 10 hr, 40 min</pre> |
|||
=={{header|AutoHotkey}}== |
=={{header|AutoHotkey}}== |
||
< |
<syntaxhighlight lang="autohotkey">duration(n){ |
||
sec:=1, min:=60*sec, hr:=60*min, day:=24*hr, wk:=7*day |
sec:=1, min:=60*sec, hr:=60*min, day:=24*hr, wk:=7*day |
||
w :=n//wk , n:=Mod(n,wk) |
w :=n//wk , n:=Mod(n,wk) |
||
Line 351: | Line 638: | ||
s :=n |
s :=n |
||
return trim((w?w " wk, ":"") (d?d " d, ":"") (h?h " hr, ":"") (m?m " min, ":"") (s?s " sec":""),", ") |
return trim((w?w " wk, ":"") (d?d " d, ":"") (h?h " hr, ":"") (m?m " min, ":"") (s?s " sec":""),", ") |
||
}</ |
}</syntaxhighlight> |
||
Examples:< |
Examples:<syntaxhighlight lang="autohotkey">data= |
||
( |
( |
||
7259 |
7259 |
||
Line 362: | Line 649: | ||
res .= A_LoopField "`t: " duration(A_LoopField) "`n" |
res .= A_LoopField "`t: " duration(A_LoopField) "`n" |
||
MsgBox % res |
MsgBox % res |
||
return</ |
return</syntaxhighlight> |
||
Outputs:<pre>7259 : 2 hr, 59 sec |
Outputs:<pre>7259 : 2 hr, 59 sec |
||
86400 : 1 d |
86400 : 1 d |
||
Line 368: | Line 655: | ||
=={{header|AWK}}== |
=={{header|AWK}}== |
||
<syntaxhighlight lang="awk"> |
|||
<lang AWK> |
|||
# syntax: GAWK -f CONVERT_SECONDS_TO_COMPOUND_DURATION.AWK |
# syntax: GAWK -f CONVERT_SECONDS_TO_COMPOUND_DURATION.AWK |
||
BEGIN { |
BEGIN { |
||
Line 403: | Line 690: | ||
return(str) |
return(str) |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
<p>Output:</p> |
<p>Output:</p> |
||
<pre> |
<pre> |
||
Line 418: | Line 705: | ||
</pre> |
</pre> |
||
=={{header| |
=={{header|BASIC}}== |
||
<lang dos>@echo off |
|||
::The Main Thing... |
|||
for %%d in (7259 86400 6000000) do call :duration %%d |
|||
exit/b 0 |
|||
::/The Main Thing. |
|||
==={{header|Commodore BASIC}}=== |
|||
::The Function... |
|||
<syntaxhighlight lang="gwbasic">10 REM CONVERT SECONDS TO COMPOUND DURATION |
|||
:duration |
|||
20 REM ADAPTED FROM RUN BASIC VERSION |
|||
set output= |
|||
30 REM =============================================================== |
|||
set /a "wk=%1/604800,rem=%1%%604800" |
|||
40 PRINT CHR$(14) |
|||
if %wk% neq 0 set "output= %wk% wk," |
|||
50 SEC = 7259 |
|||
60 GOSUB 1000 |
|||
70 SEC = 85400 |
|||
80 GOSUB 1000 |
|||
90 SEC = 6000000 |
|||
100 GOSUB 1000 |
|||
110 END |
|||
120 REM ============================================================== |
|||
1000 WK = INT(SEC/60/60/24/7) |
|||
1010 DY = INT(SEC/60/60/24) - 7*WK |
|||
1020 HR = INT(SEC/60/60) - 24*(DY+7*WK) |
|||
1030 MN = INT(SEC/60) - 60*(HR+24*(DY+7*WK)) |
|||
1040 SC = SEC - 60*(MN+60*(HR+24*(DY+7*WK))) |
|||
1050 PRINT SEC;"SEC" : PRINT " ="; |
|||
1055 F = 0 |
|||
1060 IF WK = 0 THEN 1080 |
|||
1070 PRINT WK;"WK"; : F = 1 |
|||
1080 IF DY = 0 THEN 1110 |
|||
1090 IF F THEN PRINT ","; |
|||
1100 PRINT DY;"DY"; : F = 1 |
|||
1110 IF HR = 0 THEN 1140 |
|||
1120 IF F THEN PRINT ","; |
|||
1130 PRINT HR;"HR"; : F = 1 |
|||
1140 IF MN = 0 THEN 1170 |
|||
1150 IF F THEN PRINT ","; |
|||
1160 PRINT MN;"MIN"; : F = 1 |
|||
1170 IF (SC > 0) AND F THEN PRINT ",";SC;"SEC" : GOTO 1200 |
|||
1180 IF (SC = 0) AND F THEN 1200 |
|||
1190 PRINT SC;"SEC" |
|||
1200 PRINT |
|||
1210 RETURN</syntaxhighlight> |
|||
{{out}} |
|||
7259 sec |
|||
= 2 hr, 59 sec |
|||
85400 sec |
|||
= 23 hr, 43 min, 20 sec |
|||
6000000 sec |
|||
= 9 wk, 6 dy, 10 hr, 40 min |
|||
==={{header|BaCon}}=== |
|||
set /a "d=%rem%/86400,rem=%rem%%%86400" |
|||
<syntaxhighlight lang="freebasic"> |
|||
if %d% neq 0 set "output=%output% %d% d," |
|||
'--- SAY_TIME Convert seconds to compound duration |
|||
'--- Weeks, days hours, minutes ,seconds |
|||
SUB SAY_TIME(int sec) |
|||
LOCAL week,day,hour,minute,second TYPE int |
|||
set /a "hr=%rem%/3600,rem=%rem%%%3600" |
|||
week = sec / 604800 |
|||
if %hr% neq 0 set "output=%output% %hr% hr," |
|||
day = MOD(sec /86400,7) |
|||
hour = MOD(sec / 3600 ,24) |
|||
minute = MOD(sec / 60 ,60) |
|||
second = MOD(sec,60) |
|||
IF week > 0 THEN |
|||
PRINT STR$(week) & " wk, " TO p1$ SIZE 100 |
|||
END IF |
|||
IF day > 0 THEN |
|||
set /a "min=%rem%/60,rem=%rem%%%60" |
|||
PRINT STR$(day) & " d, " TO p2$ SIZE 100 |
|||
if %min% neq 0 set "output=%output% %min% min," |
|||
END IF |
|||
IF hour > 0 THEN |
|||
if %rem% neq 0 set "output=%output% %rem% sec," |
|||
PRINT STR$(hour) & " h, " TO p3$ SIZE 100 |
|||
END IF |
|||
IF minute > 0 THEN |
|||
if %1 gtr 0 echo %1 sec = %output:~1,-1% |
|||
PRINT STR$(minute) & " min, " TO p4$ SIZE 100 |
|||
goto :EOF |
|||
END IF |
|||
::/The Function.</lang> |
|||
{{Out}} |
|||
<pre> |
|||
7259 sec = 2 hr, 59 sec |
|||
86400 sec = 1 d |
|||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
IF second > 0 THEN |
|||
=={{header|BBC BASIC}}== |
|||
PRINT STR$(second) & " sec " TO p5$ SIZE 100 |
|||
<lang bbcbasic>REM >compduration |
|||
END IF |
|||
PRINT p1$ ,p2$, p3$, p4$, p5$ |
|||
END SUB |
|||
'---result 9 wk, 6 d, 10 h, 40 min, 7 sec |
|||
SAY_TIME(6000007) |
|||
</syntaxhighlight> |
|||
==={{header|BBC BASIC}}=== |
|||
<syntaxhighlight lang="bbcbasic">REM >compduration |
|||
PRINT FN_convert(7259) |
PRINT FN_convert(7259) |
||
PRINT FN_convert(86400) |
PRINT FN_convert(86400) |
||
Line 474: | Line 817: | ||
ENDIF |
ENDIF |
||
NEXT |
NEXT |
||
= compound$</ |
= compound$</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2 hr, 59 sec |
<pre>2 hr, 59 sec |
||
1 d |
1 d |
||
9 wk, 6 d, 10 hr, 40 min</pre> |
9 wk, 6 d, 10 hr, 40 min</pre> |
||
==={{header|IS-BASIC}}=== |
|||
<syntaxhighlight lang="is-basic">100 PROGRAM "Seconds.bas" |
|||
110 NUMERIC UN(1 TO 5),SEC,UNIT |
|||
120 STRING T$(1 TO 5)*3 |
|||
130 LET UN(1)=604800:LET UN(2)=86400:LET UN(3)=3600:LET UN(4)=60:LET UN(5)=1 |
|||
140 LET T$(1)="wk":LET T$(2)="d":LET T$(3)="hr":LET T$(4)="min":LET T$(5)="sec" |
|||
150 INPUT PROMPT "Duration in seconds: ":SEC |
|||
160 PRINT SEC;"sec ="; |
|||
170 FOR I=1 TO 5 |
|||
180 IF SEC>=UN(I) THEN |
|||
190 LET UNIT=INT(SEC/UN(I)):LET SEC=MOD(SEC,UN(I)) |
|||
200 PRINT UNIT;T$(I); |
|||
210 IF I<4 AND SEC>0 THEN PRINT ","; |
|||
220 END IF |
|||
230 NEXT |
|||
240 PRINT</syntaxhighlight> |
|||
=={{header|Batch File}}== |
|||
<syntaxhighlight lang="dos">@echo off |
|||
::The Main Thing... |
|||
for %%d in (7259 86400 6000000) do call :duration %%d |
|||
exit/b 0 |
|||
::/The Main Thing. |
|||
::The Function... |
|||
:duration |
|||
set output= |
|||
set /a "wk=%1/604800,rem=%1%%604800" |
|||
if %wk% neq 0 set "output= %wk% wk," |
|||
set /a "d=%rem%/86400,rem=%rem%%%86400" |
|||
if %d% neq 0 set "output=%output% %d% d," |
|||
set /a "hr=%rem%/3600,rem=%rem%%%3600" |
|||
if %hr% neq 0 set "output=%output% %hr% hr," |
|||
set /a "min=%rem%/60,rem=%rem%%%60" |
|||
if %min% neq 0 set "output=%output% %min% min," |
|||
if %rem% neq 0 set "output=%output% %rem% sec," |
|||
if %1 gtr 0 echo %1 sec = %output:~1,-1% |
|||
goto :EOF |
|||
::/The Function.</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
7259 sec = 2 hr, 59 sec |
|||
86400 sec = 1 d |
|||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|beeswax}}== |
=={{header|beeswax}}== |
||
< |
<syntaxhighlight lang="beeswax">#>%f# #>%f# #f%<##>%f# |
||
pq":X~7~ :X@~++8~8@:X:X@~-~4~.+~8@T_ |
pq":X~7~ :X@~++8~8@:X:X@~-~4~.+~8@T_ |
||
## ## #### #`K0[`}`D2[`}BF3< < |
## ## #### #`K0[`}`D2[`}BF3< < |
||
>{` wk, `>g?"p{` d, `>g?"p{` hr, `>g?"p{` min, `>g"b{` sec, `b |
>{` wk, `>g?"p{` d, `>g?"p{` hr, `>g?"p{` min, `>g"b{` sec, `b |
||
> d > d > d > d</ |
> d > d > d > d</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 509: | Line 903: | ||
The value to convert is read from stdin, and the corresponding compound duration is written to stdout. |
The value to convert is read from stdin, and the corresponding compound duration is written to stdout. |
||
< |
<syntaxhighlight lang="befunge">&>:"<"%\"O{rq"**+\"<"/:"<"%\"r<|":*+*5-\v |
||
v-7*"l~"/7\"d"\%7:/*83\+*:"xD"\%*83:/"<"< |
v-7*"l~"/7\"d"\%7:/*83\+*:"xD"\%*83:/"<"< |
||
> \:! #v_v#-#<",",#$48*#<,#<.#<>#_:"~"%,v |
> \:! #v_v#-#<",",#$48*#<,#<.#<>#_:"~"%,v |
||
^_@#:$$< > .02g92p ^ ^!:/"~"<</ |
^_@#:$$< > .02g92p ^ ^!:/"~"<</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 523: | Line 917: | ||
=={{header|C}}== |
=={{header|C}}== |
||
<lang c> |
|||
===C: Version written in C89. Average skill level.=== |
|||
<syntaxhighlight lang="c">/* |
|||
* Program seconds2string, C89 version. |
|||
* |
|||
* Read input from argv[1] or stdin, write output to stdout. |
|||
*/ |
|||
#define _CRT_SECURE_NO_WARNINGS /* unlocks printf in Microsoft Visual Studio */ |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
/* |
|||
* Converting the number of seconds in a human-readable string. |
|||
* It is worth noting that direct output to stdout would be even simpler. |
|||
*/ |
|||
char* seconds2string(unsigned long seconds) |
|||
{ |
|||
int i; |
|||
const unsigned long s = 1; |
|||
const unsigned long m = 60 * s; |
|||
const unsigned long h = 60 * m; |
|||
const unsigned long d = 24 * h; |
|||
const unsigned long w = 7 * d; |
|||
const unsigned long coeff[5] = { w, d, h, m, s }; |
|||
const char units[5][4] = { "wk", "d", "hr", "min", "sec" }; |
|||
static char buffer[256]; |
|||
char* ptr = buffer; |
|||
for ( i = 0; i < 5; i++ ) |
|||
{ |
|||
unsigned long value; |
|||
value = seconds / coeff[i]; |
|||
seconds = seconds % coeff[i]; |
|||
if ( value ) |
|||
{ |
|||
if ( ptr != buffer ) |
|||
ptr += sprintf(ptr, ", "); |
|||
ptr += sprintf(ptr,"%lu %s",value,units[i]); |
|||
} |
|||
} |
|||
return buffer; |
|||
} |
|||
/* |
|||
* Main function for seconds2string program. |
|||
*/ |
|||
int main(int argc, char argv[]) |
|||
{ |
|||
unsigned long seconds; |
|||
if ( (argc < 2) && scanf( "%lu", &seconds ) |
|||
|| (argc >= 2) && sscanf( argv[1], "%lu", & seconds ) ) |
|||
{ |
|||
printf( "%s\n", seconds2string(seconds) ); |
|||
return EXIT_SUCCESS; |
|||
} |
|||
return EXIT_FAILURE; |
|||
}</syntaxhighlight> |
|||
===C: Version written in C99. Low skill level.=== |
|||
<syntaxhighlight lang="c"> |
|||
#include <inttypes.h> /* requires c99 */ |
#include <inttypes.h> /* requires c99 */ |
||
#include <stdbool.h> /* requires c99 */ |
#include <stdbool.h> /* requires c99 */ |
||
Line 664: | Line 1,125: | ||
return minutes*60; |
return minutes*60; |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 678: | Line 1,139: | ||
</pre> |
</pre> |
||
=={{header|C sharp}}== |
=={{header|C sharp|C#}}== |
||
===C#: Standard method=== |
===C#: Standard method=== |
||
< |
<syntaxhighlight lang="csharp">using System; |
||
using System.Collections.Generic; |
using System.Collections.Generic; |
||
using System.Linq; |
using System.Linq; |
||
Line 732: | Line 1,193: | ||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 748: | Line 1,209: | ||
{{libheader|System.Linq}} |
{{libheader|System.Linq}} |
||
{{works with|C sharp|6}} |
{{works with|C sharp|6}} |
||
< |
<syntaxhighlight lang="csharp">private static string ConvertToCompoundDuration(int seconds) |
||
{ |
{ |
||
if (seconds < 0) throw new ArgumentOutOfRangeException(nameof(seconds)); |
if (seconds < 0) throw new ArgumentOutOfRangeException(nameof(seconds)); |
||
Line 761: | Line 1,222: | ||
where parts[index] > 0 |
where parts[index] > 0 |
||
select parts[index] + units[index]); |
select parts[index] + units[index]); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|C++}}== |
=={{header|C++}}== |
||
{{works with|C++11}} |
{{works with|C++11}} |
||
< |
<syntaxhighlight lang="cpp"> |
||
#include <iostream> |
#include <iostream> |
||
#include <vector> |
#include <vector> |
||
Line 801: | Line 1,262: | ||
std::cout << " 86400 sec is "; print(convert( 86400)); |
std::cout << " 86400 sec is "; print(convert( 86400)); |
||
std::cout << "6000000 sec is "; print(convert(6000000)); |
std::cout << "6000000 sec is "; print(convert(6000000)); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 808: | Line 1,269: | ||
6000000 sec is 9 wk, 6 d, 10 hr, 40 min |
6000000 sec is 9 wk, 6 d, 10 hr, 40 min |
||
</pre> |
</pre> |
||
=={{header|Clojure}}== |
|||
<syntaxhighlight lang="clojure">(require '[clojure.string :as string]) |
|||
(def seconds-in-minute 60) |
|||
(def seconds-in-hour (* 60 seconds-in-minute)) |
|||
(def seconds-in-day (* 24 seconds-in-hour)) |
|||
(def seconds-in-week (* 7 seconds-in-day)) |
|||
(defn seconds->duration [seconds] |
|||
(let [weeks ((juxt quot rem) seconds seconds-in-week) |
|||
wk (first weeks) |
|||
days ((juxt quot rem) (last weeks) seconds-in-day) |
|||
d (first days) |
|||
hours ((juxt quot rem) (last days) seconds-in-hour) |
|||
hr (first hours) |
|||
min (quot (last hours) seconds-in-minute) |
|||
sec (rem (last hours) seconds-in-minute)] |
|||
(string/join ", " |
|||
(filter #(not (string/blank? %)) |
|||
(conj [] |
|||
(when (> wk 0) (str wk " wk")) |
|||
(when (> d 0) (str d " d")) |
|||
(when (> hr 0) (str hr " hr")) |
|||
(when (> min 0) (str min " min")) |
|||
(when (> sec 0) (str sec " sec"))))))) |
|||
(seconds->duration 7259) |
|||
(seconds->duration 86400) |
|||
(seconds->duration 6000000)</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
"2 hr, 59 sec" |
|||
"1 d" |
|||
"9 wk, 6 d, 10 hr, 40 min" |
|||
</pre> |
|||
=={{header|CLU}}== |
|||
<syntaxhighlight lang="clu">duration = proc (s: int) returns (string) |
|||
own units: array[string] := array[string]$["wk","d","hr","min","sec"] |
|||
own sizes: array[int] := array[int]$[2:7,24,60,60] |
|||
d: string := "" |
|||
r: int |
|||
for i: int in int$from_to_by(5,1,-1) do |
|||
begin |
|||
r := s // sizes[i] |
|||
s := s / sizes[i] |
|||
end except when bounds: |
|||
r := s |
|||
end |
|||
if r ~= 0 then |
|||
d := ", " || int$unparse(r) || " " || units[i] || d |
|||
end |
|||
end |
|||
return(string$rest(d,3)) |
|||
end duration |
|||
start_up = proc () |
|||
po: stream := stream$primary_output() |
|||
tests: array[int] := array[int]$[7259,86400,6000000] |
|||
for test: int in array[int]$elements(tests) do |
|||
stream$putl(po, int$unparse(test) || " => " || duration(test)) |
|||
end |
|||
end start_up</syntaxhighlight> |
|||
{{out}} |
|||
<pre>7259 => 2 hr, 59 sec |
|||
86400 => 1 d |
|||
6000000 => 9 wk, 6 d, 10 hr, 40 min</pre> |
|||
=={{header|COBOL}}== |
=={{header|COBOL}}== |
||
< |
<syntaxhighlight lang="cobol"> identification division. |
||
program-id. fmt-dura. |
program-id. fmt-dura. |
||
data division. |
data division. |
||
Line 883: | Line 1,415: | ||
. |
. |
||
end program fmt. |
end program fmt. |
||
end program fmt-dura.</ |
end program fmt-dura.</syntaxhighlight> |
||
<pre>Enter duration (seconds): 7259 |
<pre>Enter duration (seconds): 7259 |
||
2 hr, 59 sec |
2 hr, 59 sec |
||
Line 890: | Line 1,422: | ||
Enter duration (seconds): 6000000 |
Enter duration (seconds): 6000000 |
||
9 wk, 6 d, 10 hr, 40 min</pre> |
9 wk, 6 d, 10 hr, 40 min</pre> |
||
=={{header|Common Lisp}}== |
|||
<syntaxhighlight lang="lisp">(defconstant +seconds-in-minute* 60) |
|||
(defconstant +seconds-in-hour* (* 60 +seconds-in-minute*)) |
|||
(defconstant +seconds-in-day* (* 24 +seconds-in-hour*)) |
|||
(defconstant +seconds-in-week* (* 7 +seconds-in-day*)) |
|||
(defun seconds->duration (seconds) |
|||
(multiple-value-bind (weeks wk-remainder) (floor seconds +seconds-in-week*) |
|||
(multiple-value-bind (days d-remainder) (floor wk-remainder +seconds-in-day*) |
|||
(multiple-value-bind (hours hr-remainder) (floor d-remainder +seconds-in-hour*) |
|||
(multiple-value-bind (minutes secs) (floor hr-remainder +seconds-in-minute*) |
|||
(let ((chunks nil)) |
|||
(unless (zerop secs) (push (format nil "~D sec" secs) chunks)) |
|||
(unless (zerop minutes) (push (format nil "~D min" minutes) chunks)) |
|||
(unless (zerop hours) (push (format nil "~D hr" hours) chunks)) |
|||
(unless (zerop days) (push (format nil "~D d" days) chunks)) |
|||
(unless (zerop weeks) (push (format nil "~D wk" weeks) chunks)) |
|||
(format t "~{~A~^, ~}~%" chunks))))))) |
|||
(seconds->duration 7259) |
|||
(seconds->duration 86400) |
|||
(seconds->duration 6000000) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|D}}== |
=={{header|D}}== |
||
<syntaxhighlight lang="d"> |
|||
<lang d> |
|||
import std.stdio, std.conv, std.algorithm; |
import std.stdio, std.conv, std.algorithm; |
||
Line 932: | Line 1,494: | ||
6_000_000.ConvertSeconds.writeln; |
6_000_000.ConvertSeconds.writeln; |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Delphi}}== |
|||
{{works with|Delphi|6.0}} |
|||
{{libheader|SysUtils,StdCtrls,DateUtils}} |
|||
<syntaxhighlight lang="Delphi"> |
|||
const TestData: array [0..2] of integer = (7259,86400,6000000); |
|||
function SecondsToFormatDate(Sec: integer): string; |
|||
var DT: TDateTime; |
|||
var Weeks: integer; |
|||
var AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; |
|||
const SecPerDay = 60 * 60 * 24; |
|||
begin |
|||
{Convert seconds to Delphi TDateTime} |
|||
{which is floating point days} |
|||
DT:=Sec / SecPerDay; |
|||
{Get weeks and subtract them off} |
|||
Weeks:=Trunc(DT/7); |
|||
DT:=DT - Weeks * 7; |
|||
{Decode date} |
|||
DecodeDateTime(DT,AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); |
|||
{Compensate because TDateTime starts on Dec 30th 1899} |
|||
if aDay<30 then aDay:=aDay + 1 else aDay:=aDay - 30; |
|||
Result:=''; |
|||
if Weeks<>0 then Result:=Result+IntToStr(Weeks)+' wk, '; |
|||
if ADay<>0 then Result:=Result+IntToStr(ADay)+' d, '; |
|||
if AHour<>0 then Result:=Result+IntToStr(AHour)+' hr, '; |
|||
if AMinute<>0 then Result:=Result+IntToStr(AMinute)+' min, '; |
|||
if ASecond<>0 then Result:=Result+IntToStr(ASecond)+' sec, '; |
|||
end; |
|||
procedure ShowFormatedDataTime(Memo: TMemo); |
|||
var I: integer; |
|||
begin |
|||
for I:=0 to High(TestData) do |
|||
Memo.Lines.Add(IntToStr(TestData[I])+' = '+SecondsToFormatDate(TestData[I])); |
|||
end; |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
7259 = 2 hr, 59 sec, |
|||
86400 = 1 d, |
|||
6000000 = 9 wk, 6 d, 10 hr, 40 min, |
|||
Elapsed Time: 2.900 ms. |
|||
</pre> |
|||
=={{header|EasyLang}}== |
|||
<syntaxhighlight lang="text"> |
|||
func$ split sec . |
|||
divs[] = [ 60 60 24 7 ] |
|||
n$[] = [ "sec" "min" "hr" "d" "wk" ] |
|||
len r[] 5 |
|||
for i = 1 to 4 |
|||
r[i] = sec mod divs[i] |
|||
sec = sec div divs[i] |
|||
. |
|||
r[5] = sec |
|||
for i = 5 downto 1 |
|||
if r[i] <> 0 |
|||
if s$ <> "" |
|||
s$ &= ", " |
|||
. |
|||
s$ &= r[i] & " " & n$[i] |
|||
. |
|||
. |
|||
return s$ |
|||
. |
|||
print split 7259 |
|||
print split 86400 |
|||
print split 6000000 |
|||
</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 941: | Line 1,587: | ||
=={{header|Elixir}}== |
=={{header|Elixir}}== |
||
< |
<syntaxhighlight lang="elixir">defmodule Convert do |
||
@minute 60 |
@minute 60 |
||
@hour @minute*60 |
@hour @minute*60 |
||
Line 961: | Line 1,607: | ||
Enum.each([7259, 86400, 6000000], fn sec -> |
Enum.each([7259, 86400, 6000000], fn sec -> |
||
:io.fwrite "~10w sec : ~s~n", [sec, Convert.sec_to_str(sec)] |
:io.fwrite "~10w sec : ~s~n", [sec, Convert.sec_to_str(sec)] |
||
end)</ |
end)</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 977: | Line 1,623: | ||
Function ''intercalate/2'' is copied from [https://github.com/tim/erlang-oauth/blob/master/src/oauth.erl a Tim Fletcher's GitHub repository]. |
Function ''intercalate/2'' is copied from [https://github.com/tim/erlang-oauth/blob/master/src/oauth.erl a Tim Fletcher's GitHub repository]. |
||
< |
<syntaxhighlight lang="erlang"> |
||
-module(convert_seconds). |
-module(convert_seconds). |
||
Line 1,067: | Line 1,713: | ||
% ************************************************** |
% ************************************************** |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
Line 1,077: | Line 1,723: | ||
=={{header|F_Sharp|F#}}== |
=={{header|F_Sharp|F#}}== |
||
< |
<syntaxhighlight lang="fsharp">open System |
||
let convert seconds = |
let convert seconds = |
||
Line 1,097: | Line 1,743: | ||
|> Seq.map (fun str -> let sec = UInt32.Parse str in (sec, convert sec)) |
|> Seq.map (fun str -> let sec = UInt32.Parse str in (sec, convert sec)) |
||
|> Seq.iter (fun (s, v) -> printfn "%10i = %s" s v) |
|> Seq.iter (fun (s, v) -> printfn "%10i = %s" s v) |
||
0</ |
0</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>>RosettaCode 7259 86400 6000000 |
<pre>>RosettaCode 7259 86400 6000000 |
||
Line 1,103: | Line 1,749: | ||
86400 = 1 day |
86400 = 1 day |
||
6000000 = 9 wk, 6 day, 10 hr, 40 min</pre> |
6000000 = 9 wk, 6 day, 10 hr, 40 min</pre> |
||
=={{header|Factor}}== |
|||
<syntaxhighlight lang="factor">USING: assocs io kernel math math.parser qw sequences |
|||
sequences.generalizations ; |
|||
: mod/ ( x y -- w z ) /mod swap ; |
|||
: convert ( n -- seq ) |
|||
60 mod/ 60 mod/ 24 mod/ 7 mod/ 5 narray reverse ; |
|||
: .time ( n -- ) |
|||
convert [ number>string ] map qw{ wk d hr min sec } zip |
|||
[ first "0" = ] reject [ " " join ] map ", " join print ; |
|||
7259 86400 6000000 [ .time ] tri@</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Forth}}== |
|||
{{works with|Gforth|0.7.3}} |
|||
<syntaxhighlight lang="forth">CREATE C 0 , |
|||
: ., C @ IF ." , " THEN 1 C ! ; |
|||
: .TIME ( n --) |
|||
[ 60 60 24 7 * * * ]L /MOD ?DUP-IF ., . ." wk" THEN |
|||
[ 60 60 24 * * ]L /MOD ?DUP-IF ., . ." d" THEN |
|||
[ 60 60 * ]L /MOD ?DUP-IF ., . ." hr" THEN |
|||
[ 60 ]L /MOD ?DUP-IF ., . ." min" THEN |
|||
?DUP-IF ., . ." sec" THEN 0 C ! ;</syntaxhighlight> |
|||
{{out}} |
|||
<pre>2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min</pre> |
|||
=={{header|Fortran}}== |
=={{header|Fortran}}== |
||
Line 1,108: | Line 1,790: | ||
If the time to describe was not an integer but a floating-point value with fractional parts, then there is a complication. The number of seconds can be less than sixty, but, on output, 60 seconds can appear. If the number of seconds was to be written with one decimal digit (say) and the output format was F4.1 for that, then if the value was 59·95 or more, it will be rounded up for output, in this example to 60·0. Various systems make this mistake, as also with latitude and longitude, and it is a general problem. A fixup pass is necessary before generating the output: maintain an array with the integer values of the various units, then (for one decimal digit usage) check that the seconds part is less than 59·95. If not, set it to zero and augment the minutes count. If this is 60 or more, set it to zero and augment the hours count, and so on. Thus the array. |
If the time to describe was not an integer but a floating-point value with fractional parts, then there is a complication. The number of seconds can be less than sixty, but, on output, 60 seconds can appear. If the number of seconds was to be written with one decimal digit (say) and the output format was F4.1 for that, then if the value was 59·95 or more, it will be rounded up for output, in this example to 60·0. Various systems make this mistake, as also with latitude and longitude, and it is a general problem. A fixup pass is necessary before generating the output: maintain an array with the integer values of the various units, then (for one decimal digit usage) check that the seconds part is less than 59·95. If not, set it to zero and augment the minutes count. If this is 60 or more, set it to zero and augment the hours count, and so on. Thus the array. |
||
<syntaxhighlight lang="fortran"> |
|||
<lang Fortran> |
|||
SUBROUTINE PROUST(T) !Remembrance of time passed. |
SUBROUTINE PROUST(T) !Remembrance of time passed. |
||
INTEGER T !The time, in seconds. Positive only, please. |
INTEGER T !The time, in seconds. Positive only, please. |
||
Line 1,146: | Line 1,828: | ||
CALL PROUST(-666) |
CALL PROUST(-666) |
||
END |
END |
||
</syntaxhighlight> |
|||
</lang> |
|||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 1,155: | Line 1,837: | ||
0 >< |
0 >< |
||
-666 >< |
-666 >< |
||
</pre> |
|||
=={{header|FreeBASIC}}== |
|||
<syntaxhighlight lang="freebasic">'FreeBASIC version 1.05 32/64 bit |
|||
Sub Show(m As Long) |
|||
Dim As Long c(1 To 5)={604800,86400,3600,60,1} |
|||
Dim As String g(1 To 5)={" Wk"," d"," hr"," min"," sec"},comma |
|||
Dim As Long b(1 To 5),flag,m2=m |
|||
Redim As Long s(0) |
|||
For n As Long=1 To 5 |
|||
If m>=c(n) Then |
|||
Do |
|||
Redim Preserve s(Ubound(s)+1) |
|||
s(Ubound(s))=c(n) |
|||
m=m-c(n) |
|||
Loop Until m<c(n) |
|||
End If |
|||
Next n |
|||
For n As Long=1 To Ubound(s) |
|||
For m As Long=1 To 5 |
|||
If s(n)=c(m) Then b(m)+=1 |
|||
Next m |
|||
Next n |
|||
Print m2;" seconds = "; |
|||
For n As Long=1 To 5 |
|||
If b(n) Then: comma=Iif(n<5 Andalso b(n+1),","," and"):flag+=1 |
|||
If flag=1 Then comma="" |
|||
Print comma;b(n);g(n); |
|||
End If |
|||
Next |
|||
Print |
|||
End Sub |
|||
#define seconds |
|||
Show 7259 seconds |
|||
Show 86400 seconds |
|||
Show 6000000 seconds |
|||
sleep</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
7259 seconds = 2 hr and 59 sec |
|||
86400 seconds = 1 d |
|||
6000000 seconds = 9 Wk, 6 d, 10 hr and 40 min |
|||
</pre> |
|||
=={{header|Frink}}== |
|||
Frink's <CODE>-></CODE> operator can break a unit of measure into its constituent parts. However, it does not suppress zero-valued elements unless they are at the beginning or the end, so we have to do that manually. |
|||
<syntaxhighlight lang="frink"> |
|||
wk := week |
|||
n = eval[input["Enter duration in seconds: "]] |
|||
res = n s -> [0, "wk", "d", "hr", "min", "sec", 0] |
|||
res =~ %s/, 0[^,]+//g |
|||
println[res] |
|||
</syntaxhighlight> |
|||
=={{header|FutureBasic}}== |
|||
{{trans|C}} |
|||
<syntaxhighlight lang="futurebasic"> |
|||
include "NSLog.incl" |
|||
local fn CompoundDurationString( seconds as long ) as CFStringRef |
|||
long s = 1, m = s * 60, h = m * 60, d = h * 24, w = d * 7 |
|||
long v(4) : v(0) = w : v(1) = d : v(2) = h : v(3) = m : v(4) = s |
|||
long i, value |
|||
CFArrayRef abbr = @[@"wk",@"d",@"hr",@"min",@"sec"] |
|||
CFMutableStringRef string = fn MutableStringWithCapacity(0) |
|||
for i = 0 to 4 |
|||
value = seconds / v(i) |
|||
seconds = seconds mod v(i) |
|||
if ( value ) |
|||
if ( len(string) ) then MutableStringAppendString( string, @", " ) |
|||
MutableStringAppendFormat( string, @"%ld %@", value, abbr[i] ) |
|||
end if |
|||
next |
|||
end fn = string |
|||
NSLog(@"%@",fn CompoundDurationString(7259)) |
|||
NSLog(@"%@",fn CompoundDurationString(86400)) |
|||
NSLog(@"%@",fn CompoundDurationString(6000000)) |
|||
HandleEvents |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Gambas}}== |
|||
'''[https://gambas-playground.proko.eu/?gist=d7f00b8a96a6f792f0164f622f0686df Click this link to run this code]''' |
|||
<syntaxhighlight lang="gambas">Public Sub Main() |
|||
Dim iInput As Integer[] = [7259, 86400, 6000000] 'Input details |
|||
Dim iChecks As Integer[] = [604800, 86400, 3600, 60] 'Weeks, days, hours, mins in seconds |
|||
Dim iTime As New Integer[5] 'To store wk, d, hr, min & sec |
|||
Dim iOriginal, iSec, iLoop As Integer 'Various integers |
|||
Dim sOrd As String[] = [" wk", " d", " hr", " min", " sec"] 'To add to the output string |
|||
Dim sOutput As String 'Output string |
|||
For Each iSec In iInput 'For each iInput |
|||
iOriginal = iSec 'Store orginal value in seconds |
|||
iTime[4] = iSec 'Store seconds in iTime[4] |
|||
For iLoop = 0 To 3 'Loop through wk, d, hr, min & sec |
|||
If iTime[4] >= iChecks[iLoop] Then 'Check if value is = to wk, d, hr, min |
|||
iTime[iLoop] = Int(iTime[4] / iChecks[iLoop]) 'Put the correct value for wk, d, hr, min in iTime |
|||
iTime[4] = iTime[4] - (iTime[iLoop] * iChecks[iLoop]) 'Remove the amount of seconds for wk, d, hr, min from iTime[4] |
|||
Endif |
|||
Next |
|||
For iLoop = 0 To 4 'Loop through wk, d, hr, min & secs |
|||
If iTime[iLoop] > 0 Then sOutput &= ", " & Str(iTime[iLoop]) & sOrd[iLoop] 'Add comma and ordinal as needed |
|||
Next |
|||
If Left(sOutput, 2) = ", " Then sOutput = Mid(sOutput, 3) 'Remove unnecessary ", " |
|||
sOutput = Format(Str(iOriginal), "#######") & " Seconds = " & sOutput 'Add original seconds to the output string |
|||
Print sOutput 'Print sOutput string |
|||
sOutput = "" 'Clear the sOutput string |
|||
iTime = New Integer[5] 'Reset iTime[] |
|||
Next |
|||
End</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
7259 Seconds = 2 hr, 59 sec |
|||
86400 Seconds = 1 d |
|||
6000000 Seconds = 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Go}}== |
|||
<syntaxhighlight lang="go">package main |
|||
import "fmt" |
|||
func main(){ |
|||
fmt.Println(TimeStr(7259)) |
|||
fmt.Println(TimeStr(86400)) |
|||
fmt.Println(TimeStr(6000000)) |
|||
} |
|||
func TimeStr(sec int)(res string){ |
|||
wks, sec := sec / 604800,sec % 604800 |
|||
ds, sec := sec / 86400, sec % 86400 |
|||
hrs, sec := sec / 3600, sec % 3600 |
|||
mins, sec := sec / 60, sec % 60 |
|||
CommaRequired := false |
|||
if wks != 0 { |
|||
res += fmt.Sprintf("%d wk",wks) |
|||
CommaRequired = true |
|||
} |
|||
if ds != 0 { |
|||
if CommaRequired { |
|||
res += ", " |
|||
} |
|||
res += fmt.Sprintf("%d d",ds) |
|||
CommaRequired = true |
|||
} |
|||
if hrs != 0 { |
|||
if CommaRequired { |
|||
res += ", " |
|||
} |
|||
res += fmt.Sprintf("%d hr",hrs) |
|||
CommaRequired = true |
|||
} |
|||
if mins != 0 { |
|||
if CommaRequired { |
|||
res += ", " |
|||
} |
|||
res += fmt.Sprintf("%d min",mins) |
|||
CommaRequired = true |
|||
} |
|||
if sec != 0 { |
|||
if CommaRequired { |
|||
res += ", " |
|||
} |
|||
res += fmt.Sprintf("%d sec",sec) |
|||
} |
|||
return |
|||
} |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
</pre> |
||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<syntaxhighlight lang="haskell">import Control.Monad (forM_) |
||
import Data.List (intercalate, mapAccumR) |
import Data.List (intercalate, mapAccumR) |
||
import System.Environment (getArgs) |
import System.Environment (getArgs) |
||
Line 1,185: | Line 2,057: | ||
forM_ args $ \arg -> case readMaybe arg of |
forM_ args $ \arg -> case readMaybe arg of |
||
Just n -> printf "%7d seconds = %s\n" n (compoundDuration n) |
Just n -> printf "%7d seconds = %s\n" n (compoundDuration n) |
||
Nothing -> putStrLn $ "Invalid number of seconds: " ++ arg</ |
Nothing -> putStrLn $ "Invalid number of seconds: " ++ arg</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 1,193: | Line 2,065: | ||
6000000 seconds = 9 wk, 6 d, 10 hr, 40 min |
6000000 seconds = 9 wk, 6 d, 10 hr, 40 min |
||
</pre> |
</pre> |
||
Or, parameterising both the local names for these durations, and also the working assumptions about hours per day, and days per week: |
|||
<syntaxhighlight lang="haskell">import Data.List (intercalate, mapAccumR) |
|||
---------------- COMPOUND DURATION STRINGS --------------- |
|||
durationString :: |
|||
String -> |
|||
String -> |
|||
Int -> |
|||
Int -> |
|||
[String] -> |
|||
Int -> |
|||
String |
|||
durationString |
|||
componentGap |
|||
numberLabelGap |
|||
daysPerWeek |
|||
hoursPerDay |
|||
xs |
|||
n = |
|||
intercalate |
|||
componentGap |
|||
( foldr |
|||
(timeTags numberLabelGap) |
|||
[] |
|||
(zip (weekParts daysPerWeek hoursPerDay n) xs) |
|||
) |
|||
timeTags :: String -> (Int, String) -> [String] -> [String] |
|||
timeTags numberLabelGap (n, s) xs |
|||
| 0 < n = intercalate numberLabelGap [show n, s] : xs |
|||
| otherwise = xs |
|||
weekParts :: Int -> Int -> Int -> [Int] |
|||
weekParts daysPerWeek hoursPerDay = |
|||
snd |
|||
. flip |
|||
(mapAccumR byUnits) |
|||
[0, daysPerWeek, hoursPerDay, 60, 60] |
|||
byUnits :: Int -> Int -> (Int, Int) |
|||
byUnits rest x = (quot (rest - m) u, m) |
|||
where |
|||
(u, m) |
|||
| 0 < x = (x, rem rest x) |
|||
| otherwise = (1, rest) |
|||
--------------------------- TEST ------------------------- |
|||
translation :: String -> Int -> Int -> Int -> String |
|||
translation local daysPerWeek hoursPerDay n = |
|||
intercalate " -> " $ |
|||
[ show, |
|||
durationString |
|||
", " |
|||
" " |
|||
daysPerWeek |
|||
hoursPerDay |
|||
(words local) |
|||
] |
|||
<*> [n] |
|||
main :: IO () |
|||
main = do |
|||
let names = "wk d hr min sec" |
|||
let tests = [7259, 86400, 6000000] |
|||
putStrLn "Assuming 24 hrs per day:" |
|||
mapM_ (putStrLn . translation names 7 24) tests |
|||
putStrLn "\nor, at 8 hours per day, 5 days per week:" |
|||
mapM_ (putStrLn . translation names 5 8) tests</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>Assuming 24/7: |
|||
7259 -> 2 hr, 59 sec |
|||
86400 -> 1 d |
|||
6000000 -> 9 wk, 6 d, 10 hr, 40 min |
|||
or, at 8 working hours per day, 5 days per week: |
|||
7259 -> 2 hr, 59 sec |
|||
86400 -> 3 d |
|||
6000000 -> 41 wk, 3 d, 2 hr, 40 min</pre> |
|||
=={{header|J}}== |
=={{header|J}}== |
||
Line 1,198: | Line 2,155: | ||
Implementation: |
Implementation: |
||
< |
<syntaxhighlight lang="j">fmtsecs=: verb define |
||
seq=. 0 7 24 60 60 #: y |
seq=. 0 7 24 60 60 #: y |
||
}: ;:inv ,(0 ~: seq) # (8!:0 seq) ,. <;.2'wk,d,hr,min,sec,' |
}: ;:inv ,(0 ~: seq) # (8!:0 seq) ,. <;.2'wk,d,hr,min,sec,' |
||
)</ |
)</syntaxhighlight> |
||
The first line uses integer division with remainder to break the value in seconds into its components (weeks, days, hours, minutes, seconds). |
|||
The second line gives each value a label and a trailing comma, drops the parts which have a zero, combines the rest and then removes the trailing comma from the end of the resulting line. |
|||
Task examples: |
Task examples: |
||
< |
<syntaxhighlight lang="j"> fmtsecs 7259 |
||
2 hr, 59 sec |
2 hr, 59 sec |
||
fmtsecs 86400 |
fmtsecs 86400 |
||
1 d |
1 d |
||
fmtsecs 6000000 |
fmtsecs 6000000 |
||
9 wk, 6 d, 10 hr, 40 min</ |
9 wk, 6 d, 10 hr, 40 min</syntaxhighlight> |
||
=={{header|Jakt}}== |
|||
<syntaxhighlight lang="jakt"> |
|||
fn main() { |
|||
for seconds in [ |
|||
7259 |
|||
86400 |
|||
6000000 |
|||
] { |
|||
println("{}", time_string(seconds)) |
|||
} |
|||
} |
|||
fn time_string(mut seconds: i64) throws -> String { |
|||
mut result = "" |
|||
mut minutes = seconds / 60 |
|||
seconds %= 60 |
|||
if seconds > 0 { |
|||
result = format("{} sec", seconds, result) |
|||
} |
|||
mut hours = minutes / 60 |
|||
minutes %= 60 |
|||
if minutes > 0 { |
|||
result = format(match result { |
|||
"" => "{} min" |
|||
else => "{} min, {}" |
|||
}, minutes, result) |
|||
} |
|||
mut days = hours / 24 |
|||
hours %= 24 |
|||
if hours > 0 { |
|||
result = format(match result { |
|||
"" => "{} hr" |
|||
else => "{} hr, {}" |
|||
}, hours, result) |
|||
} |
|||
mut weeks = days / 7 |
|||
days %= 7 |
|||
if days > 0 { |
|||
result = format(match result { |
|||
"" => "{} d" |
|||
else => "{} d, {}" |
|||
}, days, result) |
|||
} |
|||
if weeks > 0 { |
|||
result = format(match result { |
|||
"" => "{} wk" |
|||
else => "{} wk, {}" |
|||
}, weeks, result) |
|||
} |
|||
return result |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
This is a relatively simple task in Java, using the modulus-remainder operator. |
|||
<lang java>public class CompoundDuration { |
|||
<syntaxhighlight lang="java"> |
|||
String duration(int seconds) { |
|||
StringBuilder string = new StringBuilder(); |
|||
if (seconds >= 604_800 /* 1 wk */) { |
|||
string.append("%,d wk".formatted(seconds / 604_800)); |
|||
seconds %= 604_800; |
|||
} |
|||
if (seconds >= 86_400 /* 1 d */) { |
|||
if (!string.isEmpty()) string.append(", "); |
|||
string.append("%d d".formatted(seconds / 86_400)); |
|||
seconds %= 86_400; |
|||
} |
|||
if (seconds >= 3600 /* 1 hr */) { |
|||
if (!string.isEmpty()) string.append(", "); |
|||
string.append("%d hr".formatted(seconds / 3600)); |
|||
seconds %= 3600; |
|||
} |
|||
if (seconds >= 60 /* 1 min */) { |
|||
if (!string.isEmpty()) string.append(", "); |
|||
string.append("%d min".formatted(seconds / 60)); |
|||
seconds %= 60; |
|||
} |
|||
if (seconds > 0) { |
|||
if (!string.isEmpty()) string.append(", "); |
|||
string.append("%d sec".formatted(seconds)); |
|||
} |
|||
return string.toString(); |
|||
} |
|||
</syntaxhighlight> |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
<br /> |
|||
An alternate demonstration |
|||
<syntaxhighlight lang="java">public class CompoundDuration { |
|||
public static void main(String[] args) { |
public static void main(String[] args) { |
||
Line 1,243: | Line 2,299: | ||
return sec; |
return sec; |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
<pre>2 hr, 59 sec |
<pre>2 hr, 59 sec |
||
1 d |
1 d |
||
9 wk, 6 d, 10 hr, 40 min</pre> |
9 wk, 6 d, 10 hr, 40 min</pre> |
||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
Line 1,256: | Line 2,311: | ||
====ES5==== |
====ES5==== |
||
< |
<syntaxhighlight lang="javascript">(function () { |
||
'use strict'; |
'use strict'; |
||
Line 1,315: | Line 2,370: | ||
})(); |
})(); |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
Line 1,324: | Line 2,379: | ||
====ES6==== |
====ES6==== |
||
<syntaxhighlight lang="javascript">(() => { |
|||
"use strict"; |
|||
// ---------------- COMPOUND DURATION ---------------- |
|||
<lang JavaScript>(() => { |
|||
// |
// compoundDuration :: [String] -> Int -> String |
||
const compoundDuration = labels => |
|||
nSeconds => weekParts(nSeconds) |
|||
.map((v, i) => [v, labels[i]]) |
|||
.reduce((a, x) => |
|||
a.concat( |
|||
x[0] ? [ |
|||
`${x[0]} ${x[1] || "?"}` |
|||
] : [] |
|||
), [] |
|||
) |
|||
.join(", "); |
|||
// weekParts :: Int -> [Int] |
|||
weekParts = intSeconds => [undefined, 7, 24, 60, 60] |
|||
.reduceRight((a, x) => { |
|||
let r = a.rem, |
|||
mod = isNaN(x) ? r : r % x; |
|||
return { |
|||
rem: (r - mod) / (x || 1), |
|||
parts: [mod].concat(a.parts) |
|||
}; |
|||
}, { |
|||
rem: intSeconds, |
|||
parts: [] |
|||
}) |
|||
.parts; |
|||
// weekParts :: Int -> [Int] |
|||
const weekParts = nSeconds => [0, 7, 24, 60, 60] |
|||
.reduceRight((a, x) => { |
|||
const |
|||
r = a[0], |
|||
mod = x !== 0 ? r % x : r; |
|||
return [ |
|||
(r - mod) / (x || 1), |
|||
return [7259, 86400, 6E6] |
|||
[mod, ...a[1]] |
|||
.map(intSeconds => |
|||
]; |
|||
) |
}, [nSeconds, []])[1]; |
||
.join("\n"); |
|||
})();</lang> |
|||
// ---------------------- TEST ----------------------- |
|||
// main :: IO () |
|||
const main = () => { |
|||
const localNames = ["wk", "d", "hr", "min", "sec"]; |
|||
return [7259, 86400, 6E6] |
|||
.map(nSeconds => |
|||
`${nSeconds} -> ${ |
|||
compoundDuration(localNames)(nSeconds) |
|||
}`).join("\n"); |
|||
}; |
|||
// MAIN --- |
|||
return main(); |
|||
})();</syntaxhighlight> |
|||
{{Out}} |
{{Out}} |
||
<pre>7259 -> 2 hr, 59 sec |
<pre>7259 -> 2 hr, 59 sec |
||
Line 1,370: | Line 2,434: | ||
=={{header|jq}}== |
=={{header|jq}}== |
||
{{works with|jq|1.4}} |
{{works with|jq|1.4}} |
||
'''Also works with gojq, the Go implementation''' |
|||
<lang jq>def seconds_to_time_string: |
|||
<syntaxhighlight lang="jq">def seconds_to_time_string: |
|||
def nonzero(text): floor | if . > 0 then "\(.) \(text)" else empty end; |
def nonzero(text): floor | if . > 0 then "\(.) \(text)" else empty end; |
||
if . == 0 then "0 sec" |
if . == 0 then "0 sec" |
||
Line 1,380: | Line 2,445: | ||
(. % 60 | nonzero("sec"))] |
(. % 60 | nonzero("sec"))] |
||
| join(", ") |
| join(", ") |
||
end;</ |
end;</syntaxhighlight> |
||
''Examples''': |
''Examples''': |
||
< |
<syntaxhighlight lang="jq">0, 7259, 86400, 6000000 | "\(.): \(seconds_to_time_string)"</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
< |
<syntaxhighlight lang="sh">$ jq -r -n -f Convert_seconds_to_compound_duration.jq |
||
0: 0 sec |
0: 0 sec |
||
7259: 2 hr, 59 sec |
7259: 2 hr, 59 sec |
||
86400: 1 d |
86400: 1 d |
||
6000000: 9 wk, 6 d, 10 hr, 40 min</ |
6000000: 9 wk, 6 d, 10 hr, 40 min</syntaxhighlight> |
||
=={{header|Julia}}== |
|||
<syntaxhighlight lang="julia"># 1.x |
|||
function duration(sec::Integer)::String |
|||
t = Array{Int}([]) |
|||
for dm in (60, 60, 24, 7) |
|||
sec, m = divrem(sec, dm) |
|||
pushfirst!(t, m) |
|||
end |
|||
pushfirst!(t, sec) |
|||
return join(["$num$unit" for (num, unit) in zip(t, ["w", "d", "h", "m", "s"]) if num > 0], ", ") |
|||
end |
|||
@show duration(7259) |
|||
@show duration(86400) |
|||
@show duration(6000000) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
duration(7259) = "2h, 59s" |
|||
duration(86400) = "1d" |
|||
duration(6000000) = "9w, 6d, 10h, 40m" |
|||
</pre> |
|||
=={{header|K}}== |
|||
{{works with|ngn/k}}<syntaxhighlight lang=K>F:{", "/" "/'+($x[s]),s:,&0<x}(" "\"wk d hr min sec")!0 7 24 60 60\</syntaxhighlight> |
|||
Examples: |
|||
<syntaxhighlight lang=K>F 100 |
|||
"1 min, 40 sec" |
|||
F 7259 |
|||
"2 hr, 59 sec" |
|||
F 86400 |
|||
"1 d" |
|||
F 6000000 |
|||
"9 wk, 6 d, 10 hr, 40 min"</syntaxhighlight> |
|||
tested in ngn/k |
|||
=={{header|Kotlin}}== |
|||
<syntaxhighlight lang="scala">fun compoundDuration(n: Int): String { |
|||
if (n < 0) return "" // task doesn't ask for negative integers to be converted |
|||
if (n == 0) return "0 sec" |
|||
val weeks : Int |
|||
val days : Int |
|||
val hours : Int |
|||
val minutes: Int |
|||
val seconds: Int |
|||
var divisor: Int = 7 * 24 * 60 * 60 |
|||
var rem : Int |
|||
var result = "" |
|||
weeks = n / divisor |
|||
rem = n % divisor |
|||
divisor /= 7 |
|||
days = rem / divisor |
|||
rem %= divisor |
|||
divisor /= 24 |
|||
hours = rem / divisor |
|||
rem %= divisor |
|||
divisor /= 60 |
|||
minutes = rem / divisor |
|||
seconds = rem % divisor |
|||
if (weeks > 0) result += "$weeks wk, " |
|||
if (days > 0) result += "$days d, " |
|||
if (hours > 0) result += "$hours hr, " |
|||
if (minutes > 0) result += "$minutes min, " |
|||
if (seconds > 0) |
|||
result += "$seconds sec" |
|||
else |
|||
result = result.substring(0, result.length - 2) |
|||
return result |
|||
} |
|||
fun main(args: Array<String>) { |
|||
val durations = intArrayOf(0, 7, 84, 7259, 86400, 6000000) |
|||
durations.forEach { println("$it\t-> ${compoundDuration(it)}") } |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
0 -> 0 sec |
|||
7 -> 7 sec |
|||
84 -> 1 min, 24 sec |
|||
7259 -> 2 hr, 59 sec |
|||
86400 -> 1 d |
|||
6000000 -> 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|langur}}== |
|||
<syntaxhighlight lang="langur">val d = fn(var sec) { |
|||
[ |
|||
fw/wk d hr min sec/, |
|||
for[=[]] dm in [7 * 24 * 60 * 60, 24 * 60 * 60, 60 * 60, 60] { |
|||
_for ~= [sec \ dm] |
|||
sec rem= dm |
|||
} ~ [sec], |
|||
] |
|||
} |
|||
for seconds in [7259, 86400, 6000000] { |
|||
val dur = d(seconds) |
|||
write "{{seconds:7}} sec = " |
|||
writeln join(", ", for[=[]] k of dur[1] { |
|||
if dur[2][k] != 0: _for ~= ["{{dur[2][k]}} {{dur[1][k]}}"] |
|||
}) |
|||
} |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> 7259 sec = 2 hr, 59 sec |
|||
86400 sec = 1 d |
|||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
You could also convert nanoseconds to a langur duration. Langur durations use a separate count for years, months, days, hours, minutes, seconds, and nanoseconds. A "month" and a "year" are difficult to define in terms of seconds, which is one of the reasons langur has a duration type. |
|||
=={{header|Liberty BASIC}}== |
=={{header|Liberty BASIC}}== |
||
I got a bit carried away and added 'years'... |
I got a bit carried away and added 'years'... |
||
<syntaxhighlight lang="lb"> |
|||
<lang lb> |
|||
[start] |
[start] |
||
input "Enter SECONDS: "; seconds |
input "Enter SECONDS: "; seconds |
||
Line 1,482: | Line 2,666: | ||
print |
print |
||
goto [start] |
goto [start] |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 1,498: | Line 2,682: | ||
=={{header|Lua}}== |
=={{header|Lua}}== |
||
< |
<syntaxhighlight lang="lua">function duration (secs) |
||
local units, dur = {"wk", "d", "hr", "min"}, "" |
local units, dur = {"wk", "d", "hr", "min"}, "" |
||
for i, v in ipairs({604800, 86400, 3600, 60}) do |
for i, v in ipairs({604800, 86400, 3600, 60}) do |
||
Line 1,515: | Line 2,699: | ||
print(duration(7259)) |
print(duration(7259)) |
||
print(duration(86400)) |
print(duration(86400)) |
||
print(duration(6000000))</ |
print(duration(6000000))</syntaxhighlight> |
||
=={{header| |
=={{header|Maple}}== |
||
<syntaxhighlight lang="maple"> |
|||
<lang Mathematica> |
|||
tim := proc (s) local weeks, days, hours, minutes, seconds; |
|||
compoundDuration[x_Integer] := |
|||
weeks := trunc((1/604800)*s); |
|||
days := trunc((1/86400)*s)-7*weeks; |
|||
hours := trunc((1/3600)*s)-24*days-168*weeks; |
|||
minutes := trunc((1/60)*s)-60*hours-1440*days-10080*weeks; |
|||
seconds := s-60*minutes-3600*hours-86400*days-604800*weeks; |
|||
printf("%s", cat(`if`(0 < weeks, cat(weeks, "wk, "), NULL), `if`(0 < days, cat(days, "d, "), NULL), `if`(0 < hours, cat(hours, "hr, "), NULL), `if`(0 < minutes, cat(minutes, "min, "), NULL), `if`(0 < seconds, cat(seconds, "sec"), NULL))) |
|||
end proc; |
|||
</syntaxhighlight> |
|||
=={{header|Mathematica}}/{{header|Wolfram Language}}== |
|||
<syntaxhighlight lang="mathematica">compoundDuration[x_Integer] := |
|||
StringJoin @@ (Riffle[ |
StringJoin @@ (Riffle[ |
||
ToString /@ ((({Floor[x/604800], |
ToString /@ ((({Floor[x/604800], |
||
Line 1,530: | Line 2,725: | ||
Grid[Table[{n, "secs =", |
Grid[Table[{n, "secs =", |
||
compoundDuration[n]}, {n, {7259, 86400, 6000000}}], |
compoundDuration[n]}, {n, {7259, 86400, 6000000}}], |
||
Alignment -> {Left, Baseline}] |
Alignment -> {Left, Baseline}]</syntaxhighlight> |
||
</lang> |
|||
{{out}} |
{{out}} |
||
<pre>7259 secs = 2 hr, 59 sec |
|||
<pre> |
|||
7259 secs = 2 hr, 59 sec |
|||
86400 secs = 1 d, |
86400 secs = 1 d, |
||
6000000 secs = 9 wk, 6 d, 10 hr, 40 min, |
6000000 secs = 9 wk, 6 d, 10 hr, 40 min,</pre> |
||
</pre> |
|||
=={{header|Nim}}== |
|||
<syntaxhighlight lang="nim">from strutils import addSep |
|||
const |
|||
Units = [" wk", " d", " hr", " min", " sec"] |
|||
Quantities = [7 * 24 * 60 * 60, 24 * 60 * 60, 60 * 60, 60, 1] |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc `$$`*(sec: int): string = |
|||
## Convert a duration in seconds to a friendly string. |
|||
doAssert(sec > 0) |
|||
var duration = sec |
|||
var idx = 0 |
|||
while duration != 0: |
|||
let q = duration div Quantities[idx] |
|||
if q != 0: |
|||
duration = duration mod Quantities[idx] |
|||
result.addSep(", ", 0) |
|||
result.add($q & Units[idx]) |
|||
inc idx |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
when isMainModule: |
|||
for sec in [7259, 86400, 6000000]: |
|||
echo sec, "s = ", $$sec</syntaxhighlight> |
|||
{{out}} |
|||
<pre>7259s = 2 hr, 59 sec |
|||
86400s = 1 d |
|||
6000000s = 9 wk, 6 d, 10 hr, 40 min</pre> |
|||
===Using the “times” module=== |
|||
It is also possible to use the Duration type in the “times” module and the procedure “toParts” which decomposes a duration in units of time (nanoseconds, microseconds, milliseconds, seconds, minutes, hours, days and weeks). |
|||
<syntaxhighlight lang="nim">import times |
|||
from algorithm import reversed |
|||
from strutils import addSep |
|||
const Units = [" wk", " d", " hr", " min", " sec"] |
|||
#--------------------------------------------------------------------------------------------------- |
|||
proc `$$`*(sec: int): string = |
|||
## Convert a duration in seconds to a friendly string. |
|||
## Similar to `$` but with other conventions. |
|||
doAssert(sec > 0) |
|||
var duration = initDuration(seconds = sec) |
|||
let parts = reversed(duration.toParts[Seconds..Weeks]) |
|||
for idx, part in parts: |
|||
if part != 0: |
|||
result.addSep(", ", 0) |
|||
result.add($part & Units[idx]) |
|||
#——————————————————————————————————————————————————————————————————————————————————————————————————— |
|||
when isMainModule: |
|||
for sec in [7259, 86400, 6000000]: |
|||
echo sec, "s = ", $$sec</syntaxhighlight> |
|||
{{out}} |
|||
Output is the same. |
|||
=={{header|OCaml}}== |
=={{header|OCaml}}== |
||
{{works with|OCaml|4.03+}} |
{{works with|OCaml|4.03+}} |
||
<syntaxhighlight lang="ocaml">let divisors = [ |
|||
<lang ocaml> |
|||
let divisors = [ |
|||
(max_int, "wk"); (* many wk = many wk *) |
(max_int, "wk"); (* many wk = many wk *) |
||
(7, "d"); (* 7 d = 1 wk *) |
(7, "d"); (* 7 d = 1 wk *) |
||
Line 1,562: | Line 2,823: | ||
*) |
*) |
||
let compute_duration secs = |
let compute_duration secs = |
||
let rec doloop remain res |
let rec doloop remain res = function |
||
match divs with |
|||
| [] -> res |
| [] -> res |
||
| (n, s) :: ds -> doloop (remain / n) ((remain mod n, s) :: res) ds |
| (n, s) :: ds -> doloop (remain / n) ((remain mod n, s) :: res) ds |
||
Line 1,616: | Line 2,876: | ||
n calc s |
n calc s |
||
in |
in |
||
List.iter testit test_cases |
List.iter testit test_cases</syntaxhighlight> |
||
</lang> |
|||
{{out}} |
{{out}} |
||
[PASS] 7259 seconds -> 2 hr, 59 sec; expected: 2 hr, 59 sec |
[PASS] 7259 seconds -> 2 hr, 59 sec; expected: 2 hr, 59 sec |
||
Line 1,632: | Line 2,891: | ||
{{Works with|PARI/GP|2.7.4 and above}} |
{{Works with|PARI/GP|2.7.4 and above}} |
||
< |
<syntaxhighlight lang="parigp"> |
||
\\ Convert seconds to compound duration |
\\ Convert seconds to compound duration |
||
\\ 4/11/16 aev |
\\ 4/11/16 aev |
||
Line 1,649: | Line 2,908: | ||
print(secs2compdur(6000000)); |
print(secs2compdur(6000000)); |
||
} |
} |
||
</ |
</syntaxhighlight> |
||
{{Output}} |
{{Output}} |
||
Line 1,658: | Line 2,917: | ||
9 wk, 6 d, 10 hr, 40 min |
9 wk, 6 d, 10 hr, 40 min |
||
</pre> |
</pre> |
||
=={{header|Pascal}}== |
|||
{{works with|Extended Pascal}} |
|||
<syntaxhighlight lang="pascal">program convertSecondsToCompoundDuration(output); |
|||
const |
|||
suffixUnitWeek = 'wk'; |
|||
suffixUnitDay = 'd'; |
|||
suffixUnitHour = 'hr'; { Use `'h'` to be SI-compatible. } |
|||
suffixUnitMinute = 'min'; |
|||
suffixUnitSecond = 'sec'; { NB: Only `'s'` is SI-approved. } |
|||
suffixSeparator = ' '; { A non-breaking space would be appropriate. } |
|||
quantitySeparator = ', '; |
|||
{ Maximum expected length of `string` “12345 wk, 6 d, 7 hr, 8 min, 9 sec” } |
|||
timeSpanPrintedMaximumLength = 4 * length(quantitySeparator) + |
|||
20 + length(suffixUnitWeek) + 1 + length(suffixUnitDay) + |
|||
2 + length(suffixUnitHour) + 2 + length(suffixUnitMinute) + |
|||
2 + length(suffixUnitSecond) + 5 * length(suffixSeparator); |
|||
{ Units of time expressed in seconds. } |
|||
minute = 60; |
|||
hour = 60 * minute; |
|||
day = 24 * hour; |
|||
week = 7 * day; |
|||
type |
|||
wholeNumber = 0..maxInt; |
|||
naturalNumber = 1..maxInt; |
|||
canonicalTimeSpan = record |
|||
weeks: wholeNumber; |
|||
days: 0..6; |
|||
hours: 0..23; |
|||
minutes: 0..59; |
|||
seconds: 0..59; |
|||
end; |
|||
stringFitForTimeSpan = string(timeSpanPrintedMaximumLength); |
|||
{ |
|||
\brief turns a time span expressed in seconds into a `canonicalTimeSpan` |
|||
\param duration the non-negative duration expressed in seconds |
|||
\return a `canonicalTimeSpan` representing \param duration seconds |
|||
} |
|||
function getCanonicalTimeSpan(duration: wholeNumber): canonicalTimeSpan; |
|||
{ Perform `div`ision and update `duration`. } |
|||
function split(protected unit: naturalNumber): wholeNumber; |
|||
begin |
|||
split := duration div unit; |
|||
duration := duration mod unit |
|||
end; |
|||
var |
|||
result: canonicalTimeSpan; |
|||
begin |
|||
with result do |
|||
begin |
|||
weeks := split(week); |
|||
days := split(day); |
|||
hours := split(hour); |
|||
minutes := split(minute); |
|||
seconds := duration |
|||
end; |
|||
{ In Pascal there needs to be _exactly_ one assignment to the } |
|||
{ result variable bearing the same name as of the `function`. } |
|||
getCanonicalTimeSpan := result |
|||
end; |
|||
{ |
|||
\brief turns a non-trivial duration into a string |
|||
\param n a positive duration expressed in seconds |
|||
\return \param n expressed in some human-readable form |
|||
} |
|||
function timeSpanString(protected n: naturalNumber): stringFitForTimeSpan; |
|||
const |
|||
qs = quantitySeparator; |
|||
var |
|||
result: stringFitForTimeSpan; |
|||
begin |
|||
with getCanonicalTimeSpan(n) do |
|||
begin |
|||
{ `:1` specifies the minimum-width. Omitting it would cause } |
|||
{ the compiler to insert a vendor-defined default, e. g. 20. } |
|||
writeStr(result, weeks:1, suffixSeparator, suffixUnitWeek); |
|||
{ For strings, `:n` specifies the _exact_ width (padded with spaces). } |
|||
writeStr(result, result:ord(weeks > 0) * length(result)); |
|||
if days > 0 then |
|||
begin |
|||
writeStr(result, result, qs:ord(length(result) > 0) * length(qs), |
|||
days:1, suffixSeparator, suffixUnitDay); |
|||
end; |
|||
if hours > 0 then |
|||
begin |
|||
writeStr(result, result, qs:ord(length(result) > 0) * length(qs), |
|||
hours:1, suffixSeparator, suffixUnitHour); |
|||
end; |
|||
if minutes > 0 then |
|||
begin |
|||
writeStr(result, result, qs:ord(length(result) > 0) * length(qs), |
|||
minutes:1, suffixSeparator, suffixUnitMinute); |
|||
end; |
|||
if seconds > 0 then |
|||
begin |
|||
writeStr(result, result, qs:ord(length(result) > 0) * length(qs), |
|||
seconds:1, suffixSeparator, suffixUnitSecond); |
|||
end |
|||
end; |
|||
timeSpanString := result |
|||
end; |
|||
{ === MAIN ============================================================= } |
|||
begin |
|||
writeLn( 7259, ' seconds are “', timeSpanString(7259), '”'); |
|||
writeLn( 86400, ' seconds are “', timeSpanString(86400), '”'); |
|||
writeLn(6000000, ' seconds are “', timeSpanString(6000000), '”') |
|||
end.</syntaxhighlight> |
|||
{{out}} |
|||
7259 seconds are “2 hr, 59 sec” |
|||
86400 seconds are “1 d” |
|||
6000000 seconds are “9 wk, 6 d, 10 hr, 40 min” |
|||
=={{header|Perl}}== |
=={{header|Perl}}== |
||
===Direct calculation=== |
|||
<lang perl>sub compound_duration { |
|||
<syntaxhighlight lang="perl">use strict; |
|||
use warnings; |
|||
sub compound_duration { |
|||
my $sec = shift; |
my $sec = shift; |
||
no warnings 'numeric'; |
no warnings 'numeric'; |
||
Line 1,671: | Line 3,056: | ||
int($sec/60) % 60 . " min", |
int($sec/60) % 60 . " min", |
||
int($sec) % 60 . " sec"; |
int($sec) % 60 . " sec"; |
||
} |
|||
}</lang> |
|||
for (7259, 86400, 6000000) { |
|||
Demonstration: |
|||
<lang perl>for (7259, 86400, 6000000) { |
|||
printf "%7d sec = %s\n", $_, compound_duration($_) |
printf "%7d sec = %s\n", $_, compound_duration($_) |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> 7259 sec = 2 hr, 59 sec |
|||
<pre> |
|||
7259 sec = 2 hr, 59 sec |
|||
86400 sec = 1 d |
86400 sec = 1 d |
||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
6000000 sec = 9 wk, 6 d, 10 hr, 40 min</pre> |
||
</pre> |
|||
===Using polymod=== |
|||
=={{header|Perl 6}}== |
|||
More general approach for mixed-radix conversions. |
|||
<syntaxhighlight lang="perl">use strict; |
|||
use warnings; |
|||
use Math::AnyNum 'polymod'; |
|||
sub compound_duration { |
|||
The built-in <code>polymod</code> method (which is a generalization of the <code>divmod</code> function known from other languages), is a perfect match for a task like this: |
|||
my $seconds = shift; |
|||
my @terms; |
|||
my @durations = reverse polymod($seconds, 60, 60, 24, 7); |
|||
<lang perl6>sub compound-duration ($seconds) { |
|||
my @timespans = <wk d hr min sec>; |
|||
while (my $d = shift @durations, my $t = shift @timespans) { |
|||
.grep(*[0]).reverse.join(", ") |
|||
push @terms, "$d $t" if $d |
|||
}</lang> |
|||
} |
|||
join ', ', @terms |
|||
Demonstration: |
|||
} |
|||
<lang perl6>for 7259, 86400, 6000000 { |
|||
say "{.fmt: '%7d'} sec = {compound-duration $_}"; |
|||
}</lang> |
|||
for (<7259 86400 6000000 3380521>) { |
|||
printf "%7d sec = %s\n", $_, compound_duration($_) |
|||
}</syntaxhighlight> |
|||
{{out}} |
{{out}} |
||
<pre> 7259 sec = 2 hr, 59 sec |
|||
<pre> |
|||
7259 sec = 2 hr, 59 sec |
|||
86400 sec = 1 d |
86400 sec = 1 d |
||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
||
3380521 sec = 5 wk, 4 d, 3 hr, 2 min, 1 sec</pre> |
|||
</pre> |
|||
=={{header|Phix}}== |
=={{header|Phix}}== |
||
There is a standard function for this, for more details see builtins/pelapsed.e (which will be kept up to date, unlike having a copy here) |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<lang Phix>?elapsed(7259) |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
?elapsed(86400) |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">7259</span><span style="color: #0000FF;">)</span> |
|||
?elapsed(6000000)</lang> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">86400</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">6000000</span><span style="color: #0000FF;">)</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
"2 hours and 59s" |
"2 hours and 59s" |
||
"1 day |
"1 day" |
||
" |
"9 weeks, 6 days, 10 hours, 40 minutes" |
||
</pre> |
|||
You may also be interested in the timedelta() function, which converts durations to seconds, eg: |
|||
<!--<syntaxhighlight lang="phix">(phixonline)--> |
|||
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span> |
|||
<span style="color: #008080;">include</span> <span style="color: #004080;">timedate</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #7060A8;">elapsed</span><span style="color: #0000FF;">(</span><span style="color: #000000;">6000000</span><span style="color: #0000FF;">-</span><span style="color: #7060A8;">timedelta</span><span style="color: #0000FF;">(</span><span style="color: #000000;">days</span><span style="color: #0000FF;">:=</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span><span style="color: #000000;">hours</span><span style="color: #0000FF;">:=</span><span style="color: #000000;">10</span><span style="color: #0000FF;">))</span> |
|||
<!--</syntaxhighlight>--> |
|||
{{out}} |
|||
<pre> |
|||
"9 weeks, 40 minutes" |
|||
</pre> |
</pre> |
||
The routine is implemented in builtins\pelapsed.e which you can modify as desired, and is reproduced for reference below |
|||
<lang Phix>function elapzd(integer v, string d) |
|||
-- private helper function. formats v and pluralises d by adding an "s", or not. |
|||
return sprintf("%d %s%s",{v,d,iff(v=1?"":"s")}) |
|||
end function |
|||
=={{header|PicoLisp}}== |
|||
global function elapsed(atom s) |
|||
<syntaxhighlight lang="picolisp">(for Sec (7259 86400 6000000) |
|||
-- convert s (in seconds) into an elapsed time string suitable for display. |
|||
(tab (-10 -30) |
|||
-- limits: a type check error occurs if s exceeds approx 100 billion years. |
|||
Sec |
|||
atom m,h,d,y |
|||
(glue ", " |
|||
string minus = "", secs, mins |
|||
(extract |
|||
'((N Str) |
|||
(when (gt0 (/ Sec N)) |
|||
(setq Sec (% Sec N)) |
|||
end if |
|||
(pack @ " " Str) ) ) |
|||
m = floor(s/60) |
|||
(604800 86400 3600 60 1) |
|||
'("wk" "d" "hr" "min" "sec") ) ) ) )</syntaxhighlight> |
|||
secs = sprintf(iff(integer(s)?"%ds":"%3.2fs"),s) |
|||
Output: |
|||
if m=0 then |
|||
<pre>7259 2 hr, 59 sec |
|||
return sprintf("%s%s",{minus,secs}) |
|||
86400 1 d |
|||
6000000 9 wk, 6 d, 10 hr, 40 min</pre> |
|||
s = round(s) |
|||
secs = iff(s=0?"":sprintf(" and %02ds",s)) |
|||
h = floor(m/60) |
|||
m = remainder(m,60) |
|||
if h=0 then |
|||
return sprintf("%s%s%s",{minus,elapzd(m,"minute"),secs}) |
|||
end if |
|||
mins = iff(m=0?"":", "&elapzd(m,"minute")) |
|||
if h<24 then |
|||
return sprintf("%s%s%s%s",{minus,elapzd(h,"hour"),mins,secs}) |
|||
end if |
|||
d = floor(h/24) |
|||
h = remainder(h,24) |
|||
if d<365 then |
|||
return sprintf("%s%s, %s%s%s",{minus,elapzd(d,"day"),elapzd(h,"hour"),mins,secs}) |
|||
end if |
|||
y = floor(d/365) |
|||
d = remainder(d,365) |
|||
return sprintf("%s%s, %s, %s%s%s",{minus,elapzd(y,"year"),elapzd(d,"day"),elapzd(h,"hour"),mins,secs}) |
|||
end function</lang> |
|||
=={{header|PL/I}}== |
=={{header|PL/I}}== |
||
<syntaxhighlight lang="pl/i"> |
|||
<lang PL/I> |
|||
/* Convert seconds to Compound Duration (weeks, days, hours, minutes, seconds). */ |
/* Convert seconds to Compound Duration (weeks, days, hours, minutes, seconds). */ |
||
Line 1,788: | Line 3,164: | ||
end; |
end; |
||
end cvt; |
end cvt; |
||
</syntaxhighlight> |
|||
</lang> |
|||
Results: |
Results: |
||
<pre> |
<pre> |
||
Line 1,804: | Line 3,180: | ||
=={{header|PowerShell}}== |
=={{header|PowerShell}}== |
||
<syntaxhighlight lang="powershell"> |
|||
<lang PowerShell> |
|||
function Get-Time |
function Get-Time |
||
{ |
{ |
||
Line 1,921: | Line 3,297: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
Line 1,951: | Line 3,327: | ||
TotalSeconds : 6000000 |
TotalSeconds : 6000000 |
||
TotalMilliseconds : 6000000000 |
TotalMilliseconds : 6000000000 |
||
</pre> |
|||
=={{header|Prolog}}== |
|||
Works with Swi-Prolog. |
|||
Use Contraints for this task so the that functionality can be reversed (eg: find the number of seconds for a split date). |
|||
See below for examples. |
|||
<syntaxhighlight lang="prolog">:- 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).</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
?- maplist(compound_time, [7259,86400,6000000]), !. |
|||
7259: 2 hr, 59 sec |
|||
86400: 1 d |
|||
6000000: 9 wk, 6 d, 10 hr, 40 min |
|||
true. |
|||
?- times(N, [[wk, 9],[d, 6],[hr,10],[min,40]]), !. |
|||
N = 6000000. |
|||
</pre> |
</pre> |
||
=={{header|PureBasic}}== |
=={{header|PureBasic}}== |
||
<syntaxhighlight lang="purebasic"> |
|||
<lang PureBasic> |
|||
EnableExplicit |
EnableExplicit |
||
Line 2,010: | Line 3,449: | ||
CloseConsole() |
CloseConsole() |
||
EndIf |
EndIf |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
{{out}} |
||
Line 2,022: | Line 3,461: | ||
===Python: Procedural=== |
===Python: Procedural=== |
||
< |
<syntaxhighlight lang="python">>>> def duration(seconds): |
||
t= [] |
t= [] |
||
for dm in (60, 60, 24, 7): |
for dm in (60, 60, 24, 7): |
||
Line 2,039: | Line 3,478: | ||
86400 sec = 1 d |
86400 sec = 1 d |
||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
||
>>> </ |
>>> </syntaxhighlight> |
||
===Python: Functional=== |
===Python: Functional=== |
||
< |
<syntaxhighlight lang="python">>>> def duration(seconds, _maxweeks=99999999999): |
||
return ', '.join('%d %s' % (num, unit) |
return ', '.join('%d %s' % (num, unit) |
||
for num, unit in zip([(seconds // d) % m |
for num, unit in zip([(seconds // d) % m |
||
Line 2,058: | Line 3,497: | ||
86400 sec = 1 d |
86400 sec = 1 d |
||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
||
>>> </ |
>>> </syntaxhighlight> |
||
Or, composing a solution from pure curried functions, including the '''mapAccumR''' abstraction (a combination of of '''map''' and '''reduce''', implemented in a variety of languages and functional libraries, in which a new list is derived by repeated application of the same function, as an accumulator (here, a remainder) passes from right to left): |
|||
<syntaxhighlight lang="python">'''Compound duration''' |
|||
from functools import reduce |
|||
from itertools import chain |
|||
# compoundDurationFromUnits :: [Num] -> [String] -> Num -> [(Num, String)] |
|||
def compoundDurationFromUnits(qs): |
|||
'''A list of compound string representions of a number n of time units, |
|||
in terms of the multiples given in qs, and the labels given in ks. |
|||
''' |
|||
return lambda ks: lambda n: list( |
|||
chain.from_iterable(map( |
|||
lambda v, k: [(v, k)] if 0 < v else [], |
|||
mapAccumR( |
|||
lambda a, x: divmod(a, x) if 0 < x else (1, a) |
|||
)(n)(qs)[1], |
|||
ks |
|||
)) |
|||
) |
|||
# --------------------------TEST--------------------------- |
|||
# main :: IO () |
|||
def main(): |
|||
'''Tests of various durations, with a |
|||
particular set of units and labels. |
|||
''' |
|||
print( |
|||
fTable('Compound durations from numbers of seconds:\n')(str)( |
|||
quoted("'") |
|||
)( |
|||
lambda n: ', '.join([ |
|||
str(v) + ' ' + k for v, k in |
|||
compoundDurationFromUnits([0, 7, 24, 60, 60])( |
|||
['wk', 'd', 'hr', 'min', 'sec'] |
|||
)(n) |
|||
]) |
|||
)([7259, 86400, 6000000]) |
|||
) |
|||
# -------------------------GENERIC------------------------- |
|||
# fTable :: String -> (a -> String) -> |
|||
# (b -> String) -> (a -> b) -> [a] -> String |
|||
def fTable(s): |
|||
'''Heading -> x display function -> fx display function -> |
|||
f -> xs -> tabular string. |
|||
''' |
|||
def go(xShow, fxShow, f, xs): |
|||
ys = [xShow(x) for x in xs] |
|||
w = max(map(len, ys)) |
|||
return s + '\n' + '\n'.join(map( |
|||
lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)), |
|||
xs, ys |
|||
)) |
|||
return lambda xShow: lambda fxShow: lambda f: lambda xs: go( |
|||
xShow, fxShow, f, xs |
|||
) |
|||
# mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]) |
|||
def mapAccumR(f): |
|||
'''A tuple of an accumulation and a list derived by a combined |
|||
map and fold, with accumulation from right to left. |
|||
''' |
|||
def go(a, x): |
|||
acc, y = f(a[0], x) |
|||
return (acc, [y] + a[1]) |
|||
return lambda acc: lambda xs: ( |
|||
reduce(go, reversed(xs), (acc, [])) |
|||
) |
|||
# quoted :: Char -> String -> String |
|||
def quoted(c): |
|||
'''A string flanked on both sides |
|||
by a specified quote character. |
|||
''' |
|||
return lambda s: c + s + c |
|||
# MAIN --- |
|||
if __name__ == '__main__': |
|||
main()</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>Compound durations from numbers of seconds: |
|||
7259 -> '2 hr, 59 sec' |
|||
86400 -> '1 d' |
|||
6000000 -> '9 wk, 6 d, 10 hr, 40 min'</pre> |
|||
=={{header|Quackery}}== |
|||
<syntaxhighlight lang="quackery"> [ ' [ 60 60 24 7 ] |
|||
witheach [ /mod swap ] |
|||
$ "" |
|||
' [ $ " wk, " $ " d, " |
|||
$ " hr, " $ " min, " |
|||
$ " sec, " ] |
|||
witheach |
|||
[ do rot dup iff |
|||
[ number$ |
|||
swap join join ] |
|||
else 2drop ] |
|||
-2 split drop ] is duration$ ( n--> $ ) |
|||
' [ 7259 86400 6000000 ] |
|||
witheach |
|||
[ dup echo |
|||
say " seconds is " |
|||
duration$ echo$ |
|||
say "." cr ]</syntaxhighlight> |
|||
{{Out}} |
|||
<pre>7259 seconds is 2 hr, 59 sec. |
|||
86400 seconds is 1 d. |
|||
6000000 seconds is 9 wk, 6 d, 10 hr, 40 min. |
|||
</pre> |
|||
=={{header|Racket}}== |
=={{header|Racket}}== |
||
< |
<syntaxhighlight lang="racket">#lang racket/base |
||
(require racket/string |
(require racket/string |
||
racket/list) |
racket/list) |
||
Line 2,093: | Line 3,658: | ||
(check-equal? (seconds->compound-duration-string 6000000) "9 wk, 6 d, 10 hr, 40 min")) |
(check-equal? (seconds->compound-duration-string 6000000) "9 wk, 6 d, 10 hr, 40 min")) |
||
;; Tim Brown 2015-07-21</ |
;; Tim Brown 2015-07-21</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
All tests pass... there is no output. |
All tests pass... there is no output. |
||
=={{header|Raku}}== |
|||
(formerly Perl 6) |
|||
The built-in <code>polymod</code> method (which is a generalization of the <code>divmod</code> function known from other languages), is a perfect match for a task like this: |
|||
<syntaxhighlight lang="raku" line>sub compound-duration ($seconds) { |
|||
($seconds.polymod(60, 60, 24, 7) Z <sec min hr d wk>) |
|||
.grep(*[0]).reverse.join(", ") |
|||
} |
|||
# Demonstration: |
|||
for 7259, 86400, 6000000 { |
|||
say "{.fmt: '%7d'} sec = {compound-duration $_}"; |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
7259 sec = 2 hr, 59 sec |
|||
86400 sec = 1 d |
|||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|REXX}}== |
=={{header|REXX}}== |
||
===version 1=== |
===version 1=== |
||
< |
<syntaxhighlight lang="rexx">/* REXX --------------------------------------------------------------- |
||
* Format seconds into a time string |
* Format seconds into a time string |
||
*--------------------------------------------------------------------*/ |
*--------------------------------------------------------------------*/ |
||
Line 2,145: | Line 3,733: | ||
a=what%how |
a=what%how |
||
b=what//how |
b=what//how |
||
Return a b</ |
Return a b</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2 hr, 59 sec |
<pre>2 hr, 59 sec |
||
Line 2,156: | Line 3,744: | ||
===version 2=== |
===version 2=== |
||
This REXX version can also handle fractional (seconds) as well as values of zero (time units). |
This REXX version can also handle fractional (seconds) as well as values of zero (time units). |
||
< |
<syntaxhighlight lang="rexx">/*rexx program demonstrates how to convert a number of seconds to bigger time units.*/ |
||
parse arg @; if @='' then @=7259 86400 6000000 /*Not specified? Then use the default.*/ |
parse arg @; if @='' then @=7259 86400 6000000 /*Not specified? Then use the default.*/ |
||
do j=1 for words(@); |
do j=1 for words(@); z= word(@, j) /* [↓] process each number in the list*/ |
||
say right(z, 25) 'seconds: ' convSec(z) /*convert a number to bigger time units*/ |
say right(z, 25) 'seconds: ' convSec(z) /*convert a number to bigger time units*/ |
||
end /*j*/ |
end /*j*/ |
||
Line 2,165: | Line 3,753: | ||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
convSec: parse arg x /*obtain a number from the argument. */ |
convSec: parse arg x /*obtain a number from the argument. */ |
||
w=timeU( 60*60*24*7, 'wk' ) |
w= timeU( 60*60*24*7, 'wk' ) /*obtain number of weeks (if any). */ |
||
d=timeU( 60*60*24 , 'd' ) |
d= timeU( 60*60*24 , 'd' ) /* " " " days " " */ |
||
h=timeU( 60*60 , 'hr' ) |
h= timeU( 60*60 , 'hr' ) /* " " " hours " " */ |
||
m=timeU( 60 , 'min' ) |
m= timeU( 60 , 'min' ) /* " " " minutes " " */ |
||
s=timeU( 1 , 'sec' ) |
s= timeU( 1 , 'sec' ) /* " " " seconds " " */ |
||
if x\==0 then s=word(s 0, 1) + x 'sec' /*handle fractional (residual) seconds.*/ |
if x\==0 then s=word(s 0, 1) + x 'sec' /*handle fractional (residual) seconds.*/ |
||
$=strip(space(w d h m s),,","); if $=='' then z=0 "sec" |
$=strip(space(w d h m s),,","); if $=='' then z= 0 "sec" /*handle 0 sec.*/ |
||
return $ |
return $ |
||
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
/*──────────────────────────────────────────────────────────────────────────────────────*/ |
||
timeU: parse arg u,$; |
timeU: parse arg u,$; _= x%u; if _==0 then return ''; x= x - _*u; return _ $","</syntaxhighlight> |
||
{{out|output|text= when using the default (internal) inputs:}} |
|||
<pre> |
<pre> |
||
7259 seconds: 2 hr, 59 sec |
7259 seconds: 2 hr, 59 sec |
||
Line 2,181: | Line 3,769: | ||
6000000 seconds: 9 wk, 6 d, 10 hr, 40 min |
6000000 seconds: 9 wk, 6 d, 10 hr, 40 min |
||
</pre> |
</pre> |
||
{{out|output|text= when using the inputs: <tt> 1800.7 123.50 123.00 0.00 </tt>}} |
|||
<pre> |
<pre> |
||
1800.7 seconds: 30 min, 0.7 sec |
1800.7 seconds: 30 min, 0.7 sec |
||
Line 2,190: | Line 3,778: | ||
=={{header|Ring}}== |
=={{header|Ring}}== |
||
< |
<syntaxhighlight lang="ring"> |
||
sec = 6000005 |
sec = 6000005 |
||
week = floor(sec/60/60/24/7) |
week = floor(sec/60/60/24/7) |
||
Line 2,207: | Line 3,795: | ||
if second > 0 see second |
if second > 0 see second |
||
see " seconds" + nl ok |
see " seconds" + nl ok |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|RPL}}== |
|||
≪ MOD LAST / FLOOR ≫ '<span style="color:blue">'''DIVMOD'''</span>' STO |
|||
≪ {" wk" " d" " hr" " min" " sec" } → unit |
|||
≪ 60 <span style="color:blue">'''DIVMOD'''</span> 60 <span style="color:blue">'''DIVMOD'''</span> 24 <span style="color:blue">'''DIVMOD'''</span> 7 <span style="color:blue">'''DIVMOD'''</span> |
|||
1 SF "" |
|||
1 unit SIZE '''FOR''' j |
|||
'''IF''' SWAP '''THEN''' |
|||
LAST →STR unit j GET + |
|||
'''IF''' 1 FC?C '''THEN''' ", " SWAP + '''END''' |
|||
+ '''END''' |
|||
'''NEXT''' |
|||
≫ ≫ '<span style="color:blue">'''→CDUR'''</span>' STO |
|||
Users of HP-48G and newer models can replace the <code>60 <span style="color:blue">'''DIVMOD'''</span> 60 <span style="color:blue">'''DIVMOD'''</span> 24 <span style="color:blue">'''DIVMOD'''</span> 7 <span style="color:blue">'''DIVMOD'''</span></code> line by: |
|||
{ 60 60 24 7 } 1 ≪ MOD LAST / FLOOR ≫ DOSUBS OBJ→ DROP |
|||
7259 <span style="color:blue">'''→CDUR'''</span> |
|||
86400 <span style="color:blue">'''→CDUR'''</span> |
|||
6000000 <span style="color:blue">'''→CDUR'''</span> |
|||
10! <span style="color:blue">'''→CDUR'''</span> |
|||
{{out}} |
|||
<pre> |
|||
4: "2 hr, 59 sec" |
|||
3: "1 d" |
|||
2: "9 wk, 6 d, 10 hr, 40 min" |
|||
1: "6 wk" |
|||
</pre> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="ruby">MINUTE = 60 |
||
HOUR = MINUTE*60 |
HOUR = MINUTE*60 |
||
DAY = HOUR*24 |
DAY = HOUR*24 |
||
Line 2,224: | Line 3,840: | ||
end |
end |
||
[7259, 86400, 6000000].each{|t| puts "#{t}\t: #{sec_to_str(t)}"}</ |
[7259, 86400, 6000000].each{|t| puts "#{t}\t: #{sec_to_str(t)}"}</syntaxhighlight> |
||
Output: |
Output: |
||
<pre> |
<pre> |
||
Line 2,233: | Line 3,849: | ||
=={{header|Run BASIC}}== |
=={{header|Run BASIC}}== |
||
< |
<syntaxhighlight lang="runbasic">sec = 6000005 |
||
week = int(sec/60/60/24/7) |
week = int(sec/60/60/24/7) |
||
day = int(sec/60/60/24) mod 7 |
day = int(sec/60/60/24) mod 7 |
||
Line 2,245: | Line 3,861: | ||
if hour > 0 then print hour;" hours "; |
if hour > 0 then print hour;" hours "; |
||
if minute > 0 then print minute;" minutes "; |
if minute > 0 then print minute;" minutes "; |
||
if second > 0 then print second;" seconds"</ |
if second > 0 then print second;" seconds"</syntaxhighlight> |
||
=={{header|Rust}}== |
=={{header|Rust}}== |
||
This solution deviates from the prompt a bit in order to make it more general. The benefit of doing it this way is that any values can be filled in for days, hours, minutes and seconds and the `balance` method will do the balancing accordingly. Also, rather than converting the value into a String, it simply implements the `Display` trait. |
This solution deviates from the prompt a bit in order to make it more general. The benefit of doing it this way is that any values can be filled in for days, hours, minutes and seconds and the `balance` method will do the balancing accordingly. Also, rather than converting the value into a String, it simply implements the `Display` trait. |
||
< |
<syntaxhighlight lang="rust">use std::fmt; |
||
Line 2,294: | Line 3,910: | ||
ct.balance(); |
ct.balance(); |
||
println!("After: {}", ct); |
println!("After: {}", ct); |
||
}</ |
}</syntaxhighlight> |
||
=={{header|Scala}}== |
|||
<syntaxhighlight lang="scala">//Converting Seconds to Compound Duration |
|||
object seconds{ |
|||
def main( args:Array[String] ){ |
|||
println("Enter the no.") |
|||
val input = scala.io.StdIn.readInt() |
|||
var week_r:Int = input % 604800 |
|||
var week:Int = (input - week_r)/604800 |
|||
var day_r:Int = week_r % 86400 |
|||
var day:Int = (week_r - day_r)/86400 |
|||
var hour_r:Int = day_r % 3600 |
|||
var hour:Int = (day_r - hour_r)/3600 |
|||
var minute_r:Int = hour_r % 60 |
|||
var minute:Int = (hour_r - minute_r)/60 |
|||
var sec:Int = minute_r % 60 |
|||
println("Week = " + week) |
|||
println("Day = " + day) |
|||
println("Hour = " + hour) |
|||
println("Minute = " + minute) |
|||
println("Second = " + sec) |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Scheme}}== |
|||
{{libheader|Scheme/SRFIs}} |
|||
This version uses delete from SRFI 1 and string-join from SRFI 13: |
|||
<syntaxhighlight lang="scheme"> |
|||
(import (scheme base) |
|||
(scheme write) |
|||
(srfi 1) |
|||
(only (srfi 13) string-join)) |
|||
(define *seconds-in-minute* 60) |
|||
(define *seconds-in-hour* (* 60 *seconds-in-minute*)) |
|||
(define *seconds-in-day* (* 24 *seconds-in-hour*)) |
|||
(define *seconds-in-week* (* 7 *seconds-in-day*)) |
|||
(define (seconds->duration seconds) |
|||
(define (format val unit) |
|||
(if (zero? val) "" (string-append (number->string val) " " unit))) |
|||
(let*-values (((weeks wk-remainder) (floor/ seconds *seconds-in-week*)) |
|||
((days dy-remainder) (floor/ wk-remainder *seconds-in-day*)) |
|||
((hours hr-remainder) (floor/ dy-remainder *seconds-in-hour*)) |
|||
((minutes mn-remainder) (floor/ hr-remainder *seconds-in-minute*))) |
|||
(string-join (delete "" |
|||
(list (format weeks "wk") |
|||
(format days "d") |
|||
(format hours "hr") |
|||
(format minutes "min") |
|||
(format mn-remainder "sec")) |
|||
string=?) ", "))) |
|||
(display (seconds->duration 7259)) (newline) |
|||
(display (seconds->duration 86400)) (newline) |
|||
(display (seconds->duration 6000000)) (newline) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Sidef}}== |
=={{header|Sidef}}== |
||
{{trans| |
{{trans|Raku}} |
||
< |
<syntaxhighlight lang="ruby">func polymod(n, *divs) { |
||
gather { |
gather { |
||
divs.each { |i| |
divs.each { |i| |
||
Line 2,316: | Line 4,007: | ||
[7259, 86400, 6000000].each { |s| |
[7259, 86400, 6000000].each { |s| |
||
say "#{'%7d' % s} sec = #{compound_duration(s)}" |
say "#{'%7d' % s} sec = #{compound_duration(s)}" |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
Line 2,324: | Line 4,015: | ||
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
6000000 sec = 9 wk, 6 d, 10 hr, 40 min |
||
</pre> |
</pre> |
||
=={{header|Standard ML}}== |
|||
<syntaxhighlight lang="sml">local |
|||
fun fmtNonZero (0, _, list) = list |
|||
| fmtNonZero (n, s, list) = Int.toString n ^ " " ^ s :: list |
|||
fun divModHead (_, []) = [] |
|||
| divModHead (d, head :: tail) = head div d :: head mod d :: tail |
|||
in |
|||
fun compoundDuration seconds = |
|||
let |
|||
val digits = foldl divModHead [seconds] [60, 60, 24, 7] |
|||
and units = ["wk", "d", "hr", "min", "sec"] |
|||
in |
|||
String.concatWith ", " (ListPair.foldr fmtNonZero [] (digits, units)) |
|||
end |
|||
end |
|||
val () = app (fn s => print (compoundDuration s ^ "\n")) [7259, 86400, 6000000]</syntaxhighlight> |
|||
=={{header|Swift}}== |
|||
<syntaxhighlight lang="swift">func duration (_ secs:Int) -> String { |
|||
if secs <= 0 { return "" } |
|||
let units = [(604800,"wk"), (86400,"d"), (3600,"hr"), (60,"min")] |
|||
var secs = secs |
|||
var result = "" |
|||
for (period, unit) in units { |
|||
if secs >= period { |
|||
result += "\(secs/period) \(unit), " |
|||
secs = secs % period |
|||
} |
|||
} |
|||
if secs == 0 { |
|||
result.removeLast(2) // remove ", " |
|||
} else { |
|||
result += "\(secs) sec" |
|||
} |
|||
return result |
|||
} |
|||
print(duration(7259)) |
|||
print(duration(86400)) |
|||
print(duration(6000000))</syntaxhighlight> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Line 2,329: | Line 4,062: | ||
The data-driven procedure below can be customised to use different breakpoints, simply by editing the dictionary. |
The data-driven procedure below can be customised to use different breakpoints, simply by editing the dictionary. |
||
< |
<syntaxhighlight lang="tcl">proc sec2str {i} { |
||
set factors { |
set factors { |
||
sec 60 |
sec 60 |
||
Line 2,366: | Line 4,099: | ||
check {sec2str 7259} {2 hr, 59 sec} |
check {sec2str 7259} {2 hr, 59 sec} |
||
check {sec2str 86400} {1 d} |
check {sec2str 86400} {1 d} |
||
check {sec2str 6000000} {9 wk, 6 d, 10 hr, 40 min}</ |
check {sec2str 6000000} {9 wk, 6 d, 10 hr, 40 min}</syntaxhighlight> |
||
{{Out}} |
{{Out}} |
||
Line 2,375: | Line 4,108: | ||
=={{header|uBasic/4tH}}== |
=={{header|uBasic/4tH}}== |
||
Since uBasic/4tH is integer-only, it is hard to return a string. However, it is capable to transform an integer value as required. |
Since uBasic/4tH is integer-only, it is hard to return a string. However, it is capable to transform an integer value as required. |
||
<lang>Proc _CompoundDuration(7259) |
<syntaxhighlight lang="text">Proc _CompoundDuration(7259) |
||
Proc _CompoundDuration(86400) |
Proc _CompoundDuration(86400) |
||
Proc _CompoundDuration(6000000) |
Proc _CompoundDuration(6000000) |
||
Line 2,413: | Line 4,146: | ||
_d Print " d"; : Return |
_d Print " d"; : Return |
||
_hr Print " hr"; : Return |
_hr Print " hr"; : Return |
||
_min Print " min"; : Return</ |
_min Print " min"; : Return</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre>2 hr, 59 sec |
<pre>2 hr, 59 sec |
||
Line 2,420: | Line 4,153: | ||
0 OK, 0:94</pre> |
0 OK, 0:94</pre> |
||
=={{header|Uiua}}== |
|||
{{Works with|Uiua|0.12.0-dev.1}} |
|||
[https://www.uiua.org/pad?src=0_12_0-dev_1__IyBCdWlsZHMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgYSB0aW1lIHBlcmlvZAoKVW5pdHMg4oaQIHsic2Vjb25kIiAibWludXRlIiAiaG91ciIgImRheSIgIndlZWsifQpEdXJhdGlvbnMg4oaQIFs2MCA2MCAyNCA3IDk5OTldCgojIG51bWJlci1vZi1zZWNvbmRzIC0-IFtTIE0gSCBEIFddClBhcnRzIOKGkCDih4wo4peM4oinKOKKmeKKguKKgyjijIrDt3zil78pKSBEdXJhdGlvbnPiiplbXSkKIyBTdHJpbmdpZnkgYSB1bml0OiB7IlgiICJ1bml0In0gLT4gYm94IlggdW5pdHMiICAgICAgIApTdW5pdCDihpAgL-KNmijiioLiioIpIiAi4o2l4o2cKOKKoTF84o2a4oqC4oqZQHMp4omg4pahIjEi4oqiLgojIFBhcnNlIHNlY29uZHMgYXMgYSBzdHJpbmcgcGVyaW9kOiBOIC0-ICJ4eHgiICAgIApTdHJpbmcg4oaQIMKw4pah4oqiL-KNmiQiXywgXyLih4ziiaFTdW5pdOKWveKKgyjCsXzijYnih4ziip9Vbml0c8Kw4ouVKSBQYXJ0cwriiLUoW-KWoVN0cmluZ10pWzcyNTkgODY0MDAgNjAwMDAwMCAxNDAwMDAwMCAzMTQ0OTU5OSAzMTQ0OTYwMV0K Run it in Uiua Pad!] |
|||
<syntaxhighlight lang="uiua"> |
|||
# Builds a string representation of a time period |
|||
Units ← {"second" "minute" "hour" "day" "week"} |
|||
Durations ← [60 60 24 7 9999] |
|||
# number-of-seconds -> [S M H D W] |
|||
Parts ← ⇌(◌∧(⊙⊂⊃(⌊÷|◿)) Durations⊙[]) |
|||
# Stringify a unit: {"X" "unit"} -> box"X units" |
|||
Sunit ← /⍚(⊂⊂)" "⍥⍜(⊡1|⍚⊂⊙@s)≠□"1"⊢. |
|||
# Parse seconds as a string period: N -> "xxx" |
|||
String ← °□⊢/⍚$"_, _"⇌≡Sunit▽⊃(±|⍉⇌⊟Units°⋕) Parts |
|||
∵([□String])[7259 86400 6000000 14000000 31449599 31449601] |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
╭─ |
|||
╷ ⌜2 hours, 59 seconds⌟ |
|||
⌜1 day⌟ |
|||
⌜9 weeks, 6 days, 10 hours, 40 minutes⌟ |
|||
⌜23 weeks, 1 day, 53 minutes, 20 seconds⌟ |
|||
⌜51 weeks, 6 days, 23 hours, 59 minutes, 59 seconds⌟ |
|||
⌜52 weeks, 1 second⌟ |
|||
╯ |
|||
</pre> |
|||
=={{header|Vale}}== |
|||
{{works with|Vale|0.2.0}} |
|||
<syntaxhighlight lang="vale"> |
|||
import stdlib.*; |
|||
import stdlib.stdin.*; |
|||
import stdlib.math.*; |
|||
exported func main() { |
|||
foreach testCase in [#][ |
|||
7259, |
|||
86400, |
|||
6000000, |
|||
] { |
|||
testCase.timeString().println(); |
|||
} |
|||
} |
|||
func timeString(seconds int) str { |
|||
result = ""; |
|||
minutes = seconds / 60; |
|||
set seconds = seconds.mod(60); |
|||
if seconds > 0 { |
|||
set result = seconds.str() + " sec"; |
|||
} |
|||
hours = minutes / 60; |
|||
set minutes = minutes.mod(60); |
|||
if minutes > 0 { |
|||
set result = minutes.str() + if result != "" { |
|||
" min, " + result |
|||
} else { |
|||
" min" |
|||
}; |
|||
} |
|||
days = hours / 24; |
|||
set hours = hours.mod(24); |
|||
if hours > 0 { |
|||
set result = hours.str() + if result != "" { |
|||
" hr, " + result |
|||
} else { |
|||
" hr" |
|||
}; |
|||
} |
|||
weeks = days / 7; |
|||
set days = days.mod(7); |
|||
if days > 0 { |
|||
set result = days.str() + if result != "" { |
|||
" d, " + result |
|||
} else { |
|||
" d" |
|||
}; |
|||
} |
|||
if weeks > 0 { |
|||
set result = weeks.str() + if result != "" { |
|||
" wk, " + result |
|||
} else { |
|||
" wk" |
|||
}; |
|||
} |
|||
return result; |
|||
} |
|||
</syntaxhighlight> |
|||
=={{header|VBA}}== |
|||
<syntaxhighlight lang="vb">Private Function compound_duration(ByVal seconds As Long) As String |
|||
minutes = 60 |
|||
hours = 60 * minutes |
|||
days_ = 24 * hours |
|||
weeks = 7 * days_ |
|||
Dim out As String |
|||
w = seconds \ weeks |
|||
seconds = seconds - w * weeks |
|||
d = seconds \ days_ |
|||
seconds = seconds - d * days_ |
|||
h = seconds \ hours |
|||
seconds = seconds - h * hours |
|||
m = seconds \ minutes |
|||
s = seconds Mod minutes |
|||
out = IIf(w > 0, w & " wk, ", "") & _ |
|||
IIf(d > 0, d & " d, ", "") & _ |
|||
IIf(h > 0, h & " hr, ", "") & _ |
|||
IIf(m > 0, m & " min, ", "") & _ |
|||
IIf(s > 0, s & " sec", "") |
|||
If Right(out, 2) = ", " Then |
|||
compound_duration = Left(out, Len(out) - 2) |
|||
Else |
|||
compound_duration = out |
|||
End If |
|||
End Function |
|||
Public Sub cstcd() |
|||
Debug.Print compound_duration(7259) |
|||
Debug.Print compound_duration(86400) |
|||
Debug.Print compound_duration(6000000) |
|||
End Sub</syntaxhighlight>{{out}} |
|||
<pre>2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min</pre> |
|||
=={{header|VBScript}}== |
=={{header|VBScript}}== |
||
<syntaxhighlight lang="vb"> |
|||
<lang vb> |
|||
Function compound_duration(n) |
Function compound_duration(n) |
||
Do Until n = 0 |
Do Until n = 0 |
||
Line 2,460: | Line 4,325: | ||
WScript.StdOut.WriteLine compound_duration(86400) |
WScript.StdOut.WriteLine compound_duration(86400) |
||
WScript.StdOut.WriteLine compound_duration(6000000) |
WScript.StdOut.WriteLine compound_duration(6000000) |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{Out}} |
{{Out}} |
||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|Wren}}== |
|||
<syntaxhighlight lang="wren">var duration = Fn.new { |s| |
|||
if (s < 1) return "0 sec" |
|||
var dur = "" |
|||
var divs = [7, 24, 60, 60, 1] |
|||
var units = ["wk", "d", "hr", "min", "sec"] |
|||
var t = divs.reduce { |prod, div| prod * div } |
|||
for (i in 0...divs.count) { |
|||
var u = (s/t).floor |
|||
if (u > 0) { |
|||
dur = dur + "%(u) %(units[i]), " |
|||
s = s % t |
|||
} |
|||
t = t / divs[i] |
|||
} |
|||
if (dur.endsWith(", ")) dur = dur[0..-3] |
|||
return dur |
|||
} |
|||
for (s in [7259, 86400, 6000000]) System.print(duration.call(s))</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
2 hr, 59 sec |
|||
1 d |
|||
9 wk, 6 d, 10 hr, 40 min |
|||
</pre> |
|||
=={{header|XPL0}}== |
|||
<syntaxhighlight lang="xpl0">char Str(80); |
|||
func Duration(Sec); \Convert seconds to compound duration |
|||
int Sec, Amt, Unit, DoComma, I, Quot; |
|||
[Amt:= [7*24*60*60, 24*60*60, 60*60, 60, 1]; |
|||
Unit:= [" wk", " d", " hr", " min", " sec"]; |
|||
DoComma:= false; |
|||
for I:= 0 to 4 do |
|||
[Quot:= Sec/Amt(I); |
|||
Sec:= rem(0); |
|||
if Quot # 0 then |
|||
[if DoComma then Text(8, ", "); |
|||
DoComma:= true; |
|||
IntOut(8, Quot); |
|||
Text(8, Unit(I)); |
|||
]; |
|||
]; |
|||
ChOut(8, $0D); ChOut(8, $8A); \terminating CR+LF |
|||
I:= 0; |
|||
loop [Str(I):= ChIn(8); |
|||
if Str(I) >= $80 then return Str; |
|||
I:= I+1; |
|||
]; |
|||
]; |
|||
[Text(0, Duration(7259)); |
|||
Text(0, Duration(86400)); |
|||
Text(0, Duration(6_000_000)); |
|||
]</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
<pre> |
||
2 hr, 59 sec |
2 hr, 59 sec |
||
Line 2,470: | Line 4,400: | ||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
< |
<syntaxhighlight lang="zkl">fcn toWDHMS(sec){ //-->(wk,d,h,m,s) |
||
r,b:=List(),0; |
r,b:=List(),0; |
||
foreach u in (T(60,60,24,7)){ |
foreach u in (T(60,60,24,7)){ |
||
Line 2,477: | Line 4,407: | ||
} |
} |
||
r.append(sec).reverse() |
r.append(sec).reverse() |
||
}</ |
}</syntaxhighlight> |
||
Or, if you like to be concise: |
Or, if you like to be concise: |
||
< |
<syntaxhighlight lang="zkl">fcn toWDHMS(sec){ //-->(wk,d,h,m,s) |
||
T(60,60,24,7).reduce(fcn(n,u,r){ n,u=n.divr(u); r.append(u); n }, |
T(60,60,24,7).reduce(fcn(n,u,r){ n,u=n.divr(u); r.append(u); n }, |
||
sec,r:=List()):r.append(_).reverse(); |
sec,r:=List()):r.append(_).reverse(); |
||
}</ |
}</syntaxhighlight> |
||
were the ":" op takes the left result and stuffs it into the "_" position. |
were the ":" op takes the left result and stuffs it into the "_" position. |
||
< |
<syntaxhighlight lang="zkl">units:=T(" wk"," d"," hr"," min"," sec"); |
||
foreach s in (T(7259,86400,6000000)){ |
foreach s in (T(7259,86400,6000000)){ |
||
toWDHMS(s).zip(units).pump(List,fcn([(t,u)]){ t and String(t,u) or "" }) |
toWDHMS(s).zip(units).pump(List,fcn([(t,u)]){ t and String(t,u) or "" }) |
||
.filter().concat(", ").println(); |
.filter().concat(", ").println(); |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 2,498: | Line 4,428: | ||
=={{header|ZX Spectrum Basic}}== |
=={{header|ZX Spectrum Basic}}== |
||
{{trans|AWK}} |
{{trans|AWK}} |
||
< |
<syntaxhighlight lang="zxbasic">10 LET m=60: LET h=60*m: LET d=h*24: LET w=d*7 |
||
20 DATA 10,7259,86400,6000000,0,1,60,3600,604799,604800,694861 |
20 DATA 10,7259,86400,6000000,0,1,60,3600,604799,604800,694861 |
||
30 READ n |
30 READ n |
||
Line 2,519: | Line 4,449: | ||
200 NEXT i |
200 NEXT i |
||
210 STOP |
210 STOP |
||
220 DEF FN m(a,b)=a-INT (a/b)*b</ |
220 DEF FN m(a,b)=a-INT (a/b)*b</syntaxhighlight> |
Revision as of 13:23, 13 June 2024
![Task](http://static.miraheze.org/rosettacodewiki/thumb/b/ba/Rcode-button-task-crushed.png/64px-Rcode-button-task-crushed.png)
You are encouraged to solve this task according to the task description, using any language you may know.
- 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).
11l
F duration(=sec)
[Int] t
L(dm) [60, 60, 24, 7]
Int m
(sec, m) = (sec I/ dm, sec % dm)
t.insert(0, m)
t.insert(0, sec)
R zip(t, [‘wk’, ‘d’, ‘hr’, ‘min’, ‘sec’]).filter(num_unit -> num_unit[0] > 0).map(num_unit -> num_unit[0]‘ ’num_unit[1]).join(‘, ’)
print(duration(7259))
print(duration(86400))
print(duration(6000000))
Action!
INCLUDE "H6:REALMATH.ACT"
DEFINE PTR="CARD"
TYPE Time=[BYTE s,m,h,d,w]
CARD ARRAY units(5)
PROC Convert(REAL POINTER seconds Time POINTER t)
BYTE ARRAY b,duration=[60 60 24 7]
BYTE i
REAL r,n
b=t
FOR i=0 TO 3
DO
IntToReal(duration(i),n)
RealMod(seconds,n,r)
b(i)=RealToInt(r)
RealDivInt(seconds,n,r)
RealAssign(r,seconds)
OD
b(4)=RealToInt(seconds)
RETURN
PROC PrintTime(Time POINTER t)
INT i
BYTE first,n
BYTE ARRAY b
b=t i=4 first=1
WHILE i>=0
DO
n=b(i)
IF n>0 THEN
IF first=0 THEN
Print(", ")
ELSE
first=0
FI
PrintF("%B %S",n,units(i))
FI
i==-1
OD
RETURN
PROC Test(CHAR ARRAY s)
REAL seconds
Time t
ValR(s,seconds)
PrintR(seconds) Print(" -> ")
Convert(seconds,t)
PrintTime(t) PutE()
RETURN
PROC Main()
Put(125) PutE() ;clear the screen
MathInit()
units(0)="sec" units(1)="min"
units(2)="hr" units(3)="d"
units(4)="wk"
Test("7259")
Test("86400")
Test("6000000")
RETURN
- Output:
Screenshot from Atari 8-bit computer
259 -> 2 hr, 59 sec 86400 -> 1 d 6000000 -> 9 wk, 6 d, 10 hr, 40 min
Ada
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;
- Output:
6 SECONDS = 6 SEC 60 SECONDS = 1 MIN 3659 SECONDS = 1 HR, 59 SEC 7259 SECONDS = 2 HR, 59 SEC 86400 SECONDS = 1 D 6000000 SECONDS = 9 WK, 6 D, 10 HR, 40 MIN 6001200 SECONDS = 9 WK, 6 D, 11 HR 6001230 SECONDS = 9 WK, 6 D, 11 HR, 30 SEC 600000000 SECONDS = 992 WK, 10 HR, 40 MIN
ALGOL 68
# MODE to hold the compound duration #
MODE DURATION = STRUCT( INT weeks, days, hours, minutes, seconds );
# returns seconds converted to a DURATION #
OP TODURATION = ( LONG INT seconds )DURATION:
BEGIN
LONG INT time := seconds;
DURATION result := DURATION( 0, 0, 0, 0, 0 );
seconds OF result := SHORTEN ( time MOD 60 );
time OVERAB 60;
minutes OF result := SHORTEN ( time MOD 60 );
time OVERAB 60;
hours OF result := SHORTEN ( time MOD 24 );
time OVERAB 24;
days OF result := SHORTEN ( time MOD 7 );
time OVERAB 7;
weeks OF result := SHORTEN time;
result
END # DURATION # ;# returns seconds converted to a DURATION #
OP TODURATION = ( INT seconds )DURATION: TODURATION LENG seconds;
# returns a readable form of the DURATION #
OP TOSTRING = ( DURATION t )STRING:
BEGIN
STRING result := "";
STRING separator := "";
IF weeks OF t /= 0 THEN result +:= separator + whole( weeks OF t, 0 ) + " wk"; separator := ", " FI;
IF days OF t /= 0 THEN result +:= separator + whole( days OF t, 0 ) + " d"; separator := ", " FI;
IF hours OF t /= 0 THEN result +:= separator + whole( hours OF t, 0 ) + " hr"; separator := ", " FI;
IF minutes OF t /= 0 THEN result +:= separator + whole( minutes OF t, 0 ) + " min"; separator := ", " FI;
IF seconds OF t /= 0 THEN result +:= separator + whole( seconds OF t, 0 ) + " sec"; separator := ", " FI;
IF result = ""
THEN
# duration is 0 #
result := "0 sec"
FI;
result
END # TOSTRING # ;
# test cases #
print( ( TOSTRING TODURATION 7259, newline ) );
print( ( TOSTRING TODURATION 86400, newline ) );
print( ( TOSTRING TODURATION 6000000, newline ) )
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
ALGOL W
Based on Algol 68 but Algol W does not have dynamic string handling which makes this more complex.
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.
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
APL
duration←{
names←'wk' 'd' 'hr' 'min' 'sec'
parts←0 7 24 60 60⊤⍵
fmt←⍕¨(parts≠0)/parts,¨names
¯2↓∊fmt,¨⊂', '
}
- Output:
duration 7259 2 hr, 59 sec duration 86400 1 d duration 6000000 9 wk, 6 d, 10 hr, 40 min
AppleScript
Functional
-------------------- COMPOUND DURATIONS ------------------
-- weekParts Int -> [Int]
on weekParts(intSeconds)
unitParts(intSeconds, [missing value, 7, 24, 60, 60])
end weekParts
-- localCompoundDuration :: Int -> String
on localCompoundDuration(localNames, intSeconds)
-- [String] -> (Int, String) -> [String]
script formatted
on |λ|(lstPair, a)
set q to item 1 of lstPair
if q > 0 then
{(q as string) & space & item 2 of lstPair} & a
else
a
end if
end |λ|
end script
intercalate(", ", ¬
foldr(formatted, [], ¬
zip(weekParts(intSeconds), localNames)))
end localCompoundDuration
------------------ INTEGER DECOMPOSITION -----------------
-- unitParts :: Int -> [maybe Int] -> [Int]
on unitParts(intTotal, unitList)
-- partList :: Record -> Int -> Record
script partList
on |λ|(x, a)
set intRest to remaining of a
if x is not missing value then
set intMod to intRest mod x
set d to x
else
set intMod to intRest
set d to 1
end if
{remaining:(intRest - intMod) div d, parts:{intMod} & parts of a}
end |λ|
end script
parts of foldr(partList, ¬
{remaining:intTotal, parts:[]}, unitList)
end unitParts
--------------------------- TEST -------------------------
on run
script angloNames
on |λ|(n)
(n as string) & " -> " & ¬
localCompoundDuration(["wk", "d", "hr", "min", "sec"], n)
end |λ|
end script
unlines(map(angloNames, [7259, 86400, 6000000]))
end run
-------------------- GENERIC FUNCTIONS -------------------
-- foldr :: (a -> b -> b) -> b -> [a] -> b
on foldr(f, startValue, xs)
tell mReturn(f)
set v to startValue
set lng to length of xs
repeat with i from lng to 1 by -1
set v to |λ|(item i of xs, v, i, xs)
end repeat
return v
end tell
end foldr
-- intercalate :: String -> [String] -> String
on intercalate(delim, xs)
set {dlm, my text item delimiters} to ¬
{my text item delimiters, delim}
set s to xs as text
set my text item delimiters to dlm
s
end intercalate
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f
-- to each element of xs.
tell mReturn(f)
set lng to length of xs
set lst to {}
repeat with i from 1 to lng
set end of lst to |λ|(item i of xs, i, xs)
end repeat
return lst
end tell
end map
-- min :: Ord a => a -> a -> a
on min(x, y)
if y < x then
y
else
x
end if
end min
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper.
if script is class of f then
f
else
script
property |λ| : f
end script
end if
end mReturn
-- unlines :: [String] -> String
on unlines(xs)
-- A single string formed by the intercalation
-- of a list of strings with the newline character.
set {dlm, my text item delimiters} to ¬
{my text item delimiters, linefeed}
set s to xs as text
set my text item delimiters to dlm
s
end unlines
-- zip :: [a] -> [b] -> [(a, b)]
on zip(xs, ys)
-- A list of step-wise pairs drawn from xs and ys
-- up to the length of the shorter of those lists.
set lng to min(length of xs, length of ys)
set zs to {}
repeat with i from 1 to lng
set end of zs to {item i of xs, item i of ys}
end repeat
return zs
end zip
- Output:
7259 -> 2 hr, 59 sec 86400 -> 1 d 6000000 -> 9 wk, 6 d, 10 hr, 40 min
Straightforward
on secondsToCompoundDuration(sec)
if ((sec's class is not integer) or (sec < 0)) then ¬
error "secondsToCompoundDuration() handler only accepts positive integers."
-- The task description notwithstanding, return "0 sec" if the input is 0.
if (sec = 0) then return "0 sec"
-- Otherwise perform the described task.
set units to {weeks, days, hours, minutes, 1}
set suffixes to {" wk, ", " d, ", " hr, ", " min, ", " sec, "}
set output to ""
repeat with i from 1 to 5
set unit to units's item i
set unitValue to sec div unit
if (unitValue > 0) then set output to output & unitValue & suffixes's item i
set sec to sec mod unit
if (sec = 0) then exit repeat
end repeat
return output's text 1 thru -3
end secondsToCompoundDuration
return secondsToCompoundDuration(7259) & linefeed & ¬
secondsToCompoundDuration(86400) & linefeed & ¬
secondsToCompoundDuration(6000000)
- Output:
"2 hr, 59 sec
1 d
9 wk, 6 d, 10 hr, 40 min"
Applesoft BASIC
100 DATA604800,WK,86400,D,3600,HR,60,MIN,1,SEC
110 FOR I = 0 TO 4
120 READ M(I), U$(I)
130 NEXT
140 DATA7259,86400,6000000
150 ON ERR GOTO 270
160 READ S
170 GOSUB 200
180 PRINT S " = " S$
190 GOTO 160
200 N = S
210 S$ = ""
220 FOR I = 0 TO 4
230 IF INT(N / M(I)) THEN S$ = S$ + MID$(", ", 1, (LEN(S$) > 0) * 2) + STR$(INT(N / M(I))) + " " + U$(I)
240 N = N - INT(N / M(I)) * M(I)
250 NEXT I
260 RETURN
270 END
Arturo
Units: [" wk", " d", " hr", " min", " sec"]
Quantities: @[7 * 24 * 60 * 60, 24 * 60 * 60, 60 * 60, 60, 1]
durationString: function [d][
dur: d
idx: 0
result: new []
while [not? zero? dur][
q: dur / Quantities\[idx]
if not? zero? q [
dur: dur % Quantities\[idx]
'result ++ ~{|q||Units\[idx]|}
]
idx: idx +1
]
return join.with:", " result
]
loop [7259 86400 6000000] 't [
print [t "s => " durationString t]
]
- Output:
7259 s => 2 hr, 59 sec 86400 s => 1 d 6000000 s => 9 wk, 6 d, 10 hr, 40 min
AutoHotkey
duration(n){
sec:=1, min:=60*sec, hr:=60*min, day:=24*hr, wk:=7*day
w :=n//wk , n:=Mod(n,wk)
d :=n//day , n:=Mod(n,day)
h :=n//hr , n:=Mod(n,hr)
m :=n//min , n:=Mod(n,min)
s :=n
return trim((w?w " wk, ":"") (d?d " d, ":"") (h?h " hr, ":"") (m?m " min, ":"") (s?s " sec":""),", ")
}
Examples:
data=
(
7259
86400
6000000
)
loop, parse, data, `n, `r
res .= A_LoopField "`t: " duration(A_LoopField) "`n"
MsgBox % res
return
Outputs:
7259 : 2 hr, 59 sec 86400 : 1 d 6000000 : 9 wk, 6 d, 10 hr, 40 min
AWK
# syntax: GAWK -f CONVERT_SECONDS_TO_COMPOUND_DURATION.AWK
BEGIN {
n = split("7259 86400 6000000 0 1 60 3600 604799 604800 694861",arr," ")
for (i=1; i<=n; i++) {
printf("%9s %s\n",arr[i],howlong(arr[i]))
}
exit(0)
}
function howlong(seconds, n_day,n_hour,n_min,n_sec,n_week,str,x) {
if (seconds >= (x = 60*60*24*7)) {
n_week = int(seconds / x)
seconds = seconds % x
}
if (seconds >= (x = 60*60*24)) {
n_day = int(seconds / x)
seconds = seconds % x
}
if (seconds >= (x = 60*60)) {
n_hour = int(seconds / x)
seconds = seconds % x
}
if (seconds >= (x = 60)) {
n_min = int(seconds / x)
seconds = seconds % x
}
n_sec = int(seconds)
str = (n_week > 0) ? (str n_week " wk, ") : str
str = (n_day > 0) ? (str n_day " d, ") : str
str = (n_hour > 0) ? (str n_hour " hr, ") : str
str = (n_min > 0) ? (str n_min " min, ") : str
str = (n_sec > 0) ? (str n_sec " sec") : str
sub(/, $/,"",str)
return(str)
}
Output:
7259 2 hr, 59 sec 86400 1 d 6000000 9 wk, 6 d, 10 hr, 40 min 0 1 1 sec 60 1 min 3600 1 hr 604799 6 d, 23 hr, 59 min, 59 sec 604800 1 wk 694861 1 wk, 1 d, 1 hr, 1 min, 1 sec
BASIC
Commodore BASIC
10 REM CONVERT SECONDS TO COMPOUND DURATION
20 REM ADAPTED FROM RUN BASIC VERSION
30 REM ===============================================================
40 PRINT CHR$(14)
50 SEC = 7259
60 GOSUB 1000
70 SEC = 85400
80 GOSUB 1000
90 SEC = 6000000
100 GOSUB 1000
110 END
120 REM ==============================================================
1000 WK = INT(SEC/60/60/24/7)
1010 DY = INT(SEC/60/60/24) - 7*WK
1020 HR = INT(SEC/60/60) - 24*(DY+7*WK)
1030 MN = INT(SEC/60) - 60*(HR+24*(DY+7*WK))
1040 SC = SEC - 60*(MN+60*(HR+24*(DY+7*WK)))
1050 PRINT SEC;"SEC" : PRINT " =";
1055 F = 0
1060 IF WK = 0 THEN 1080
1070 PRINT WK;"WK"; : F = 1
1080 IF DY = 0 THEN 1110
1090 IF F THEN PRINT ",";
1100 PRINT DY;"DY"; : F = 1
1110 IF HR = 0 THEN 1140
1120 IF F THEN PRINT ",";
1130 PRINT HR;"HR"; : F = 1
1140 IF MN = 0 THEN 1170
1150 IF F THEN PRINT ",";
1160 PRINT MN;"MIN"; : F = 1
1170 IF (SC > 0) AND F THEN PRINT ",";SC;"SEC" : GOTO 1200
1180 IF (SC = 0) AND F THEN 1200
1190 PRINT SC;"SEC"
1200 PRINT
1210 RETURN
- Output:
7259 sec = 2 hr, 59 sec 85400 sec = 23 hr, 43 min, 20 sec 6000000 sec = 9 wk, 6 dy, 10 hr, 40 min
BaCon
'--- SAY_TIME Convert seconds to compound duration
'--- Weeks, days hours, minutes ,seconds
SUB SAY_TIME(int sec)
LOCAL week,day,hour,minute,second TYPE int
week = sec / 604800
day = MOD(sec /86400,7)
hour = MOD(sec / 3600 ,24)
minute = MOD(sec / 60 ,60)
second = MOD(sec,60)
IF week > 0 THEN
PRINT STR$(week) & " wk, " TO p1$ SIZE 100
END IF
IF day > 0 THEN
PRINT STR$(day) & " d, " TO p2$ SIZE 100
END IF
IF hour > 0 THEN
PRINT STR$(hour) & " h, " TO p3$ SIZE 100
END IF
IF minute > 0 THEN
PRINT STR$(minute) & " min, " TO p4$ SIZE 100
END IF
IF second > 0 THEN
PRINT STR$(second) & " sec " TO p5$ SIZE 100
END IF
PRINT p1$ ,p2$, p3$, p4$, p5$
END SUB
'---result 9 wk, 6 d, 10 h, 40 min, 7 sec
SAY_TIME(6000007)
BBC BASIC
REM >compduration
PRINT FN_convert(7259)
PRINT FN_convert(86400)
PRINT FN_convert(6000000)
END
:
DEF FN_convert(seconds%)
LOCAL units%(), units$(), i%, unit%, compound$
DIM units%(4)
DIM units$(4)
units%() = 604800, 86400, 3600, 60, 1
units$() = "wk", "d", "hr", "min", "sec"
compound$ = ""
FOR i% = 0 TO 4
IF seconds% >= units%(i%) THEN
unit% = seconds% DIV units%(i%)
seconds% = seconds% MOD units%(i%)
compound$ += STR$(unit%) + " " + units$(i%)
IF i% < 4 AND seconds% > 0 THEN compound$ += ", "
ENDIF
NEXT
= compound$
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
IS-BASIC
100 PROGRAM "Seconds.bas"
110 NUMERIC UN(1 TO 5),SEC,UNIT
120 STRING T$(1 TO 5)*3
130 LET UN(1)=604800:LET UN(2)=86400:LET UN(3)=3600:LET UN(4)=60:LET UN(5)=1
140 LET T$(1)="wk":LET T$(2)="d":LET T$(3)="hr":LET T$(4)="min":LET T$(5)="sec"
150 INPUT PROMPT "Duration in seconds: ":SEC
160 PRINT SEC;"sec =";
170 FOR I=1 TO 5
180 IF SEC>=UN(I) THEN
190 LET UNIT=INT(SEC/UN(I)):LET SEC=MOD(SEC,UN(I))
200 PRINT UNIT;T$(I);
210 IF I<4 AND SEC>0 THEN PRINT ",";
220 END IF
230 NEXT
240 PRINT
Batch File
@echo off
::The Main Thing...
for %%d in (7259 86400 6000000) do call :duration %%d
exit/b 0
::/The Main Thing.
::The Function...
:duration
set output=
set /a "wk=%1/604800,rem=%1%%604800"
if %wk% neq 0 set "output= %wk% wk,"
set /a "d=%rem%/86400,rem=%rem%%%86400"
if %d% neq 0 set "output=%output% %d% d,"
set /a "hr=%rem%/3600,rem=%rem%%%3600"
if %hr% neq 0 set "output=%output% %hr% hr,"
set /a "min=%rem%/60,rem=%rem%%%60"
if %min% neq 0 set "output=%output% %min% min,"
if %rem% neq 0 set "output=%output% %rem% sec,"
if %1 gtr 0 echo %1 sec = %output:~1,-1%
goto :EOF
::/The Function.
- Output:
7259 sec = 2 hr, 59 sec 86400 sec = 1 d 6000000 sec = 9 wk, 6 d, 10 hr, 40 min
beeswax
#>%f# #>%f# #f%<##>%f#
pq":X~7~ :X@~++8~8@:X:X@~-~4~.+~8@T_
## ## #### #`K0[`}`D2[`}BF3< <
>{` wk, `>g?"p{` d, `>g?"p{` hr, `>g?"p{` min, `>g"b{` sec, `b
> d > d > d > d
- Output:
julia> beeswax("seconds to compound duration.bswx") i7259 2 hr, 59 sec Program finished! julia> beeswax("seconds to compound duration.bswx") i86400 1 d Program finished! julia> beeswax("seconds to compound duration.bswx") i6000000 9 wk, 6 d, 10 hr, 40 min Program finished!
Befunge
The value to convert is read from stdin, and the corresponding compound duration is written to stdout.
&>:"<"%\"O{rq"**+\"<"/:"<"%\"r<|":*+*5-\v
v-7*"l~"/7\"d"\%7:/*83\+*:"xD"\%*83:/"<"<
> \:! #v_v#-#<",",#$48*#<,#<.#<>#_:"~"%,v
^_@#:$$< > .02g92p ^ ^!:/"~"<
- Output:
7259 2 hr, 59 sec 86400 1 d 6000000 9 wk, 6 d, 10 hr, 40 min
C
C: Version written in C89. Average skill level.
/*
* Program seconds2string, C89 version.
*
* Read input from argv[1] or stdin, write output to stdout.
*/
#define _CRT_SECURE_NO_WARNINGS /* unlocks printf in Microsoft Visual Studio */
#include <stdio.h>
#include <stdlib.h>
/*
* Converting the number of seconds in a human-readable string.
* It is worth noting that direct output to stdout would be even simpler.
*/
char* seconds2string(unsigned long seconds)
{
int i;
const unsigned long s = 1;
const unsigned long m = 60 * s;
const unsigned long h = 60 * m;
const unsigned long d = 24 * h;
const unsigned long w = 7 * d;
const unsigned long coeff[5] = { w, d, h, m, s };
const char units[5][4] = { "wk", "d", "hr", "min", "sec" };
static char buffer[256];
char* ptr = buffer;
for ( i = 0; i < 5; i++ )
{
unsigned long value;
value = seconds / coeff[i];
seconds = seconds % coeff[i];
if ( value )
{
if ( ptr != buffer )
ptr += sprintf(ptr, ", ");
ptr += sprintf(ptr,"%lu %s",value,units[i]);
}
}
return buffer;
}
/*
* Main function for seconds2string program.
*/
int main(int argc, char argv[])
{
unsigned long seconds;
if ( (argc < 2) && scanf( "%lu", &seconds )
|| (argc >= 2) && sscanf( argv[1], "%lu", & seconds ) )
{
printf( "%s\n", seconds2string(seconds) );
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
C: Version written in C99. Low skill level.
#include <inttypes.h> /* requires c99 */
#include <stdbool.h> /* requires c99 */
#include <stdio.h>
#include <stdlib.h>
#define N_EL 5
uintmax_t sec_to_week(uintmax_t);
uintmax_t sec_to_day(uintmax_t);
uintmax_t sec_to_hour(uintmax_t);
uintmax_t sec_to_min(uintmax_t);
uintmax_t week_to_sec(uintmax_t);
uintmax_t day_to_sec(uintmax_t);
uintmax_t hour_to_sec(uintmax_t);
uintmax_t min_to_sec(uintmax_t);
char *format_sec(uintmax_t);
/* the primary function */
int main(int argc, char *argv[])
{
uintmax_t input;
char *a;
if(argc<2) {
printf("usage: %s #seconds\n", argv[0]);
return 1;
}
input = strtoumax(argv[1],(void *)0, 10 /*base 10*/);
if(input<1) {
printf("Bad input: %s\n", argv[1]);
printf("usage: %s #seconds\n", argv[0]);
return 1;
}
printf("Number entered: %" PRIuMAX "\n", input);
a = format_sec(input);
printf(a);
free(a);
return 0;
}
/* note: must free memory
* after using this function */
char *format_sec(uintmax_t input)
{
int i;
bool first;
uintmax_t weeks, days, hours, mins;
/*seconds kept in input*/
char *retval;
FILE *stream;
size_t size;
uintmax_t *traverse[N_EL]={&weeks,&days,
&hours,&mins,&input};
char *labels[N_EL]={"wk","d","hr","min","sec"};
weeks = sec_to_week(input);
input = input - week_to_sec(weeks);
days = sec_to_day(input);
input = input - day_to_sec(days);
hours = sec_to_hour(input);
input = input - hour_to_sec(hours);
mins = sec_to_min(input);
input = input - min_to_sec(mins);
/* input now has the remaining seconds */
/* open stream */
stream = open_memstream(&retval,&size);
if(stream == 0) {
fprintf(stderr,"Unable to allocate memory");
return 0;
}
/* populate stream */
first = true;
for(i=0;i<N_EL;i++) {
if ( *(traverse[i]) != 0 ) {
if(!first) {
fprintf(stream,", %" PRIuMAX " %s",
*(traverse[i]), labels[i]);
} else {
fprintf(stream,"%" PRIuMAX " %s",
*(traverse[i]), labels[i]);
}
fflush(stream);
first=false;
}
}
fprintf(stream,"\n");
fclose(stream);
return retval;
}
uintmax_t sec_to_week(uintmax_t seconds)
{
return sec_to_day(seconds)/7;
}
uintmax_t sec_to_day(uintmax_t seconds)
{
return sec_to_hour(seconds)/24;
}
uintmax_t sec_to_hour(uintmax_t seconds)
{
return sec_to_min(seconds)/60;
}
uintmax_t sec_to_min(uintmax_t seconds)
{
return seconds/60;
}
uintmax_t week_to_sec(uintmax_t weeks)
{
return day_to_sec(weeks*7);
}
uintmax_t day_to_sec(uintmax_t days)
{
return hour_to_sec(days*24);
}
uintmax_t hour_to_sec(uintmax_t hours)
{
return min_to_sec(hours*60);
}
uintmax_t min_to_sec(uintmax_t minutes)
{
return minutes*60;
}
- Output:
Number entered: 7259 2 hr, 59 sec Number entered: 86400 1 d Number entered: 6000000 9 wk, 6 d, 10 hr, 40 min
C#
C#: Standard method
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConvertSecondsToCompoundDuration
{
class Program
{
static void Main( string[] args )
{
foreach ( string arg in args )
{
int duration ;
bool isValid = int.TryParse( arg , out duration ) ;
if ( !isValid ) { Console.Error.WriteLine( "ERROR: Not an integer: {0}" , arg ) ; }
if ( duration < 0 ) { Console.Error.WriteLine( "ERROR: duration must be non-negative" , arg ) ; }
Console.WriteLine();
Console.WriteLine( "{0:#,##0} seconds ==> {1}" , duration , FormatAsDuration(duration) ) ;
}
}
private static string FormatAsDuration( int duration )
{
if ( duration < 0 ) throw new ArgumentOutOfRangeException("duration") ;
return string.Join( ", " , GetDurationParts(duration) ) ;
}
private static IEnumerable<string> GetDurationParts( int duration )
{
var parts = new[]
{
new { Name="wk" , Length = 7*24*60*60*1 , } ,
new { Name="d" , Length = 24*60*60*1 , } ,
new { Name="h" , Length = 60*60*1 , } ,
new { Name="m" , Length = 60*1 , } ,
new { Name="s" , Length = 1 , } ,
} ;
foreach ( var part in parts )
{
int n = Math.DivRem( duration , part.Length , out duration ) ;
if ( n > 0 ) yield return string.Format( "{0} {1}" , n , part.Name ) ;
}
}
}
}
- Output:
7,259 seconds ==> 2 h, 59 s 86,400 seconds ==> 1 d 6,000,000 seconds ==> 9 wk, 6 d, 10 h, 40 m
C#: Using the TimeSpan struct and query syntax
private static string ConvertToCompoundDuration(int seconds)
{
if (seconds < 0) throw new ArgumentOutOfRangeException(nameof(seconds));
if (seconds == 0) return "0 sec";
TimeSpan span = TimeSpan.FromSeconds(seconds);
int[] parts = {span.Days / 7, span.Days % 7, span.Hours, span.Minutes, span.Seconds};
string[] units = {" wk", " d", " hr", " min", " sec"};
return string.Join(", ",
from index in Enumerable.Range(0, units.Length)
where parts[index] > 0
select parts[index] + units[index]);
}
C++
#include <iostream>
#include <vector>
using entry = std::pair<int, const char*>;
void print(const std::vector<entry>& entries, std::ostream& out = std::cout)
{
bool first = true;
for(const auto& e: entries) {
if(!first) out << ", ";
first = false;
out << e.first << " " << e.second;
}
out << '\n';
}
std::vector<entry> convert(int seconds)
{
static const entry time_table[] = {
{7*24*60*60, "wk"}, {24*60*60, "d"}, {60*60, "hr"}, {60, "min"}, {1, "sec"}
};
std::vector<entry> result;
for(const auto& e: time_table) {
int time = seconds / e.first;
if(time != 0) result.emplace_back(time, e.second);
seconds %= e.first;
}
return result;
}
int main()
{
std::cout << " 7259 sec is "; print(convert( 7259));
std::cout << " 86400 sec is "; print(convert( 86400));
std::cout << "6000000 sec is "; print(convert(6000000));
}
- Output:
7259 sec is 2 hr, 59 sec 86400 sec is 1 d 6000000 sec is 9 wk, 6 d, 10 hr, 40 min
Clojure
(require '[clojure.string :as string])
(def seconds-in-minute 60)
(def seconds-in-hour (* 60 seconds-in-minute))
(def seconds-in-day (* 24 seconds-in-hour))
(def seconds-in-week (* 7 seconds-in-day))
(defn seconds->duration [seconds]
(let [weeks ((juxt quot rem) seconds seconds-in-week)
wk (first weeks)
days ((juxt quot rem) (last weeks) seconds-in-day)
d (first days)
hours ((juxt quot rem) (last days) seconds-in-hour)
hr (first hours)
min (quot (last hours) seconds-in-minute)
sec (rem (last hours) seconds-in-minute)]
(string/join ", "
(filter #(not (string/blank? %))
(conj []
(when (> wk 0) (str wk " wk"))
(when (> d 0) (str d " d"))
(when (> hr 0) (str hr " hr"))
(when (> min 0) (str min " min"))
(when (> sec 0) (str sec " sec")))))))
(seconds->duration 7259)
(seconds->duration 86400)
(seconds->duration 6000000)
- Output:
"2 hr, 59 sec" "1 d" "9 wk, 6 d, 10 hr, 40 min"
CLU
duration = proc (s: int) returns (string)
own units: array[string] := array[string]$["wk","d","hr","min","sec"]
own sizes: array[int] := array[int]$[2:7,24,60,60]
d: string := ""
r: int
for i: int in int$from_to_by(5,1,-1) do
begin
r := s // sizes[i]
s := s / sizes[i]
end except when bounds:
r := s
end
if r ~= 0 then
d := ", " || int$unparse(r) || " " || units[i] || d
end
end
return(string$rest(d,3))
end duration
start_up = proc ()
po: stream := stream$primary_output()
tests: array[int] := array[int]$[7259,86400,6000000]
for test: int in array[int]$elements(tests) do
stream$putl(po, int$unparse(test) || " => " || duration(test))
end
end start_up
- Output:
7259 => 2 hr, 59 sec 86400 => 1 d 6000000 => 9 wk, 6 d, 10 hr, 40 min
COBOL
identification division.
program-id. fmt-dura.
data division.
working-storage section.
1 input-seconds pic 9(8).
1 formatted-duration pic x(30) global.
1 fractions.
2 weeks pic z(3)9.
2 days pic z(3)9.
2 hours pic z(3)9.
2 minutes pic z(3)9.
2 seconds pic z(3)9.
1 .
2 weeks-str pic x(4) value "wk".
2 days-str pic x(4) value "d".
2 hours-str pic x(4) value "hr".
2 minutes-str pic x(4) value "min".
2 seconds-str pic x(4) value "sec".
1 work binary global.
2 str-pos pic 9(4).
2 chars-transferred pic 9(4).
procedure division.
begin.
display "Enter duration (seconds): " no advancing
accept input-seconds
divide input-seconds by 60 giving input-seconds
remainder seconds
divide input-seconds by 60 giving input-seconds
remainder minutes
divide input-seconds by 24 giving input-seconds
remainder hours
divide input-seconds by 7 giving weeks
remainder days
move 1 to str-pos
call "fmt" using weeks weeks-str
call "fmt" using days days-str
call "fmt" using hours hours-str
call "fmt" using minutes minutes-str
call "fmt" using seconds seconds-str
display formatted-duration
stop run
.
identification division.
program-id. fmt.
data division.
working-storage section.
77 nothing pic x.
linkage section.
1 formatted-value pic x(4).
1 duration-size pic x(4).
procedure division using formatted-value duration-size.
begin.
if function numval (formatted-value) not = 0
perform insert-comma-space
unstring formatted-value delimited all space
into nothing formatted-duration (str-pos:)
count chars-transferred
add chars-transferred to str-pos
string space delimited size
duration-size delimited space
into formatted-duration pointer str-pos
end-if
exit program
.
insert-comma-space.
if str-pos > 1
move ", " to formatted-duration (str-pos:)
add 2 to str-pos
end-if
.
end program fmt.
end program fmt-dura.
Enter duration (seconds): 7259 2 hr, 59 sec Enter duration (seconds): 86400 1 d Enter duration (seconds): 6000000 9 wk, 6 d, 10 hr, 40 min
Common Lisp
(defconstant +seconds-in-minute* 60)
(defconstant +seconds-in-hour* (* 60 +seconds-in-minute*))
(defconstant +seconds-in-day* (* 24 +seconds-in-hour*))
(defconstant +seconds-in-week* (* 7 +seconds-in-day*))
(defun seconds->duration (seconds)
(multiple-value-bind (weeks wk-remainder) (floor seconds +seconds-in-week*)
(multiple-value-bind (days d-remainder) (floor wk-remainder +seconds-in-day*)
(multiple-value-bind (hours hr-remainder) (floor d-remainder +seconds-in-hour*)
(multiple-value-bind (minutes secs) (floor hr-remainder +seconds-in-minute*)
(let ((chunks nil))
(unless (zerop secs) (push (format nil "~D sec" secs) chunks))
(unless (zerop minutes) (push (format nil "~D min" minutes) chunks))
(unless (zerop hours) (push (format nil "~D hr" hours) chunks))
(unless (zerop days) (push (format nil "~D d" days) chunks))
(unless (zerop weeks) (push (format nil "~D wk" weeks) chunks))
(format t "~{~A~^, ~}~%" chunks)))))))
(seconds->duration 7259)
(seconds->duration 86400)
(seconds->duration 6000000)
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
D
import std.stdio, std.conv, std.algorithm;
immutable uint SECSPERWEEK = 604_800;
immutable uint SECSPERDAY = 86_400;
immutable uint SECSPERHOUR = 3_600;
immutable uint SECSPERMIN = 60;
string ConvertSeconds(in uint seconds)
{
uint rem = seconds;
uint weeks = rem / SECSPERWEEK;
rem %= SECSPERWEEK;
uint days = rem / SECSPERDAY;
rem %= SECSPERDAY;
uint hours = rem / SECSPERHOUR;
rem %= SECSPERHOUR;
uint mins = rem / SECSPERMIN;
rem %= SECSPERMIN;
string formatted = "";
(weeks != 0) ? formatted ~= (weeks.to!string ~ " wk, ") : formatted;
(days != 0) ? formatted ~= (days.to!string ~ " d, ") : formatted;
(hours != 0) ? formatted ~= (hours.to!string ~ " hr, ") : formatted;
(mins != 0) ? formatted ~= (mins.to!string ~ " min, ") : formatted;
(rem != 0) ? formatted ~= (rem.to!string ~ " sec") : formatted;
if (formatted.endsWith(", ")) return formatted[0..$-2];
return formatted;
}
void main()
{
7_259.ConvertSeconds.writeln;
86_400.ConvertSeconds.writeln;
6_000_000.ConvertSeconds.writeln;
}
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Delphi
const TestData: array [0..2] of integer = (7259,86400,6000000);
function SecondsToFormatDate(Sec: integer): string;
var DT: TDateTime;
var Weeks: integer;
var AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word;
const SecPerDay = 60 * 60 * 24;
begin
{Convert seconds to Delphi TDateTime}
{which is floating point days}
DT:=Sec / SecPerDay;
{Get weeks and subtract them off}
Weeks:=Trunc(DT/7);
DT:=DT - Weeks * 7;
{Decode date}
DecodeDateTime(DT,AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond);
{Compensate because TDateTime starts on Dec 30th 1899}
if aDay<30 then aDay:=aDay + 1 else aDay:=aDay - 30;
Result:='';
if Weeks<>0 then Result:=Result+IntToStr(Weeks)+' wk, ';
if ADay<>0 then Result:=Result+IntToStr(ADay)+' d, ';
if AHour<>0 then Result:=Result+IntToStr(AHour)+' hr, ';
if AMinute<>0 then Result:=Result+IntToStr(AMinute)+' min, ';
if ASecond<>0 then Result:=Result+IntToStr(ASecond)+' sec, ';
end;
procedure ShowFormatedDataTime(Memo: TMemo);
var I: integer;
begin
for I:=0 to High(TestData) do
Memo.Lines.Add(IntToStr(TestData[I])+' = '+SecondsToFormatDate(TestData[I]));
end;
- Output:
7259 = 2 hr, 59 sec, 86400 = 1 d, 6000000 = 9 wk, 6 d, 10 hr, 40 min, Elapsed Time: 2.900 ms.
EasyLang
func$ split sec .
divs[] = [ 60 60 24 7 ]
n$[] = [ "sec" "min" "hr" "d" "wk" ]
len r[] 5
for i = 1 to 4
r[i] = sec mod divs[i]
sec = sec div divs[i]
.
r[5] = sec
for i = 5 downto 1
if r[i] <> 0
if s$ <> ""
s$ &= ", "
.
s$ &= r[i] & " " & n$[i]
.
.
return s$
.
print split 7259
print split 86400
print split 6000000
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Elixir
defmodule Convert do
@minute 60
@hour @minute*60
@day @hour*24
@week @day*7
@divisor [@week, @day, @hour, @minute, 1]
def sec_to_str(sec) do
{_, [s, m, h, d, w]} =
Enum.reduce(@divisor, {sec,[]}, fn divisor,{n,acc} ->
{rem(n,divisor), [div(n,divisor) | acc]}
end)
["#{w} wk", "#{d} d", "#{h} hr", "#{m} min", "#{s} sec"]
|> Enum.reject(fn str -> String.starts_with?(str, "0") end)
|> Enum.join(", ")
end
end
Enum.each([7259, 86400, 6000000], fn sec ->
:io.fwrite "~10w sec : ~s~n", [sec, Convert.sec_to_str(sec)]
end)
- Output:
7259 sec : 2 hr, 59 sec 86400 sec : 1 d 6000000 sec : 9 wk, 6 d, 10 hr, 40 min
Erlang
Function mapaccumr/3 is adapted from here.
Function intercalate/2 is copied from a Tim Fletcher's GitHub repository.
-module(convert_seconds).
-export([test/0]).
test() ->
lists:map(fun convert/1, [7259, 86400, 6000000]),
ok.
convert(Seconds) ->
io:format(
"~7s seconds = ~s\n",
[integer_to_list(Seconds), compoundDuration(Seconds)] ).
% Compound duration of t seconds. The argument is assumed to be positive.
compoundDuration(Seconds) ->
intercalate(
", ",
lists:map(
fun({D,L}) -> io_lib:format("~p ~s",[D, L]) end,
compdurs(Seconds) ) ).
% Time broken down into non-zero durations and their labels.
compdurs(T) ->
Ds =
reduceBy(
T,
lists:map(
fun(Dl) -> element(1,Dl) end,
tl(durLabs()) ) ),
lists:filter(
fun(Dl) -> element(1,Dl) /= 0 end,
lists:zip(
Ds,
lists:map(
fun(Dl) -> element(2,Dl) end,
durLabs() ) ) ).
% Duration/label pairs.
durLabs() ->
[
{undefined, "wk"},
{7, "d"},
{24, "hr"},
{60, "min"},
{60, "sec"}
].
reduceBy(N, Xs) ->
{N_, Ys} = mapaccumr(fun quotRem/2, N, Xs),
[N_ | Ys].
quotRem(X1, X2) ->
{X1 div X2, X1 rem X2}.
% **************************************************
% Adapted from http://lpaste.net/edit/47875
% **************************************************
mapaccuml(_,I,[]) ->
{I, []};
mapaccuml(F,I,[H|T]) ->
{Accum, NH} = F(I,H),
{FAccum, NT} = mapaccuml(F,Accum,T),
{FAccum, [NH | NT]}.
mapaccumr(_,I,[]) ->
{I, []};
mapaccumr(F,I,L) ->
{Acc, Ys} = mapaccuml(F,I,lists:reverse(L)),
{Acc, lists:reverse(Ys)}.
% **************************************************
% **************************************************
% Copied from https://github.com/tim/erlang-oauth/blob/master/src/oauth.erl
% **************************************************
intercalate(Sep, Xs) ->
lists:concat(intersperse(Sep, Xs)).
intersperse(_, []) ->
[];
intersperse(_, [X]) ->
[X];
intersperse(Sep, [X | Xs]) ->
[X, Sep | intersperse(Sep, Xs)].
% **************************************************
Output:
7259 seconds = 2 hr, 59 sec 86400 seconds = 1 d 6000000 seconds = 9 wk, 6 d, 10 hr, 40 min
F#
open System
let convert seconds =
let span = TimeSpan.FromSeconds(seconds |> float)
let (wk, day) = Math.DivRem(span.Days, 7)
let parts =
[(wk, "wk"); (day, "day"); (span.Hours, "hr"); (span.Minutes, "min"); (span.Seconds, "sec")]
let result =
List.foldBack (fun (n, u) acc ->
(if n > 0 then n.ToString() + " " + u else "")
+ (if n > 0 && acc.Length > 0 then ", " else "")
+ acc
) parts ""
if result.Length > 0 then result else "0 sec"
[<EntryPoint>]
let main argv =
argv
|> Seq.map (fun str -> let sec = UInt32.Parse str in (sec, convert sec))
|> Seq.iter (fun (s, v) -> printfn "%10i = %s" s v)
0
- Output:
>RosettaCode 7259 86400 6000000 7259 = 2 hr, 59 sec 86400 = 1 day 6000000 = 9 wk, 6 day, 10 hr, 40 min
Factor
USING: assocs io kernel math math.parser qw sequences
sequences.generalizations ;
: mod/ ( x y -- w z ) /mod swap ;
: convert ( n -- seq )
60 mod/ 60 mod/ 24 mod/ 7 mod/ 5 narray reverse ;
: .time ( n -- )
convert [ number>string ] map qw{ wk d hr min sec } zip
[ first "0" = ] reject [ " " join ] map ", " join print ;
7259 86400 6000000 [ .time ] tri@
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Forth
CREATE C 0 ,
: ., C @ IF ." , " THEN 1 C ! ;
: .TIME ( n --)
[ 60 60 24 7 * * * ]L /MOD ?DUP-IF ., . ." wk" THEN
[ 60 60 24 * * ]L /MOD ?DUP-IF ., . ." d" THEN
[ 60 60 * ]L /MOD ?DUP-IF ., . ." hr" THEN
[ 60 ]L /MOD ?DUP-IF ., . ." min" THEN
?DUP-IF ., . ." sec" THEN 0 C ! ;
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Fortran
If the PARAMETER statements were replaced (say with suitable DATA statements) then this could be compiled with Fortran 77, if a find-last-non-blank function were to be supplied and a supplementary scratchpad used so that the numbers could be placed without leading spaces (thus "9" and "10", not " 9") because the I0 format specifier is a F90 facility. Earlier Fortran compilers lacking a CHARACTER variable would present further difficulty.
If the time to describe was not an integer but a floating-point value with fractional parts, then there is a complication. The number of seconds can be less than sixty, but, on output, 60 seconds can appear. If the number of seconds was to be written with one decimal digit (say) and the output format was F4.1 for that, then if the value was 59·95 or more, it will be rounded up for output, in this example to 60·0. Various systems make this mistake, as also with latitude and longitude, and it is a general problem. A fixup pass is necessary before generating the output: maintain an array with the integer values of the various units, then (for one decimal digit usage) check that the seconds part is less than 59·95. If not, set it to zero and augment the minutes count. If this is 60 or more, set it to zero and augment the hours count, and so on. Thus the array.
SUBROUTINE PROUST(T) !Remembrance of time passed.
INTEGER T !The time, in seconds. Positive only, please.
INTEGER NTYPES !How many types of time?
PARAMETER (NTYPES = 5) !This should do.
INTEGER USIZE(NTYPES) !Size of the time unit.
CHARACTER*3 UNAME(NTYPES)!Name of the time unit.
PARAMETER (USIZE = (/7*24*60*60, 24*60*60, 60*60, 60, 1/)) !The compiler does some arithmetic.
PARAMETER (UNAME = (/ "wk", "d", "hr","min","sec"/)) !Approved names, with trailing spaces.
CHARACTER*28 TEXT !A scratchpad.
INTEGER I,L,N,S !Assistants.
S = T !A copy I can mess with.
L = 0 !No text has been generated.
DO I = 1,NTYPES !Step through the types to do so.
N = S/USIZE(I) !Largest first.
IF (N.GT.0) THEN !Above the waterline?
S = S - N*USIZE(I) !Yes! Remove its contribution.
IF (L.GT.0) THEN !Is this the first text to be rolled?
L = L + 2 !No.
TEXT(L - 1:L) = ", " !Cough forth some punctuation.
END IF !Now ready for this count.
WRITE (TEXT(L + 1:),1) N,UNAME(I) !Place, with the unit name.
1 FORMAT (I0,1X,A) !I0 means I only: variable-length, no leading spaces.
L = LEN_TRIM(TEXT) !Find the last non-blank resulting.
END IF !Since I'm not keeping track.
END DO !On to the next unit.
Cast forth the result.
WRITE (6,*) T,">",TEXT(1:L),"<" !With annotation.
END !Simple enough with integers.
PROGRAM MARCEL !Stir the cup.
CALL PROUST(7259)
CALL PROUST(7260)
CALL PROUST(86400)
CALL PROUST(6000000)
CALL PROUST(0)
CALL PROUST(-666)
END
Output:
7259 >2 hr, 59 sec< 7260 >2 hr, 1 min< 86400 >1 d< 6000000 >9 wk, 6 d, 10 hr, 40 min< 0 >< -666 ><
FreeBASIC
'FreeBASIC version 1.05 32/64 bit
Sub Show(m As Long)
Dim As Long c(1 To 5)={604800,86400,3600,60,1}
Dim As String g(1 To 5)={" Wk"," d"," hr"," min"," sec"},comma
Dim As Long b(1 To 5),flag,m2=m
Redim As Long s(0)
For n As Long=1 To 5
If m>=c(n) Then
Do
Redim Preserve s(Ubound(s)+1)
s(Ubound(s))=c(n)
m=m-c(n)
Loop Until m<c(n)
End If
Next n
For n As Long=1 To Ubound(s)
For m As Long=1 To 5
If s(n)=c(m) Then b(m)+=1
Next m
Next n
Print m2;" seconds = ";
For n As Long=1 To 5
If b(n) Then: comma=Iif(n<5 Andalso b(n+1),","," and"):flag+=1
If flag=1 Then comma=""
Print comma;b(n);g(n);
End If
Next
Print
End Sub
#define seconds
Show 7259 seconds
Show 86400 seconds
Show 6000000 seconds
sleep
Output:
7259 seconds = 2 hr and 59 sec 86400 seconds = 1 d 6000000 seconds = 9 Wk, 6 d, 10 hr and 40 min
Frink
Frink's ->
operator can break a unit of measure into its constituent parts. However, it does not suppress zero-valued elements unless they are at the beginning or the end, so we have to do that manually.
wk := week
n = eval[input["Enter duration in seconds: "]]
res = n s -> [0, "wk", "d", "hr", "min", "sec", 0]
res =~ %s/, 0[^,]+//g
println[res]
FutureBasic
include "NSLog.incl"
local fn CompoundDurationString( seconds as long ) as CFStringRef
long s = 1, m = s * 60, h = m * 60, d = h * 24, w = d * 7
long v(4) : v(0) = w : v(1) = d : v(2) = h : v(3) = m : v(4) = s
long i, value
CFArrayRef abbr = @[@"wk",@"d",@"hr",@"min",@"sec"]
CFMutableStringRef string = fn MutableStringWithCapacity(0)
for i = 0 to 4
value = seconds / v(i)
seconds = seconds mod v(i)
if ( value )
if ( len(string) ) then MutableStringAppendString( string, @", " )
MutableStringAppendFormat( string, @"%ld %@", value, abbr[i] )
end if
next
end fn = string
NSLog(@"%@",fn CompoundDurationString(7259))
NSLog(@"%@",fn CompoundDurationString(86400))
NSLog(@"%@",fn CompoundDurationString(6000000))
HandleEvents
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Gambas
Click this link to run this code
Public Sub Main()
Dim iInput As Integer[] = [7259, 86400, 6000000] 'Input details
Dim iChecks As Integer[] = [604800, 86400, 3600, 60] 'Weeks, days, hours, mins in seconds
Dim iTime As New Integer[5] 'To store wk, d, hr, min & sec
Dim iOriginal, iSec, iLoop As Integer 'Various integers
Dim sOrd As String[] = [" wk", " d", " hr", " min", " sec"] 'To add to the output string
Dim sOutput As String 'Output string
For Each iSec In iInput 'For each iInput
iOriginal = iSec 'Store orginal value in seconds
iTime[4] = iSec 'Store seconds in iTime[4]
For iLoop = 0 To 3 'Loop through wk, d, hr, min & sec
If iTime[4] >= iChecks[iLoop] Then 'Check if value is = to wk, d, hr, min
iTime[iLoop] = Int(iTime[4] / iChecks[iLoop]) 'Put the correct value for wk, d, hr, min in iTime
iTime[4] = iTime[4] - (iTime[iLoop] * iChecks[iLoop]) 'Remove the amount of seconds for wk, d, hr, min from iTime[4]
Endif
Next
For iLoop = 0 To 4 'Loop through wk, d, hr, min & secs
If iTime[iLoop] > 0 Then sOutput &= ", " & Str(iTime[iLoop]) & sOrd[iLoop] 'Add comma and ordinal as needed
Next
If Left(sOutput, 2) = ", " Then sOutput = Mid(sOutput, 3) 'Remove unnecessary ", "
sOutput = Format(Str(iOriginal), "#######") & " Seconds = " & sOutput 'Add original seconds to the output string
Print sOutput 'Print sOutput string
sOutput = "" 'Clear the sOutput string
iTime = New Integer[5] 'Reset iTime[]
Next
End
Output:
7259 Seconds = 2 hr, 59 sec 86400 Seconds = 1 d 6000000 Seconds = 9 wk, 6 d, 10 hr, 40 min
Go
package main
import "fmt"
func main(){
fmt.Println(TimeStr(7259))
fmt.Println(TimeStr(86400))
fmt.Println(TimeStr(6000000))
}
func TimeStr(sec int)(res string){
wks, sec := sec / 604800,sec % 604800
ds, sec := sec / 86400, sec % 86400
hrs, sec := sec / 3600, sec % 3600
mins, sec := sec / 60, sec % 60
CommaRequired := false
if wks != 0 {
res += fmt.Sprintf("%d wk",wks)
CommaRequired = true
}
if ds != 0 {
if CommaRequired {
res += ", "
}
res += fmt.Sprintf("%d d",ds)
CommaRequired = true
}
if hrs != 0 {
if CommaRequired {
res += ", "
}
res += fmt.Sprintf("%d hr",hrs)
CommaRequired = true
}
if mins != 0 {
if CommaRequired {
res += ", "
}
res += fmt.Sprintf("%d min",mins)
CommaRequired = true
}
if sec != 0 {
if CommaRequired {
res += ", "
}
res += fmt.Sprintf("%d sec",sec)
}
return
}
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Haskell
import Control.Monad (forM_)
import Data.List (intercalate, mapAccumR)
import System.Environment (getArgs)
import Text.Printf (printf)
import Text.Read (readMaybe)
reduceBy :: Integral a => a -> [a] -> [a]
n `reduceBy` xs = n' : ys where (n', ys) = mapAccumR quotRem n xs
-- Duration/label pairs.
durLabs :: [(Integer, String)]
durLabs = [(undefined, "wk"), (7, "d"), (24, "hr"), (60, "min"), (60, "sec")]
-- Time broken down into non-zero durations and their labels.
compdurs :: Integer -> [(Integer, String)]
compdurs t = let ds = t `reduceBy` (map fst $ tail durLabs)
in filter ((/=0) . fst) $ zip ds (map snd durLabs)
-- Compound duration of t seconds. The argument is assumed to be positive.
compoundDuration :: Integer -> String
compoundDuration = intercalate ", " . map (uncurry $ printf "%d %s") . compdurs
main :: IO ()
main = do
args <- getArgs
forM_ args $ \arg -> case readMaybe arg of
Just n -> printf "%7d seconds = %s\n" n (compoundDuration n)
Nothing -> putStrLn $ "Invalid number of seconds: " ++ arg
- Output:
7259 seconds = 2 hr, 59 sec 86400 seconds = 1 d 6000000 seconds = 9 wk, 6 d, 10 hr, 40 min
Or, parameterising both the local names for these durations, and also the working assumptions about hours per day, and days per week:
import Data.List (intercalate, mapAccumR)
---------------- COMPOUND DURATION STRINGS ---------------
durationString ::
String ->
String ->
Int ->
Int ->
[String] ->
Int ->
String
durationString
componentGap
numberLabelGap
daysPerWeek
hoursPerDay
xs
n =
intercalate
componentGap
( foldr
(timeTags numberLabelGap)
[]
(zip (weekParts daysPerWeek hoursPerDay n) xs)
)
timeTags :: String -> (Int, String) -> [String] -> [String]
timeTags numberLabelGap (n, s) xs
| 0 < n = intercalate numberLabelGap [show n, s] : xs
| otherwise = xs
weekParts :: Int -> Int -> Int -> [Int]
weekParts daysPerWeek hoursPerDay =
snd
. flip
(mapAccumR byUnits)
[0, daysPerWeek, hoursPerDay, 60, 60]
byUnits :: Int -> Int -> (Int, Int)
byUnits rest x = (quot (rest - m) u, m)
where
(u, m)
| 0 < x = (x, rem rest x)
| otherwise = (1, rest)
--------------------------- TEST -------------------------
translation :: String -> Int -> Int -> Int -> String
translation local daysPerWeek hoursPerDay n =
intercalate " -> " $
[ show,
durationString
", "
" "
daysPerWeek
hoursPerDay
(words local)
]
<*> [n]
main :: IO ()
main = do
let names = "wk d hr min sec"
let tests = [7259, 86400, 6000000]
putStrLn "Assuming 24 hrs per day:"
mapM_ (putStrLn . translation names 7 24) tests
putStrLn "\nor, at 8 hours per day, 5 days per week:"
mapM_ (putStrLn . translation names 5 8) tests
- Output:
Assuming 24/7: 7259 -> 2 hr, 59 sec 86400 -> 1 d 6000000 -> 9 wk, 6 d, 10 hr, 40 min or, at 8 working hours per day, 5 days per week: 7259 -> 2 hr, 59 sec 86400 -> 3 d 6000000 -> 41 wk, 3 d, 2 hr, 40 min
J
Implementation:
fmtsecs=: verb define
seq=. 0 7 24 60 60 #: y
}: ;:inv ,(0 ~: seq) # (8!:0 seq) ,. <;.2'wk,d,hr,min,sec,'
)
The first line uses integer division with remainder to break the value in seconds into its components (weeks, days, hours, minutes, seconds).
The second line gives each value a label and a trailing comma, drops the parts which have a zero, combines the rest and then removes the trailing comma from the end of the resulting line.
Task examples:
fmtsecs 7259
2 hr, 59 sec
fmtsecs 86400
1 d
fmtsecs 6000000
9 wk, 6 d, 10 hr, 40 min
Jakt
fn main() {
for seconds in [
7259
86400
6000000
] {
println("{}", time_string(seconds))
}
}
fn time_string(mut seconds: i64) throws -> String {
mut result = ""
mut minutes = seconds / 60
seconds %= 60
if seconds > 0 {
result = format("{} sec", seconds, result)
}
mut hours = minutes / 60
minutes %= 60
if minutes > 0 {
result = format(match result {
"" => "{} min"
else => "{} min, {}"
}, minutes, result)
}
mut days = hours / 24
hours %= 24
if hours > 0 {
result = format(match result {
"" => "{} hr"
else => "{} hr, {}"
}, hours, result)
}
mut weeks = days / 7
days %= 7
if days > 0 {
result = format(match result {
"" => "{} d"
else => "{} d, {}"
}, days, result)
}
if weeks > 0 {
result = format(match result {
"" => "{} wk"
else => "{} wk, {}"
}, weeks, result)
}
return result
}
Java
This is a relatively simple task in Java, using the modulus-remainder operator.
String duration(int seconds) {
StringBuilder string = new StringBuilder();
if (seconds >= 604_800 /* 1 wk */) {
string.append("%,d wk".formatted(seconds / 604_800));
seconds %= 604_800;
}
if (seconds >= 86_400 /* 1 d */) {
if (!string.isEmpty()) string.append(", ");
string.append("%d d".formatted(seconds / 86_400));
seconds %= 86_400;
}
if (seconds >= 3600 /* 1 hr */) {
if (!string.isEmpty()) string.append(", ");
string.append("%d hr".formatted(seconds / 3600));
seconds %= 3600;
}
if (seconds >= 60 /* 1 min */) {
if (!string.isEmpty()) string.append(", ");
string.append("%d min".formatted(seconds / 60));
seconds %= 60;
}
if (seconds > 0) {
if (!string.isEmpty()) string.append(", ");
string.append("%d sec".formatted(seconds));
}
return string.toString();
}
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
An alternate demonstration
public class CompoundDuration {
public static void main(String[] args) {
compound(7259);
compound(86400);
compound(6000_000);
}
private static void compound(long seconds) {
StringBuilder sb = new StringBuilder();
seconds = addUnit(sb, seconds, 604800, " wk, ");
seconds = addUnit(sb, seconds, 86400, " d, ");
seconds = addUnit(sb, seconds, 3600, " hr, ");
seconds = addUnit(sb, seconds, 60, " min, ");
addUnit(sb, seconds, 1, " sec, ");
sb.setLength(sb.length() > 2 ? sb.length() - 2 : 0);
System.out.println(sb);
}
private static long addUnit(StringBuilder sb, long sec, long unit, String s) {
long n;
if ((n = sec / unit) > 0) {
sb.append(n).append(s);
sec %= (n * unit);
}
return sec;
}
}
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
JavaScript
Functional
ES5
(function () {
'use strict';
// angloDuration :: Int -> String
function angloDuration(intSeconds) {
return zip(
weekParts(intSeconds),
['wk', 'd', 'hr', 'min','sec']
)
.reduce(function (a, x) {
return a.concat(x[0] ? (
[(x[0].toString() + ' ' + x[1])]
) : []);
}, [])
.join(', ');
}
// weekParts :: Int -> [Int]
function weekParts(intSeconds) {
return [undefined, 7, 24, 60, 60]
.reduceRight(function (a, x) {
var intRest = a.remaining,
intMod = isNaN(x) ? intRest : intRest % x;
return {
remaining:(intRest - intMod) / (x || 1),
parts: [intMod].concat(a.parts)
};
}, {
remaining: intSeconds,
parts: []
})
.parts
}
// GENERIC ZIP
// zip :: [a] -> [b] -> [(a,b)]
function zip(xs, ys) {
return xs.length === ys.length ? (
xs.map(function (x, i) {
return [x, ys[i]];
})
) : undefined;
}
// TEST
return [7259, 86400, 6000000]
.map(function (intSeconds) {
return intSeconds.toString() +
' -> ' + angloDuration(intSeconds);
})
.join('\n');
})();
- Output:
7259 -> 2 hr, 59 sec 86400 -> 1 d 6000000 -> 9 wk, 6 d, 10 hr, 40 min
ES6
(() => {
"use strict";
// ---------------- COMPOUND DURATION ----------------
// compoundDuration :: [String] -> Int -> String
const compoundDuration = labels =>
nSeconds => weekParts(nSeconds)
.map((v, i) => [v, labels[i]])
.reduce((a, x) =>
a.concat(
x[0] ? [
`${x[0]} ${x[1] || "?"}`
] : []
), []
)
.join(", ");
// weekParts :: Int -> [Int]
const weekParts = nSeconds => [0, 7, 24, 60, 60]
.reduceRight((a, x) => {
const
r = a[0],
mod = x !== 0 ? r % x : r;
return [
(r - mod) / (x || 1),
[mod, ...a[1]]
];
}, [nSeconds, []])[1];
// ---------------------- TEST -----------------------
// main :: IO ()
const main = () => {
const localNames = ["wk", "d", "hr", "min", "sec"];
return [7259, 86400, 6E6]
.map(nSeconds =>
`${nSeconds} -> ${
compoundDuration(localNames)(nSeconds)
}`).join("\n");
};
// MAIN ---
return main();
})();
- Output:
7259 -> 2 hr, 59 sec 86400 -> 1 d 6000000 -> 9 wk, 6 d, 10 hr, 40 min
jq
Also works with gojq, the Go implementation
def seconds_to_time_string:
def nonzero(text): floor | if . > 0 then "\(.) \(text)" else empty end;
if . == 0 then "0 sec"
else
[(./60/60/24/7 | nonzero("wk")),
(./60/60/24 % 7 | nonzero("d")),
(./60/60 % 24 | nonzero("hr")),
(./60 % 60 | nonzero("min")),
(. % 60 | nonzero("sec"))]
| join(", ")
end;
Examples':
0, 7259, 86400, 6000000 | "\(.): \(seconds_to_time_string)"
- Output:
$ jq -r -n -f Convert_seconds_to_compound_duration.jq
0: 0 sec
7259: 2 hr, 59 sec
86400: 1 d
6000000: 9 wk, 6 d, 10 hr, 40 min
Julia
# 1.x
function duration(sec::Integer)::String
t = Array{Int}([])
for dm in (60, 60, 24, 7)
sec, m = divrem(sec, dm)
pushfirst!(t, m)
end
pushfirst!(t, sec)
return join(["$num$unit" for (num, unit) in zip(t, ["w", "d", "h", "m", "s"]) if num > 0], ", ")
end
@show duration(7259)
@show duration(86400)
@show duration(6000000)
- Output:
duration(7259) = "2h, 59s" duration(86400) = "1d" duration(6000000) = "9w, 6d, 10h, 40m"
K
F:{", "/" "/'+($x[s]),s:,&0<x}(" "\"wk d hr min sec")!0 7 24 60 60\
Examples:
F 100
"1 min, 40 sec"
F 7259
"2 hr, 59 sec"
F 86400
"1 d"
F 6000000
"9 wk, 6 d, 10 hr, 40 min"
tested in ngn/k
Kotlin
fun compoundDuration(n: Int): String {
if (n < 0) return "" // task doesn't ask for negative integers to be converted
if (n == 0) return "0 sec"
val weeks : Int
val days : Int
val hours : Int
val minutes: Int
val seconds: Int
var divisor: Int = 7 * 24 * 60 * 60
var rem : Int
var result = ""
weeks = n / divisor
rem = n % divisor
divisor /= 7
days = rem / divisor
rem %= divisor
divisor /= 24
hours = rem / divisor
rem %= divisor
divisor /= 60
minutes = rem / divisor
seconds = rem % divisor
if (weeks > 0) result += "$weeks wk, "
if (days > 0) result += "$days d, "
if (hours > 0) result += "$hours hr, "
if (minutes > 0) result += "$minutes min, "
if (seconds > 0)
result += "$seconds sec"
else
result = result.substring(0, result.length - 2)
return result
}
fun main(args: Array<String>) {
val durations = intArrayOf(0, 7, 84, 7259, 86400, 6000000)
durations.forEach { println("$it\t-> ${compoundDuration(it)}") }
}
- Output:
0 -> 0 sec 7 -> 7 sec 84 -> 1 min, 24 sec 7259 -> 2 hr, 59 sec 86400 -> 1 d 6000000 -> 9 wk, 6 d, 10 hr, 40 min
langur
val d = fn(var sec) {
[
fw/wk d hr min sec/,
for[=[]] dm in [7 * 24 * 60 * 60, 24 * 60 * 60, 60 * 60, 60] {
_for ~= [sec \ dm]
sec rem= dm
} ~ [sec],
]
}
for seconds in [7259, 86400, 6000000] {
val dur = d(seconds)
write "{{seconds:7}} sec = "
writeln join(", ", for[=[]] k of dur[1] {
if dur[2][k] != 0: _for ~= ["{{dur[2][k]}} {{dur[1][k]}}"]
})
}
- Output:
7259 sec = 2 hr, 59 sec 86400 sec = 1 d 6000000 sec = 9 wk, 6 d, 10 hr, 40 min
You could also convert nanoseconds to a langur duration. Langur durations use a separate count for years, months, days, hours, minutes, seconds, and nanoseconds. A "month" and a "year" are difficult to define in terms of seconds, which is one of the reasons langur has a duration type.
Liberty BASIC
I got a bit carried away and added 'years'...
[start]
input "Enter SECONDS: "; seconds
seconds=int(abs(seconds))
if seconds=0 then print "Program complete.": end
UnitsFound=0: LastFound$=""
years=int(seconds/31449600): seconds=seconds mod 31449600
if years then LastFound$="years"
weeks=int(seconds/604800): seconds=seconds mod 604800
if weeks then LastFound$="weeks"
days=int(seconds/86400): seconds=seconds mod 86400
if days then LastFound$="days"
hours=int(seconds/3600): seconds=seconds mod 3600
if hours then LastFound$="hours"
minutes=int(seconds/60): seconds=seconds mod 60
if minutes then LastFound$="minutes"
if seconds then LastFound$="seconds"
select case years
case 0
case 1: print years; " year";
case else: print years; " years";
end select
select case weeks
case 0
case 1
if years then
if LastFound$="weeks" then print " and "; else print ", ";
end if
print weeks; " week";
case else
if years then
if LastFound$="weeks" then print " and "; else print ", ";
end if
print weeks; " weeks";
end select
select case days
case 0
case 1
if years or weeks then
if LastFound$="days" then print " and "; else print ", ";
end if
print days; " day";
case else
if years or weeks then
if LastFound$="days" then print " and "; else print ", ";
end if
print days; " days";
end select
select case hours
case 0
case 1
if years or weeks or days then
if LastFound$="hours" then print " and "; else print ", ";
end if
print hours; " hour";
case else
if years or weeks or days then
if LastFound$="hours" then print " and "; else print ", ";
end if
print hours; " hours";
end select
select case minutes
case 0
case 1
if years or weeks or days or hours then
if LastFound$="minutes" then print " and "; else print ", ";
end if
print minutes; " minute";
case else
if years or weeks or days or hours then
if LastFound$="minutes" then print " and "; else print ", ";
end if
print minutes; " minutes";
end select
select case seconds
case 0
case 1
if years or weeks or days or hours or minutes then
if LastFound$="seconds" then print " and "; else print ", ";
end if
print seconds; " second";
case else
if years or weeks or days or hours or minutes then
if LastFound$="seconds" then print " and "; else print ", ";
end if
print seconds; " seconds";
end select
print
goto [start]
- Output:
Enter SECONDS: 7259 2 hours and 59 seconds Enter SECONDS: 86400 1 day Enter SECONDS: 6000000 9 weeks, 6 days, 10 hours and 40 minutes Enter SECONDS: 987654321 31 years, 21 weeks, 4 hours, 25 minutes and 21 seconds Enter SECONDS: Program complete.
Lua
function duration (secs)
local units, dur = {"wk", "d", "hr", "min"}, ""
for i, v in ipairs({604800, 86400, 3600, 60}) do
if secs >= v then
dur = dur .. math.floor(secs / v) .. " " .. units[i] .. ", "
secs = secs % v
end
end
if secs == 0 then
return dur:sub(1, -3)
else
return dur .. secs .. " sec"
end
end
print(duration(7259))
print(duration(86400))
print(duration(6000000))
Maple
tim := proc (s) local weeks, days, hours, minutes, seconds;
weeks := trunc((1/604800)*s);
days := trunc((1/86400)*s)-7*weeks;
hours := trunc((1/3600)*s)-24*days-168*weeks;
minutes := trunc((1/60)*s)-60*hours-1440*days-10080*weeks;
seconds := s-60*minutes-3600*hours-86400*days-604800*weeks;
printf("%s", cat(`if`(0 < weeks, cat(weeks, "wk, "), NULL), `if`(0 < days, cat(days, "d, "), NULL), `if`(0 < hours, cat(hours, "hr, "), NULL), `if`(0 < minutes, cat(minutes, "min, "), NULL), `if`(0 < seconds, cat(seconds, "sec"), NULL)))
end proc;
Mathematica /Wolfram Language
compoundDuration[x_Integer] :=
StringJoin @@ (Riffle[
ToString /@ ((({Floor[x/604800],
Mod[x, 604800]} /. {a_, b_} -> {a, Floor[b/86400],
Mod[b, 86400]}) /. {a__, b_} -> {a, Floor[b/3600],
Mod[b, 3600]}) /. {a__, b_} -> {a, Floor[b/60],
Mod[b, 60]}), {" wk, ", " d, ", " hr, ", " min, ",
" sec"}] //. {a___, "0", b_, c___} -> {a, c})
Grid[Table[{n, "secs =",
compoundDuration[n]}, {n, {7259, 86400, 6000000}}],
Alignment -> {Left, Baseline}]
- Output:
7259 secs = 2 hr, 59 sec 86400 secs = 1 d, 6000000 secs = 9 wk, 6 d, 10 hr, 40 min,
Nim
from strutils import addSep
const
Units = [" wk", " d", " hr", " min", " sec"]
Quantities = [7 * 24 * 60 * 60, 24 * 60 * 60, 60 * 60, 60, 1]
#---------------------------------------------------------------------------------------------------
proc `$$`*(sec: int): string =
## Convert a duration in seconds to a friendly string.
doAssert(sec > 0)
var duration = sec
var idx = 0
while duration != 0:
let q = duration div Quantities[idx]
if q != 0:
duration = duration mod Quantities[idx]
result.addSep(", ", 0)
result.add($q & Units[idx])
inc idx
#———————————————————————————————————————————————————————————————————————————————————————————————————
when isMainModule:
for sec in [7259, 86400, 6000000]:
echo sec, "s = ", $$sec
- Output:
7259s = 2 hr, 59 sec 86400s = 1 d 6000000s = 9 wk, 6 d, 10 hr, 40 min
Using the “times” module
It is also possible to use the Duration type in the “times” module and the procedure “toParts” which decomposes a duration in units of time (nanoseconds, microseconds, milliseconds, seconds, minutes, hours, days and weeks).
import times
from algorithm import reversed
from strutils import addSep
const Units = [" wk", " d", " hr", " min", " sec"]
#---------------------------------------------------------------------------------------------------
proc `$$`*(sec: int): string =
## Convert a duration in seconds to a friendly string.
## Similar to `$` but with other conventions.
doAssert(sec > 0)
var duration = initDuration(seconds = sec)
let parts = reversed(duration.toParts[Seconds..Weeks])
for idx, part in parts:
if part != 0:
result.addSep(", ", 0)
result.add($part & Units[idx])
#———————————————————————————————————————————————————————————————————————————————————————————————————
when isMainModule:
for sec in [7259, 86400, 6000000]:
echo sec, "s = ", $$sec
- Output:
Output is the same.
OCaml
let divisors = [
(max_int, "wk"); (* many wk = many wk *)
(7, "d"); (* 7 d = 1 wk *)
(24, "hr"); (* 24 hr = 1 d *)
(60, "min"); (* 60 min = 1 hr *)
(60, "sec") (* 60 sec = 1 min *)
]
(* Convert a number of seconds into a list of values for weeks, days, hours,
* minutes and seconds, by dividing the number of seconds 'secs' successively by
* the values contained in the list 'divisors' (taking them in reverse order).
* Ex:
* compute_duration 7259
* returns
* [(0, "wk"); (0, "d"); (2, "hr") (0, "min"); (59, "sec")]
*)
let compute_duration secs =
let rec doloop remain res = function
| [] -> res
| (n, s) :: ds -> doloop (remain / n) ((remain mod n, s) :: res) ds
in
doloop secs [] (List.rev divisors)
(* Format nicely the list of values.
* Ex:
* pretty_print [(0, "wk"); (0, "d"); (2, "hr") (0, "min"); (59, "sec")]
* returns
* "2 hr, 59 sec"
*
* Intermediate steps:
* 1. Keep only the pairs where duration is not 0
* [(2, "hr"); (59, "sec")]
* 2. Format each pair as a string
* ["2 hr"; "59 sec"]
* 3. Concatenate the strings separating them by a comma+space
* "2 hr, 59 sec"
*)
let pretty_print dur =
List.filter (fun (d, _) -> d <> 0) dur
|> List.map (fun (d, l) -> Printf.sprintf "%d %s" d l)
|> String.concat ", "
(* Transform a number of seconds into the corresponding compound duration
* string.
* Not sure what to do with 0... *)
let compound = function
| n when n > 0 -> compute_duration n |> pretty_print
| n when n = 0 -> string_of_int 0 ^ "..."
| _ -> invalid_arg "Number of seconds must be positive"
(* Some testing... *)
let () =
let test_cases = [
(7259, "2 hr, 59 sec");
(86400, "1 d");
(6000000, "9 wk, 6 d, 10 hr, 40 min");
(0, "0...");
(3599, "59 min, 59 sec");
(3600, "1 hr");
(3601, "1 hr, 1 sec")
] in
let testit (n, s) =
let calc = compound n in
Printf.printf "[%s] %d seconds -> %s; expected: %s\n"
(if calc = s then "PASS" else "FAIL")
n calc s
in
List.iter testit test_cases
- Output:
[PASS] 7259 seconds -> 2 hr, 59 sec; expected: 2 hr, 59 sec [PASS] 86400 seconds -> 1 d; expected: 1 d [PASS] 6000000 seconds -> 9 wk, 6 d, 10 hr, 40 min; expected: 9 wk, 6 d, 10 hr, 40 min [PASS] 0 seconds -> 0...; expected: 0... [PASS] 3599 seconds -> 59 min, 59 sec; expected: 59 min, 59 sec [PASS] 3600 seconds -> 1 hr; expected: 1 hr [PASS] 3601 seconds -> 1 hr, 1 sec; expected: 1 hr, 1 sec
PARI/GP
Note: my own string function ssubstr() was used. You can find it here on RosettaCode Wiki.
\\ Convert seconds to compound duration
\\ 4/11/16 aev
secs2compdur(secs)={
my(us=[604800,86400,3600,60,1],ut=[" wk, "," d, "," hr, "," min, "," sec"],
cd=[0,0,0,0,0],u,cdt="");
for(i=1,5, u=secs\us[i]; if(u==0, next, cd[i]=u; secs-=us[i]*cd[i]));
for(i=1,5, if(cd[i]==0, next, cdt=Str(cdt,cd[i],ut[i])));
if(ssubstr(cdt,#cdt-1,1)==",", cdt=ssubstr(cdt,1,#cdt-2));
return(cdt);
}
{\\ Required tests:
print(secs2compdur(7259));
print(secs2compdur(86400));
print(secs2compdur(6000000));
}
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Pascal
program convertSecondsToCompoundDuration(output);
const
suffixUnitWeek = 'wk';
suffixUnitDay = 'd';
suffixUnitHour = 'hr'; { Use `'h'` to be SI-compatible. }
suffixUnitMinute = 'min';
suffixUnitSecond = 'sec'; { NB: Only `'s'` is SI-approved. }
suffixSeparator = ' '; { A non-breaking space would be appropriate. }
quantitySeparator = ', ';
{ Maximum expected length of `string` “12345 wk, 6 d, 7 hr, 8 min, 9 sec” }
timeSpanPrintedMaximumLength = 4 * length(quantitySeparator) +
20 + length(suffixUnitWeek) + 1 + length(suffixUnitDay) +
2 + length(suffixUnitHour) + 2 + length(suffixUnitMinute) +
2 + length(suffixUnitSecond) + 5 * length(suffixSeparator);
{ Units of time expressed in seconds. }
minute = 60;
hour = 60 * minute;
day = 24 * hour;
week = 7 * day;
type
wholeNumber = 0..maxInt;
naturalNumber = 1..maxInt;
canonicalTimeSpan = record
weeks: wholeNumber;
days: 0..6;
hours: 0..23;
minutes: 0..59;
seconds: 0..59;
end;
stringFitForTimeSpan = string(timeSpanPrintedMaximumLength);
{
\brief turns a time span expressed in seconds into a `canonicalTimeSpan`
\param duration the non-negative duration expressed in seconds
\return a `canonicalTimeSpan` representing \param duration seconds
}
function getCanonicalTimeSpan(duration: wholeNumber): canonicalTimeSpan;
{ Perform `div`ision and update `duration`. }
function split(protected unit: naturalNumber): wholeNumber;
begin
split := duration div unit;
duration := duration mod unit
end;
var
result: canonicalTimeSpan;
begin
with result do
begin
weeks := split(week);
days := split(day);
hours := split(hour);
minutes := split(minute);
seconds := duration
end;
{ In Pascal there needs to be _exactly_ one assignment to the }
{ result variable bearing the same name as of the `function`. }
getCanonicalTimeSpan := result
end;
{
\brief turns a non-trivial duration into a string
\param n a positive duration expressed in seconds
\return \param n expressed in some human-readable form
}
function timeSpanString(protected n: naturalNumber): stringFitForTimeSpan;
const
qs = quantitySeparator;
var
result: stringFitForTimeSpan;
begin
with getCanonicalTimeSpan(n) do
begin
{ `:1` specifies the minimum-width. Omitting it would cause }
{ the compiler to insert a vendor-defined default, e. g. 20. }
writeStr(result, weeks:1, suffixSeparator, suffixUnitWeek);
{ For strings, `:n` specifies the _exact_ width (padded with spaces). }
writeStr(result, result:ord(weeks > 0) * length(result));
if days > 0 then
begin
writeStr(result, result, qs:ord(length(result) > 0) * length(qs),
days:1, suffixSeparator, suffixUnitDay);
end;
if hours > 0 then
begin
writeStr(result, result, qs:ord(length(result) > 0) * length(qs),
hours:1, suffixSeparator, suffixUnitHour);
end;
if minutes > 0 then
begin
writeStr(result, result, qs:ord(length(result) > 0) * length(qs),
minutes:1, suffixSeparator, suffixUnitMinute);
end;
if seconds > 0 then
begin
writeStr(result, result, qs:ord(length(result) > 0) * length(qs),
seconds:1, suffixSeparator, suffixUnitSecond);
end
end;
timeSpanString := result
end;
{ === MAIN ============================================================= }
begin
writeLn( 7259, ' seconds are “', timeSpanString(7259), '”');
writeLn( 86400, ' seconds are “', timeSpanString(86400), '”');
writeLn(6000000, ' seconds are “', timeSpanString(6000000), '”')
end.
- Output:
7259 seconds are “2 hr, 59 sec” 86400 seconds are “1 d” 6000000 seconds are “9 wk, 6 d, 10 hr, 40 min”
Perl
Direct calculation
use strict;
use warnings;
sub compound_duration {
my $sec = shift;
no warnings 'numeric';
return join ', ', grep { $_ > 0 }
int($sec/60/60/24/7) . " wk",
int($sec/60/60/24) % 7 . " d",
int($sec/60/60) % 24 . " hr",
int($sec/60) % 60 . " min",
int($sec) % 60 . " sec";
}
for (7259, 86400, 6000000) {
printf "%7d sec = %s\n", $_, compound_duration($_)
}
- Output:
7259 sec = 2 hr, 59 sec 86400 sec = 1 d 6000000 sec = 9 wk, 6 d, 10 hr, 40 min
Using polymod
More general approach for mixed-radix conversions.
use strict;
use warnings;
use Math::AnyNum 'polymod';
sub compound_duration {
my $seconds = shift;
my @terms;
my @durations = reverse polymod($seconds, 60, 60, 24, 7);
my @timespans = <wk d hr min sec>;
while (my $d = shift @durations, my $t = shift @timespans) {
push @terms, "$d $t" if $d
}
join ', ', @terms
}
for (<7259 86400 6000000 3380521>) {
printf "%7d sec = %s\n", $_, compound_duration($_)
}
- Output:
7259 sec = 2 hr, 59 sec 86400 sec = 1 d 6000000 sec = 9 wk, 6 d, 10 hr, 40 min 3380521 sec = 5 wk, 4 d, 3 hr, 2 min, 1 sec
Phix
There is a standard function for this, for more details see builtins/pelapsed.e (which will be kept up to date, unlike having a copy here)
with javascript_semantics ?elapsed(7259) ?elapsed(86400) ?elapsed(6000000)
- Output:
"2 hours and 59s" "1 day" "9 weeks, 6 days, 10 hours, 40 minutes"
You may also be interested in the timedelta() function, which converts durations to seconds, eg:
with javascript_semantics include timedate.e ?elapsed(6000000-timedelta(days:=6,hours:=10))
- Output:
"9 weeks, 40 minutes"
PicoLisp
(for Sec (7259 86400 6000000)
(tab (-10 -30)
Sec
(glue ", "
(extract
'((N Str)
(when (gt0 (/ Sec N))
(setq Sec (% Sec N))
(pack @ " " Str) ) )
(604800 86400 3600 60 1)
'("wk" "d" "hr" "min" "sec") ) ) ) )
Output:
7259 2 hr, 59 sec 86400 1 d 6000000 9 wk, 6 d, 10 hr, 40 min
PL/I
/* Convert seconds to Compound Duration (weeks, days, hours, minutes, seconds). */
cvt: procedure options (main); /* 5 August 2015 */
declare interval float (15);
declare (unit, i, q controlled) fixed binary;
declare done bit (1) static initial ('0'b);
declare name (5) character (4) varying static initial (' wk', ' d', ' hr', ' min', ' sec' );
get (interval);
put edit (interval, ' seconds = ') (f(10), a);
if interval = 0 then do; put skip list ('0 sec'); stop; end;
do unit = 60, 60, 24, 7;
allocate q;
q = mod(interval, unit);
interval = interval / unit;
end;
allocate q; q = interval;
do i = 1 to 5;
if q > 0 then
do;
if done then put edit (', ') (a);
put edit (trim(q), name(i)) (a, a); done = '1'b;
end;
if i < 5 then free q;
end;
end cvt;
Results:
65 seconds = 1 min, 5 sec 3750 seconds = 1 hr, 2 min, 30 sec 1483506 seconds = 2 wk, 3 d, 4 hr, 5 min, 6 sec 60 seconds = 1 min 3604 seconds = 1 hr, 4 sec 100000000 seconds = 165 wk, 2 d, 9 hr, 46 min, 40 sec 987654321 seconds = 1633 wk, 4 hr, 25 min, 21 sec 86400 seconds = 1 d 86403 seconds = 1 d, 3 sec 3 more to come.
PowerShell
function Get-Time
{
<#
.SYNOPSIS
Gets a time string in the form: # wk, # d, # hr, # min, # sec
.DESCRIPTION
Gets a time string in the form: # wk, # d, # hr, # min, # sec
(Values of 0 are not displayed in the string.)
Days, Hours, Minutes or Seconds in any combination may be used
as well as Start and End dates.
When used with the -AsObject switch an object containing properties
similar to a System.TimeSpan object is returned.
.INPUTS
DateTime or Int32
.OUTPUTS
String or PSCustomObject
.EXAMPLE
Get-Time -Seconds 7259
.EXAMPLE
Get-Time -Days 31 -Hours 4 -Minutes 8 -Seconds 16
.EXAMPLE
Get-Time -Days 31 -Hours 4 -Minutes 8 -Seconds 16 -AsObject
.EXAMPLE
Get-Time -Start 3/10/2016 -End 1/20/2017
.EXAMPLE
Get-Time -Start (Get-Date) -End (Get-Date).AddSeconds(6000000)
#>
[CmdletBinding(DefaultParameterSetName='Date')]
Param
(
# Start date
[Parameter(Mandatory=$false, ParameterSetName='Date',
Position=0)]
[datetime]
$Start = (Get-Date),
# End date
[Parameter(Mandatory=$false, ParameterSetName='Date',
Position=1)]
[datetime]
$End = (Get-Date),
# Days in the time span
[Parameter(Mandatory=$false, ParameterSetName='Time')]
[int]
$Days = 0,
# Hours in the time span
[Parameter(Mandatory=$false, ParameterSetName='Time')]
[int]
$Hours = 0,
# Minutes in the time span
[Parameter(Mandatory=$false, ParameterSetName='Time')]
[int]
$Minutes = 0,
# Seconds in the time span
[Parameter(Mandatory=$false, ParameterSetName='Time')]
[int]
$Seconds = 0,
[switch]
$AsObject
)
Begin
{
[PSCustomObject]$timeObject = "PSCustomObject" |
Select-Object -Property Weeks,RemainingDays,
Days,Hours,Minutes,Seconds,Milliseconds,Ticks,
TotalDays,TotalHours,TotalMinutes,TotalSeconds,TotalMilliseconds
[int]$remainingDays = 0
[int]$weeks = 0
[string[]]$timeString = @()
}
Process
{
switch ($PSCmdlet.ParameterSetName)
{
'Date' { $timeSpan = New-TimeSpan -Start $Start -End $End }
'Time' { $timeSpan = New-TimeSpan -Days $Days -Hours $Hours -Minutes $Minutes -Seconds $Seconds }
}
$weeks = [System.Math]::DivRem($timeSpan.Days, 7, [ref]$remainingDays)
$timeObject.Weeks = $weeks
$timeObject.RemainingDays = $remainingDays
$timeObject.Days = $timeSpan.Days
$timeObject.Hours = $timeSpan.Hours
$timeObject.Minutes = $timeSpan.Minutes
$timeObject.Seconds = $timeSpan.Seconds
$timeObject.Milliseconds = $timeSpan.Milliseconds
$timeObject.Ticks = $timeSpan.Ticks
$timeObject.TotalDays = $timeSpan.TotalDays
$timeObject.TotalHours = $timeSpan.TotalHours
$timeObject.TotalMinutes = $timeSpan.TotalMinutes
$timeObject.TotalSeconds = $timeSpan.TotalSeconds
$timeObject.TotalMilliseconds = $timeSpan.TotalMilliseconds
}
End
{
if ($AsObject) { return $timeObject }
if ($timeObject.Weeks) { $timeString += "$($timeObject.Weeks) wk" }
if ($timeObject.RemainingDays) { $timeString += "$($timeObject.RemainingDays) d" }
if ($timeObject.Hours) { $timeString += "$($timeObject.Hours) hr" }
if ($timeObject.Minutes) { $timeString += "$($timeObject.Minutes) min" }
if ($timeObject.Seconds) { $timeString += "$($timeObject.Seconds) sec" }
return ($timeString -join ", ")
}
}
- Output:
PS C:\Scripts> 7259, 86400, 6000000 | ForEach-Object { Get-Time -Seconds $_ } 2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min PS C:\Scripts> Get-Time -Start 3/10/2016 -End 1/20/2017 45 wk, 1 d PS C:\Scripts> Get-Time -Seconds 6000000 -AsObject Weeks : 9 RemainingDays : 6 Days : 69 Hours : 10 Minutes : 40 Seconds : 0 Milliseconds : 0 Ticks : 60000000000000 TotalDays : 69.4444444444444 TotalHours : 1666.66666666667 TotalMinutes : 100000 TotalSeconds : 6000000 TotalMilliseconds : 6000000000
Prolog
Works with Swi-Prolog. Use Contraints for this task so the that functionality can be reversed (eg: find the number of seconds for a split date).
See below for examples.
:- 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).
- Output:
?- maplist(compound_time, [7259,86400,6000000]), !. 7259: 2 hr, 59 sec 86400: 1 d 6000000: 9 wk, 6 d, 10 hr, 40 min true. ?- times(N, [[wk, 9],[d, 6],[hr,10],[min,40]]), !. N = 6000000.
PureBasic
EnableExplicit
Procedure.s ConvertSeconds(NbSeconds)
Protected weeks, days, hours, minutes, seconds
Protected divisor, remainder
Protected duration$ = ""
divisor = 7 * 24 * 60 * 60 ; seconds in a week
weeks = NbSeconds / divisor
remainder = NbSeconds % divisor
divisor / 7 ; seconds in a day
days = remainder / divisor
remainder % divisor
divisor / 24 ; seconds in an hour
hours = remainder / divisor
remainder % divisor
divisor / 60 ; seconds in a minute
minutes = remainder / divisor
seconds = remainder % divisor
If weeks > 0
duration$ + Str(weeks) + " wk, "
EndIf
If days > 0
duration$ + Str(days) + " d, "
EndIf
If hours > 0
duration$ + Str(hours) + " hr, "
EndIf
If minutes > 0
duration$ + Str(minutes) + " min, "
EndIf
If seconds > 0
duration$ + Str(seconds) + " sec"
EndIf
If Right(duration$, 2) = ", "
duration$ = Mid(duration$, 0, Len(duration$) - 2)
EndIf
ProcedureReturn duration$
EndProcedure
If OpenConsole()
PrintN(ConvertSeconds(7259))
PrintN(ConvertSeconds(86400))
PrintN(ConvertSeconds(6000000))
PrintN("")
PrintN("Press any key to close the console")
Repeat: Delay(10) : Until Inkey() <> ""
CloseConsole()
EndIf
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Python
Python: Procedural
>>> def duration(seconds):
t= []
for dm in (60, 60, 24, 7):
seconds, m = divmod(seconds, dm)
t.append(m)
t.append(seconds)
return ', '.join('%d %s' % (num, unit)
for num, unit in zip(t[::-1], 'wk d hr min sec'.split())
if num)
>>> for seconds in [7259, 86400, 6000000]:
print("%7d sec = %s" % (seconds, duration(seconds)))
7259 sec = 2 hr, 59 sec
86400 sec = 1 d
6000000 sec = 9 wk, 6 d, 10 hr, 40 min
>>>
Python: Functional
>>> def duration(seconds, _maxweeks=99999999999):
return ', '.join('%d %s' % (num, unit)
for num, unit in zip([(seconds // d) % m
for d, m in ((604800, _maxweeks),
(86400, 7), (3600, 24),
(60, 60), (1, 60))],
['wk', 'd', 'hr', 'min', 'sec'])
if num)
>>> for seconds in [7259, 86400, 6000000]:
print("%7d sec = %s" % (seconds, duration(seconds)))
7259 sec = 2 hr, 59 sec
86400 sec = 1 d
6000000 sec = 9 wk, 6 d, 10 hr, 40 min
>>>
Or, composing a solution from pure curried functions, including the mapAccumR abstraction (a combination of of map and reduce, implemented in a variety of languages and functional libraries, in which a new list is derived by repeated application of the same function, as an accumulator (here, a remainder) passes from right to left):
'''Compound duration'''
from functools import reduce
from itertools import chain
# compoundDurationFromUnits :: [Num] -> [String] -> Num -> [(Num, String)]
def compoundDurationFromUnits(qs):
'''A list of compound string representions of a number n of time units,
in terms of the multiples given in qs, and the labels given in ks.
'''
return lambda ks: lambda n: list(
chain.from_iterable(map(
lambda v, k: [(v, k)] if 0 < v else [],
mapAccumR(
lambda a, x: divmod(a, x) if 0 < x else (1, a)
)(n)(qs)[1],
ks
))
)
# --------------------------TEST---------------------------
# main :: IO ()
def main():
'''Tests of various durations, with a
particular set of units and labels.
'''
print(
fTable('Compound durations from numbers of seconds:\n')(str)(
quoted("'")
)(
lambda n: ', '.join([
str(v) + ' ' + k for v, k in
compoundDurationFromUnits([0, 7, 24, 60, 60])(
['wk', 'd', 'hr', 'min', 'sec']
)(n)
])
)([7259, 86400, 6000000])
)
# -------------------------GENERIC-------------------------
# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
'''Heading -> x display function -> fx display function ->
f -> xs -> tabular string.
'''
def go(xShow, fxShow, f, xs):
ys = [xShow(x) for x in xs]
w = max(map(len, ys))
return s + '\n' + '\n'.join(map(
lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
xs, ys
))
return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
xShow, fxShow, f, xs
)
# mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
def mapAccumR(f):
'''A tuple of an accumulation and a list derived by a combined
map and fold, with accumulation from right to left.
'''
def go(a, x):
acc, y = f(a[0], x)
return (acc, [y] + a[1])
return lambda acc: lambda xs: (
reduce(go, reversed(xs), (acc, []))
)
# quoted :: Char -> String -> String
def quoted(c):
'''A string flanked on both sides
by a specified quote character.
'''
return lambda s: c + s + c
# MAIN ---
if __name__ == '__main__':
main()
- Output:
Compound durations from numbers of seconds: 7259 -> '2 hr, 59 sec' 86400 -> '1 d' 6000000 -> '9 wk, 6 d, 10 hr, 40 min'
Quackery
[ ' [ 60 60 24 7 ]
witheach [ /mod swap ]
$ ""
' [ $ " wk, " $ " d, "
$ " hr, " $ " min, "
$ " sec, " ]
witheach
[ do rot dup iff
[ number$
swap join join ]
else 2drop ]
-2 split drop ] is duration$ ( n--> $ )
' [ 7259 86400 6000000 ]
witheach
[ dup echo
say " seconds is "
duration$ echo$
say "." cr ]
- Output:
7259 seconds is 2 hr, 59 sec. 86400 seconds is 1 d. 6000000 seconds is 9 wk, 6 d, 10 hr, 40 min.
Racket
#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
- Output:
All tests pass... there is no output.
Raku
(formerly Perl 6)
The built-in polymod
method (which is a generalization of the divmod
function known from other languages), is a perfect match for a task like this:
sub compound-duration ($seconds) {
($seconds.polymod(60, 60, 24, 7) Z <sec min hr d wk>)
.grep(*[0]).reverse.join(", ")
}
# Demonstration:
for 7259, 86400, 6000000 {
say "{.fmt: '%7d'} sec = {compound-duration $_}";
}
- Output:
7259 sec = 2 hr, 59 sec 86400 sec = 1 d 6000000 sec = 9 wk, 6 d, 10 hr, 40 min
REXX
version 1
/* REXX ---------------------------------------------------------------
* Format seconds into a time string
*--------------------------------------------------------------------*/
Call test 7259 ,'2 hr, 59 sec'
Call test 86400 ,'1 d'
Call test 6000000 ,'9 wk, 6 d, 10 hr, 40 min'
Call test 123.50 ,'2 min, 3.5 sec'
Call test 123.00 ,'2 min, 3 sec'
Call test 0.00 ,'0 sec'
Exit
test:
Parse arg secs,xres
res=sec2ct(secs)
Say res
If res<>xres Then Say '**ERROR**'
Return
sec2ct:
Parse Arg s
/*
m=s%60; s=s//60
h=m%60; m=m//60
d=h%24; h=h//24
w=d%7; d=d//7
*/
If s=0 Then Return '0 sec'
Parse Value split(s,60) with m s
Parse Value split(m,60) with h m
Parse Value split(h,24) with d h
Parse Value split(d, 7) with w d
ol=''
If w>0 Then ol=ol w 'wk,'
If d>0 Then ol=ol d 'd,'
If h>0 Then ol=ol h 'hr,'
If m>0 Then ol=ol m 'min,'
If s>0 Then ol=ol (s/1) 'sec'
ol=strip(ol)
ol=strip(ol,,',')
Return ol
split: Procedure
Parse Arg what,how
a=what%how
b=what//how
Return a b
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min 2 min, 3.5 sec 2 min, 3 sec 0 sec
version 2
This REXX version can also handle fractional (seconds) as well as values of zero (time units).
/*rexx program demonstrates how to convert a number of seconds to bigger time units.*/
parse arg @; if @='' then @=7259 86400 6000000 /*Not specified? Then use the default.*/
do j=1 for words(@); z= word(@, j) /* [↓] process each number in the list*/
say right(z, 25) 'seconds: ' convSec(z) /*convert a number to bigger time units*/
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
convSec: parse arg x /*obtain a number from the argument. */
w= timeU( 60*60*24*7, 'wk' ) /*obtain number of weeks (if any). */
d= timeU( 60*60*24 , 'd' ) /* " " " days " " */
h= timeU( 60*60 , 'hr' ) /* " " " hours " " */
m= timeU( 60 , 'min' ) /* " " " minutes " " */
s= timeU( 1 , 'sec' ) /* " " " seconds " " */
if x\==0 then s=word(s 0, 1) + x 'sec' /*handle fractional (residual) seconds.*/
$=strip(space(w d h m s),,","); if $=='' then z= 0 "sec" /*handle 0 sec.*/
return $
/*──────────────────────────────────────────────────────────────────────────────────────*/
timeU: parse arg u,$; _= x%u; if _==0 then return ''; x= x - _*u; return _ $","
- output when using the default (internal) inputs:
7259 seconds: 2 hr, 59 sec 86400 seconds: 1 d 6000000 seconds: 9 wk, 6 d, 10 hr, 40 min
- output when using the inputs: 1800.7 123.50 123.00 0.00
1800.7 seconds: 30 min, 0.7 sec 123.50 seconds: 2 min, 3.50 sec 123.00 seconds: 2 min, 3 sec 0.00 seconds: 0 sec
Ring
sec = 6000005
week = floor(sec/60/60/24/7)
if week > 0 see sec
see " seconds is " + week + " weeks " ok
day = floor(sec/60/60/24) % 7
if day > 0 see day
see " days " ok
hour = floor(sec/60/60) % 24
if hour > 0 see hour
see " hours " ok
minute = floor(sec/60) % 60
if minute > 0 see minute
see " minutes " ok
second = sec % 60
if second > 0 see second
see " seconds" + nl ok
RPL
≪ MOD LAST / FLOOR ≫ 'DIVMOD' STO ≪ {" wk" " d" " hr" " min" " sec" } → unit ≪ 60 DIVMOD 60 DIVMOD 24 DIVMOD 7 DIVMOD 1 SF "" 1 unit SIZE FOR j IF SWAP THEN LAST →STR unit j GET + IF 1 FC?C THEN ", " SWAP + END + END NEXT ≫ ≫ '→CDUR' STO
Users of HP-48G and newer models can replace the 60 DIVMOD 60 DIVMOD 24 DIVMOD 7 DIVMOD
line by:
{ 60 60 24 7 } 1 ≪ MOD LAST / FLOOR ≫ DOSUBS OBJ→ DROP
7259 →CDUR 86400 →CDUR 6000000 →CDUR 10! →CDUR
- Output:
4: "2 hr, 59 sec" 3: "1 d" 2: "9 wk, 6 d, 10 hr, 40 min" 1: "6 wk"
Ruby
MINUTE = 60
HOUR = MINUTE*60
DAY = HOUR*24
WEEK = DAY*7
def sec_to_str(sec)
w, rem = sec.divmod(WEEK)
d, rem = rem.divmod(DAY)
h, rem = rem.divmod(HOUR)
m, s = rem.divmod(MINUTE)
units = ["#{w} wk", "#{d} d", "#{h} h", "#{m} min", "#{s} sec"]
units.reject{|str| str.start_with?("0")}.join(", ")
end
[7259, 86400, 6000000].each{|t| puts "#{t}\t: #{sec_to_str(t)}"}
Output:
7259 : 2 h, 59 sec 86400 : 1 d 6000000 : 9 wk, 6 d, 10 h, 40 min
Run BASIC
sec = 6000005
week = int(sec/60/60/24/7)
day = int(sec/60/60/24) mod 7
hour = int(sec/60/60) mod 24
minute = int(sec/60) mod 60
second = sec mod 60
print sec;" seconds is ";
if week > 0 then print week;" weeks ";
if day > 0 then print day;" days ";
if hour > 0 then print hour;" hours ";
if minute > 0 then print minute;" minutes ";
if second > 0 then print second;" seconds"
Rust
This solution deviates from the prompt a bit in order to make it more general. The benefit of doing it this way is that any values can be filled in for days, hours, minutes and seconds and the `balance` method will do the balancing accordingly. Also, rather than converting the value into a String, it simply implements the `Display` trait.
use std::fmt;
struct CompoundTime {
w: usize,
d: usize,
h: usize,
m: usize,
s: usize,
}
macro_rules! reduce {
($s: ident, $(($from: ident, $to: ident, $factor: expr)),+) => {{
$(
$s.$to += $s.$from / $factor;
$s.$from %= $factor;
)+
}}
}
impl CompoundTime {
#[inline]
fn new(w: usize, d: usize, h: usize, m: usize, s: usize) -> Self{
CompoundTime { w: w, d: d, h: h, m: m, s: s, }
}
#[inline]
fn balance(&mut self) {
reduce!(self, (s, m, 60), (m, h, 60),
(h, d, 24), (d, w, 7));
}
}
impl fmt::Display for CompoundTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}w {}d {}h {}m {}s",
self.w, self.d, self.h, self.m, self.s)
}
}
fn main() {
let mut ct = CompoundTime::new(0,3,182,345,2412);
println!("Before: {}", ct);
ct.balance();
println!("After: {}", ct);
}
Scala
//Converting Seconds to Compound Duration
object seconds{
def main( args:Array[String] ){
println("Enter the no.")
val input = scala.io.StdIn.readInt()
var week_r:Int = input % 604800
var week:Int = (input - week_r)/604800
var day_r:Int = week_r % 86400
var day:Int = (week_r - day_r)/86400
var hour_r:Int = day_r % 3600
var hour:Int = (day_r - hour_r)/3600
var minute_r:Int = hour_r % 60
var minute:Int = (hour_r - minute_r)/60
var sec:Int = minute_r % 60
println("Week = " + week)
println("Day = " + day)
println("Hour = " + hour)
println("Minute = " + minute)
println("Second = " + sec)
}
}
Scheme
This version uses delete from SRFI 1 and string-join from SRFI 13:
(import (scheme base)
(scheme write)
(srfi 1)
(only (srfi 13) string-join))
(define *seconds-in-minute* 60)
(define *seconds-in-hour* (* 60 *seconds-in-minute*))
(define *seconds-in-day* (* 24 *seconds-in-hour*))
(define *seconds-in-week* (* 7 *seconds-in-day*))
(define (seconds->duration seconds)
(define (format val unit)
(if (zero? val) "" (string-append (number->string val) " " unit)))
(let*-values (((weeks wk-remainder) (floor/ seconds *seconds-in-week*))
((days dy-remainder) (floor/ wk-remainder *seconds-in-day*))
((hours hr-remainder) (floor/ dy-remainder *seconds-in-hour*))
((minutes mn-remainder) (floor/ hr-remainder *seconds-in-minute*)))
(string-join (delete ""
(list (format weeks "wk")
(format days "d")
(format hours "hr")
(format minutes "min")
(format mn-remainder "sec"))
string=?) ", ")))
(display (seconds->duration 7259)) (newline)
(display (seconds->duration 86400)) (newline)
(display (seconds->duration 6000000)) (newline)
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Sidef
func polymod(n, *divs) {
gather {
divs.each { |i|
var m = take(n % i)
(n -= m) /= i
}
take(n)
}
}
func compound_duration(seconds) {
(polymod(seconds, 60, 60, 24, 7) ~Z <sec min hr d wk>).grep { |a|
a[0] > 0
}.reverse.map{.join(' ')}.join(', ')
}
[7259, 86400, 6000000].each { |s|
say "#{'%7d' % s} sec = #{compound_duration(s)}"
}
- Output:
7259 sec = 2 hr, 59 sec 86400 sec = 1 d 6000000 sec = 9 wk, 6 d, 10 hr, 40 min
Standard ML
local
fun fmtNonZero (0, _, list) = list
| fmtNonZero (n, s, list) = Int.toString n ^ " " ^ s :: list
fun divModHead (_, []) = []
| divModHead (d, head :: tail) = head div d :: head mod d :: tail
in
fun compoundDuration seconds =
let
val digits = foldl divModHead [seconds] [60, 60, 24, 7]
and units = ["wk", "d", "hr", "min", "sec"]
in
String.concatWith ", " (ListPair.foldr fmtNonZero [] (digits, units))
end
end
val () = app (fn s => print (compoundDuration s ^ "\n")) [7259, 86400, 6000000]
Swift
func duration (_ secs:Int) -> String {
if secs <= 0 { return "" }
let units = [(604800,"wk"), (86400,"d"), (3600,"hr"), (60,"min")]
var secs = secs
var result = ""
for (period, unit) in units {
if secs >= period {
result += "\(secs/period) \(unit), "
secs = secs % period
}
}
if secs == 0 {
result.removeLast(2) // remove ", "
} else {
result += "\(secs) sec"
}
return result
}
print(duration(7259))
print(duration(86400))
print(duration(6000000))
Tcl
The data-driven procedure below can be customised to use different breakpoints, simply by editing the dictionary.
proc sec2str {i} {
set factors {
sec 60
min 60
hr 24
d 7
wk Inf
}
set result ""
foreach {label max} $factors {
if {$i >= $max} {
set r [expr {$i % $max}]
set i [expr {$i / $max}]
if {$r} {
lappend result "$r $label"
}
} else {
if {$i > 0} {
lappend result "$i $label"
}
break
}
}
join [lreverse $result] ", "
}
proc check {cmd res} {
set r [uplevel 1 $cmd]
if {$r eq $res} {
puts "Ok! $cmd \t = $res"
} else {
puts "ERROR: $cmd = $r \t expected $res"
}
}
check {sec2str 7259} {2 hr, 59 sec}
check {sec2str 86400} {1 d}
check {sec2str 6000000} {9 wk, 6 d, 10 hr, 40 min}
- Output:
Ok! sec2str 7259 = 2 hr, 59 sec Ok! sec2str 86400 = 1 d Ok! sec2str 6000000 = 9 wk, 6 d, 10 hr, 40 min
uBasic/4tH
Since uBasic/4tH is integer-only, it is hard to return a string. However, it is capable to transform an integer value as required.
Proc _CompoundDuration(7259)
Proc _CompoundDuration(86400)
Proc _CompoundDuration(6000000)
End
_CompoundDuration Param(1) ' Print compound seconds
a@ = FUNC(_Compound(a@, 604800, _wk))
a@ = FUNC(_Compound(a@, 86400, _d))
a@ = FUNC(_Compound(a@, 3600, _hr))
a@ = FUNC(_Compound(a@, 60, _min))
If a@ > 0 Then Print a@;" sec"; ' Still seconds left to print?
Print
Return
_Compound Param(3)
Local(1)
d@ = a@/b@ ' Get main component
a@ = a@%b@ ' Leave the rest
If d@ > 0 Then ' Print the component
Print d@;
Proc c@
If a@ > 0 Then
Print ", "; ' If something follows, take
EndIf ' care of the comma
EndIf
Return (a@)
_wk Print " wk"; : Return
_d Print " d"; : Return
_hr Print " hr"; : Return
_min Print " min"; : Return
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min 0 OK, 0:94
Uiua
# Builds a string representation of a time period
Units ← {"second" "minute" "hour" "day" "week"}
Durations ← [60 60 24 7 9999]
# number-of-seconds -> [S M H D W]
Parts ← ⇌(◌∧(⊙⊂⊃(⌊÷|◿)) Durations⊙[])
# Stringify a unit: {"X" "unit"} -> box"X units"
Sunit ← /⍚(⊂⊂)" "⍥⍜(⊡1|⍚⊂⊙@s)≠□"1"⊢.
# Parse seconds as a string period: N -> "xxx"
String ← °□⊢/⍚$"_, _"⇌≡Sunit▽⊃(±|⍉⇌⊟Units°⋕) Parts
∵([□String])[7259 86400 6000000 14000000 31449599 31449601]
- Output:
╭─ ╷ ⌜2 hours, 59 seconds⌟ ⌜1 day⌟ ⌜9 weeks, 6 days, 10 hours, 40 minutes⌟ ⌜23 weeks, 1 day, 53 minutes, 20 seconds⌟ ⌜51 weeks, 6 days, 23 hours, 59 minutes, 59 seconds⌟ ⌜52 weeks, 1 second⌟ ╯
Vale
import stdlib.*;
import stdlib.stdin.*;
import stdlib.math.*;
exported func main() {
foreach testCase in [#][
7259,
86400,
6000000,
] {
testCase.timeString().println();
}
}
func timeString(seconds int) str {
result = "";
minutes = seconds / 60;
set seconds = seconds.mod(60);
if seconds > 0 {
set result = seconds.str() + " sec";
}
hours = minutes / 60;
set minutes = minutes.mod(60);
if minutes > 0 {
set result = minutes.str() + if result != "" {
" min, " + result
} else {
" min"
};
}
days = hours / 24;
set hours = hours.mod(24);
if hours > 0 {
set result = hours.str() + if result != "" {
" hr, " + result
} else {
" hr"
};
}
weeks = days / 7;
set days = days.mod(7);
if days > 0 {
set result = days.str() + if result != "" {
" d, " + result
} else {
" d"
};
}
if weeks > 0 {
set result = weeks.str() + if result != "" {
" wk, " + result
} else {
" wk"
};
}
return result;
}
VBA
Private Function compound_duration(ByVal seconds As Long) As String
minutes = 60
hours = 60 * minutes
days_ = 24 * hours
weeks = 7 * days_
Dim out As String
w = seconds \ weeks
seconds = seconds - w * weeks
d = seconds \ days_
seconds = seconds - d * days_
h = seconds \ hours
seconds = seconds - h * hours
m = seconds \ minutes
s = seconds Mod minutes
out = IIf(w > 0, w & " wk, ", "") & _
IIf(d > 0, d & " d, ", "") & _
IIf(h > 0, h & " hr, ", "") & _
IIf(m > 0, m & " min, ", "") & _
IIf(s > 0, s & " sec", "")
If Right(out, 2) = ", " Then
compound_duration = Left(out, Len(out) - 2)
Else
compound_duration = out
End If
End Function
Public Sub cstcd()
Debug.Print compound_duration(7259)
Debug.Print compound_duration(86400)
Debug.Print compound_duration(6000000)
End Sub
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
VBScript
Function compound_duration(n)
Do Until n = 0
If n >= 604800 Then
wk = Int(n/604800)
n = n-(604800*wk)
compound_duration = compound_duration & wk & " wk"
End If
If n >= 86400 Then
d = Int(n/86400)
n = n-(86400*d)
If wk > 0 Then compound_duration = compound_duration & ", " End If
compound_duration = compound_duration & d & " d"
End If
If n >= 3600 Then
hr = Int(n/3600)
n = n-(3600*hr)
If d > 0 Then compound_duration = compound_duration & ", " End If
compound_duration = compound_duration & hr & " hr"
End If
If n >= 60 Then
min = Int(n/60)
n = n-(60*min)
If hr > 0 Then compound_duration = compound_duration & ", " End If
compound_duration = compound_duration & min & " min"
End If
If n > 0 Then
If min > 0 Then compound_duration = compound_duration & ", " End If
compound_duration = compound_duration & ", " & n & " sec"
n = 0
End If
Loop
End Function
'validating the function
WScript.StdOut.WriteLine compound_duration(7259)
WScript.StdOut.WriteLine compound_duration(86400)
WScript.StdOut.WriteLine compound_duration(6000000)
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
Wren
var duration = Fn.new { |s|
if (s < 1) return "0 sec"
var dur = ""
var divs = [7, 24, 60, 60, 1]
var units = ["wk", "d", "hr", "min", "sec"]
var t = divs.reduce { |prod, div| prod * div }
for (i in 0...divs.count) {
var u = (s/t).floor
if (u > 0) {
dur = dur + "%(u) %(units[i]), "
s = s % t
}
t = t / divs[i]
}
if (dur.endsWith(", ")) dur = dur[0..-3]
return dur
}
for (s in [7259, 86400, 6000000]) System.print(duration.call(s))
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
XPL0
char Str(80);
func Duration(Sec); \Convert seconds to compound duration
int Sec, Amt, Unit, DoComma, I, Quot;
[Amt:= [7*24*60*60, 24*60*60, 60*60, 60, 1];
Unit:= [" wk", " d", " hr", " min", " sec"];
DoComma:= false;
for I:= 0 to 4 do
[Quot:= Sec/Amt(I);
Sec:= rem(0);
if Quot # 0 then
[if DoComma then Text(8, ", ");
DoComma:= true;
IntOut(8, Quot);
Text(8, Unit(I));
];
];
ChOut(8, $0D); ChOut(8, $8A); \terminating CR+LF
I:= 0;
loop [Str(I):= ChIn(8);
if Str(I) >= $80 then return Str;
I:= I+1;
];
];
[Text(0, Duration(7259));
Text(0, Duration(86400));
Text(0, Duration(6_000_000));
]
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
zkl
fcn toWDHMS(sec){ //-->(wk,d,h,m,s)
r,b:=List(),0;
foreach u in (T(60,60,24,7)){
sec,b=sec.divr(u); // aka divmod
r.append(b);
}
r.append(sec).reverse()
}
Or, if you like to be concise:
fcn toWDHMS(sec){ //-->(wk,d,h,m,s)
T(60,60,24,7).reduce(fcn(n,u,r){ n,u=n.divr(u); r.append(u); n },
sec,r:=List()):r.append(_).reverse();
}
were the ":" op takes the left result and stuffs it into the "_" position.
units:=T(" wk"," d"," hr"," min"," sec");
foreach s in (T(7259,86400,6000000)){
toWDHMS(s).zip(units).pump(List,fcn([(t,u)]){ t and String(t,u) or "" })
.filter().concat(", ").println();
}
- Output:
2 hr, 59 sec 1 d 9 wk, 6 d, 10 hr, 40 min
ZX Spectrum Basic
10 LET m=60: LET h=60*m: LET d=h*24: LET w=d*7
20 DATA 10,7259,86400,6000000,0,1,60,3600,604799,604800,694861
30 READ n
40 FOR i=1 TO n
50 READ s
60 LET nweek=0: LET nday=0: LET nhour=0: LET nmin=0: LET nsec=0: LET s$=""
70 PRINT s;" = ";
80 IF s>=w THEN LET nweek=INT (s/w): LET s=FN m(s,w)
90 IF s>=d THEN LET nday=INT (s/d): LET s=FN m(s,d)
100 IF s>=h THEN LET nhour=INT (s/h): LET s=FN m(s,h)
110 IF s>=m THEN LET nmin=INT (s/m): LET s=FN m(s,m)
120 LET nsec=INT (s)
130 IF nweek>0 THEN LET s$=s$+STR$ nweek+" wk, "
140 IF nday>0 THEN LET s$=s$+STR$ nday+" d, "
150 IF nhour>0 THEN LET s$=s$+STR$ nhour+" hr, "
160 IF nmin>0 THEN LET s$=s$+STR$ nmin+" min, "
170 IF nsec>0 THEN LET s$=s$+STR$ nsec+" sec"
180 IF s$<>"" THEN IF s$(LEN s$-1)="," THEN LET s$=s$( TO LEN s$-2)
190 PRINT s$
200 NEXT i
210 STOP
220 DEF FN m(a,b)=a-INT (a/b)*b
- Programming Tasks
- Solutions by Programming Task
- Date and time
- 11l
- Action!
- Action! Tool Kit
- Action! Real Math
- Ada
- ALGOL 68
- ALGOL W
- APL
- AppleScript
- Applesoft BASIC
- Arturo
- AutoHotkey
- AWK
- BASIC
- Commodore BASIC
- BaCon
- BBC BASIC
- IS-BASIC
- Batch File
- Beeswax
- Befunge
- C
- C sharp
- System
- System.Collections.Generic
- System.Linq
- C++
- Clojure
- CLU
- COBOL
- Common Lisp
- D
- Delphi
- SysUtils,StdCtrls,DateUtils
- EasyLang
- Elixir
- Erlang
- F Sharp
- Factor
- Forth
- Fortran
- FreeBASIC
- Frink
- FutureBasic
- Gambas
- Go
- Haskell
- J
- Jakt
- Java
- JavaScript
- Jq
- Julia
- K
- Kotlin
- Langur
- Liberty BASIC
- Lua
- Maple
- Mathematica
- Wolfram Language
- Nim
- OCaml
- PARI/GP
- Pascal
- Perl
- Phix
- PicoLisp
- PL/I
- PowerShell
- Prolog
- PureBasic
- Python
- Quackery
- Racket
- Raku
- REXX
- Ring
- RPL
- Ruby
- Run BASIC
- Rust
- Scala
- Scheme
- Scheme/SRFIs
- Sidef
- Standard ML
- Swift
- Tcl
- UBasic/4tH
- Uiua
- Vale
- VBA
- VBScript
- Wren
- XPL0
- Zkl
- ZX Spectrum Basic