
Write a function or program which:
100), andThis 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., return2 min, 10 sec and not1 min, 70 sec or130 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).
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))
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)RETURNPROC 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 ODRETURNPROC Test(CHAR ARRAY s) REAL seconds Time t ValR(s,seconds) PrintR(seconds) Print(" -> ") Convert(seconds,t) PrintTime(t) PutE()RETURNPROC 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")RETURNScreenshot from Atari 8-bit computer
259 -> 2 hr, 59 sec86400 -> 1 d6000000 -> 9 wk, 6 d, 10 hr, 40 min
withAda.Text_IO;procedureConvertistypeTimeisrange0..10_000*356*20*60*60;-- at most 10_000 yearssubtypeValid_DurationisTimerange1..10_000*356*20*60*60;typeUnitsis(WK,D,HR,MIN,SEC);packageIOrenamesAda.Text_IO;Divide_By:constantarray(Units)ofTime:=(1_000*53,7,24,60,60);Split:array(Units)ofTime;No_Comma:Units;X:Time;Test_Cases:array(Positiverange<>)ofValid_Duration:=(6,60,3659,7_259,86_400,6_000_000,6_001_200,6_001_230,600_000_000);beginforTest_CaseofTest_CasesloopIO.Put(Time'Image(Test_Case)&" SECONDS =");X:=Test_Case;-- split X up into weeks, days, ..., secondsNo_Comma:=Units'First;forUnitinreverseUnitsloop-- Unit = SEC, ..., WK (in that order)Split(Unit):=XmodDivide_By(Unit);X:=X/Divide_By(Unit);ifUnit>No_CommaandSplit(Unit)>0thenNo_Comma:=Unit;endif;endloop;-- ouput weeks, days, ..., secondsforUnitinUnitsloop-- Unit = WK, .., SEC (in that order)ifSplit(Unit)>0thenIO.Put(Time'Image(Split(Unit))&" "&Units'Image(Unit)&(ifNo_Comma>Unitthen","else""));endif;endloop;IO.New_Line;endloop;endConvert;
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
# MODE to hold the compound duration #MODE DURATION = STRUCT( INT weeks, days, hours, minutes, seconds );# returns number of seconds converted to a DURATION #OP TODURATION = ( LONG INT number of seconds )DURATION: BEGIN LONG INT time := number of 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 number of seconds converted to a DURATION #OP TODURATION = ( INT number of seconds )DURATION: TODURATION LENG number of 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 ) )
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
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.
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
duration←{names←'wk''d''hr''min''sec'parts←07246060⊤⍵fmt←⍕¨(parts≠0)/parts,¨names¯2↓∊fmt,¨⊂', '}
duration 72592 hr, 59 sec duration 864001 d duration 60000009 wk, 6 d, 10 hr, 40 min
-------------------- COMPOUND DURATIONS -------------------- weekParts Int -> [Int]onweekParts(intSeconds)unitParts(intSeconds,[missing value,7,24,60,60])endweekParts-- localCompoundDuration :: Int -> StringonlocalCompoundDuration(localNames,intSeconds)-- [String] -> (Int, String) -> [String]scriptformattedon|λ|(lstPair,a)setqtoitem1oflstPairifq>0then{(qasstring)&space&item2oflstPair}&aelseaendifend|λ|endscriptintercalate(", ",¬foldr(formatted,[],¬zip(weekParts(intSeconds),localNames)))endlocalCompoundDuration------------------ INTEGER DECOMPOSITION ------------------- unitParts :: Int -> [maybe Int] -> [Int]onunitParts(intTotal,unitList)-- partList :: Record -> Int -> RecordscriptpartListon|λ|(x,a)setintResttoremainingofaifxis notmissing valuethensetintModtointRestmodxsetdtoxelsesetintModtointRestsetdto1endif{remaining:(intRest-intMod)divd,parts:{intMod}&partsofa}end|λ|endscriptpartsoffoldr(partList,¬{remaining:intTotal,parts:[]},unitList)endunitParts--------------------------- TEST -------------------------onrunscriptangloNameson|λ|(n)(nasstring)&" -> "&¬localCompoundDuration(["wk","d","hr","min","sec"],n)end|λ|endscriptunlines(map(angloNames,[7259,86400,6000000]))endrun-------------------- GENERIC FUNCTIONS --------------------- foldr :: (a -> b -> b) -> b -> [a] -> bonfoldr(f,startValue,xs)tellmReturn(f)setvtostartValuesetlngtolengthofxsrepeatwithifromlngto1by-1setvto|λ|(itemiofxs,v,i,xs)endrepeatreturnvendtellendfoldr-- intercalate :: String -> [String] -> Stringonintercalate(delim,xs)set{dlm,mytext item delimiters}to¬{mytext item delimiters,delim}setstoxsastextsetmytext item delimiterstodlmsendintercalate-- map :: (a -> b) -> [a] -> [b]onmap(f,xs)-- The list obtained by applying f-- to each element of xs.tellmReturn(f)setlngtolengthofxssetlstto{}repeatwithifrom1tolngsetendoflstto|λ|(itemiofxs,i,xs)endrepeatreturnlstendtellendmap-- min :: Ord a => a -> a -> aonmin(x,y)ify<xthenyelsexendifendmin-- mReturn :: First-class m => (a -> b) -> m (a -> b)onmReturn(f)-- 2nd class handler function lifted into 1st class script wrapper.ifscriptisclassoffthenfelsescriptproperty|λ|:fendscriptendifendmReturn-- unlines :: [String] -> Stringonunlines(xs)-- A single string formed by the intercalation-- of a list of strings with the newline character.set{dlm,mytext item delimiters}to¬{mytext item delimiters,linefeed}setstoxsastextsetmytext item delimiterstodlmsendunlines-- zip :: [a] -> [b] -> [(a, b)]onzip(xs,ys)-- A list of step-wise pairs drawn from xs and ys-- up to the length of the shorter of those lists.setlngtomin(lengthofxs,lengthofys)setzsto{}repeatwithifrom1tolngsetendofzsto{itemiofxs,itemiofys}endrepeatreturnzsendzip
7259 -> 2 hr, 59 sec86400 -> 1 d6000000 -> 9 wk, 6 d, 10 hr, 40 min
onsecondsToCompoundDuration(sec)if((sec'sclassis notinteger)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)thenreturn"0 sec"-- Otherwise perform the described task.setunitsto{weeks,days,hours,minutes,1}setsuffixesto{" wk, "," d, "," hr, "," min, "," sec, "}setoutputto""repeatwithifrom1to5setunittounits'sitemisetunitValuetosecdivunitif(unitValue>0)thensetoutputtooutput&unitValue&suffixes'sitemisetsectosecmodunitif(sec=0)thenexitrepeatendrepeatreturnoutput'stext1thru-3endsecondsToCompoundDurationreturnsecondsToCompoundDuration(7259)&linefeed&¬secondsToCompoundDuration(86400)&linefeed&¬secondsToCompoundDuration(6000000)
"2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min"
100 DATA604800,WK,86400,D,3600,HR,60,MIN,1,SEC110 FOR I = 0 TO 4120 READ M(I), U$(I)130 NEXT140 DATA7259,86400,6000000150 ON ERR GOTO 270160 READ S170 GOSUB 200180 PRINT S " = " S$190 GOTO 160200 N = S210 S$ = ""220 FOR I = 0 TO 4230 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 I260 RETURN270 ENDUnits:[" wk"," d"," hr"," min"," sec"]Quantities:@[7*24*60*60,24*60*60,60*60,60,1]durationString:function[d][dur:didx:0result:[]while[not?zero?dur][q:dur/Quantities\[idx]ifnot?zero?q[dur:dur%Quantities\[idx]'result++~{|q||Units\[idx]|}]idx:idx+1]returnjoin.with:","result]loop[7259864006000000]'t[print[t"s =>"durationStringt]]
7259 s => 2 hr, 59 sec 86400 s => 1 d 6000000 s => 9 wk, 6 d, 10 hr, 40 min
duration(n){sec:=1,min:=60*sec,hr:=60*min,day:=24*hr,wk:=7*dayw:=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:=nreturntrim((w?w" wk, ":"")(d?d" d, ":"")(h?h" hr, ":"")(m?m" min, ":"")(s?s" sec":""),", ")}
Examples:
data=(7259864006000000)loop,parse,data,`n,`rres.=A_LoopField"`t: "duration(A_LoopField)"`n"MsgBox%resreturn
Outputs:
7259: 2 hr, 59 sec86400: 1 d6000000: 9 wk, 6 d, 10 hr, 40 min
# syntax: GAWK -f CONVERT_SECONDS_TO_COMPOUND_DURATION.AWKBEGIN{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)}functionhowlong(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)?(strn_week" wk, "):strstr=(n_day>0)?(strn_day" d, "):strstr=(n_hour>0)?(strn_hour" hr, "):strstr=(n_min>0)?(strn_min" min, "):strstr=(n_sec>0)?(strn_sec" sec"):strsub(/, $/,"",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
10REM CONVERT SECONDS TO COMPOUND DURATION20REM ADAPTED FROM RUN BASIC VERSION30REM ===============================================================40PRINTCHR$(14)50SEC=725960GOSUB100070SEC=8540080GOSUB100090SEC=6000000100GOSUB1000110END120REM ==============================================================1000WK=INT(SEC/60/60/24/7)1010DY=INT(SEC/60/60/24)-7*WK1020HR=INT(SEC/60/60)-24*(DY+7*WK)1030MN=INT(SEC/60)-60*(HR+24*(DY+7*WK))1040SC=SEC-60*(MN+60*(HR+24*(DY+7*WK)))1050PRINTSEC;"SEC":PRINT" =";1055F=01060IFWK=0THEN10801070PRINTWK;"WK";:F=11080IFDY=0THEN11101090IFFTHENPRINT",";1100PRINTDY;"DY";:F=11110IFHR=0THEN11401120IFFTHENPRINT",";1130PRINTHR;"HR";:F=11140IFMN=0THEN11701150IFFTHENPRINT",";1160PRINTMN;"MIN";:F=11170IF(SC>0)ANDFTHENPRINT",";SC;"SEC":GOTO12001180IF(SC=0)ANDFTHEN12001190PRINTSC;"SEC"1200PRINT1210RETURN
7259 sec = 2 hr, 59 sec85400 sec = 23 hr, 43 min, 20 sec6000000 sec = 9 wk, 6 dy, 10 hr, 40 min
'--- SAY_TIME Convert seconds to compound duration'--- Weeks, days hours, minutes ,secondsSUBSAY_TIME(intsec)LOCALweek,day,hour,minute,secondTYPEintweek=sec/604800day=MOD(sec/86400,7)hour=MOD(sec/3600,24)minute=MOD(sec/60,60)second=MOD(sec,60)IFweek>0THENPRINTSTR$(week)&" wk, "TOp1$SIZE100ENDIFIFday>0THENPRINTSTR$(day)&" d, "TOp2$SIZE100ENDIFIFhour>0THENPRINTSTR$(hour)&" h, "TOp3$SIZE100ENDIFIFminute>0THENPRINTSTR$(minute)&" min, "TOp4$SIZE100ENDIFIFsecond>0THENPRINTSTR$(second)&" sec "TOp5$SIZE100ENDIFPRINTp1$,p2$,p3$,p4$,p5$ENDSUB'---result 9 wk, 6 d, 10 h, 40 min, 7 secSAY_TIME(6000007)
REM >compdurationPRINTFN_convert(7259)PRINTFN_convert(86400)PRINTFN_convert(6000000)END:DEFFN_convert(seconds%)LOCALunits%(),units$(),i%,unit%,compound$DIMunits%(4)DIMunits$(4)units%()=604800,86400,3600,60,1units$()="wk","d","hr","min","sec"compound$=""FORi%=0TO4IFseconds%>=units%(i%)THENunit%=seconds%DIVunits%(i%)seconds%=seconds%MODunits%(i%)compound$+=STR$(unit%)+" "+units$(i%)IFi%<4ANDseconds%>0THENcompound$+=", "ENDIFNEXT=compound$
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
100 PROGRAM "Seconds.bas"110 NUMERIC UN(1 TO 5),SEC,UNIT120 STRING T$(1 TO 5)*3130 LET UN(1)=604800:LET UN(2)=86400:LET UN(3)=3600:LET UN(4)=60:LET UN(5)=1140 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: ":SEC160 PRINT SEC;"sec =";170 FOR I=1 TO 5180 IF SEC>=UN(I) THEN190 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
@echo off::The Main Thing...for%%din(7259 86400 6000000)docall:duration%%dexit/b 0::/The Main Thing.::The Function...:durationsetoutput=set/a"wk=%1/604800,rem=%1%%604800"if%wk%neq 0set"output=%wk% wk,"set/a"d=%rem%/86400,rem=%rem%%%86400"if%d%neq 0set"output=%output%%d% d,"set/a"hr=%rem%/3600,rem=%rem%%%3600"if%hr%neq 0set"output=%output%%hr% hr,"set/a"min=%rem%/60,rem=%rem%%%60"if%min%neq 0set"output=%output%%min% min,"if%rem%neq 0set"output=%output%%rem% sec,"if%1gtr 0echo%1 sec =%output:~1,-1%goto:EOF::/The Function.
7259 sec = 2 hr, 59 sec86400 sec = 1 d6000000 sec = 9 wk, 6 d, 10 hr, 40 min
#>%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 > djulia> beeswax("seconds to compound duration.bswx")i72592 hr, 59 secProgram finished!julia> beeswax("seconds to compound duration.bswx")i864001 dProgram finished!julia> beeswax("seconds to compound duration.bswx")i60000009 wk, 6 d, 10 hr, 40 minProgram finished!The value to convert is read from stdin, and the corresponding compound duration is written to stdout.
&>:"<"%\"O{rq"**+\"<"/:"<"%\"r<|":*+*5-\vv-7*"l~"/7\"d"\%7:/*83\+*:"xD"\%*83:/"<"<>\:!#v_v#-#<",",#$48*#<,#<.#<>#_:"~"%,v^_@#:$$<>.02g92p^^!:/"~"<
72592 hr, 59 sec864001 d60000009 wk, 6 d, 10 hr, 40 min
/* * 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(unsignedlongseconds){inti;constunsignedlongs=1;constunsignedlongm=60*s;constunsignedlongh=60*m;constunsignedlongd=24*h;constunsignedlongw=7*d;constunsignedlongcoeff[5]={w,d,h,m,s};constcharunits[5][4]={"wk","d","hr","min","sec"};staticcharbuffer[256];char*ptr=buffer;for(i=0;i<5;i++){unsignedlongvalue;value=seconds/coeff[i];seconds=seconds%coeff[i];if(value){if(ptr!=buffer)ptr+=sprintf(ptr,", ");ptr+=sprintf(ptr,"%lu %s",value,units[i]);}}returnbuffer;}/* * Main function for seconds2string program. */intmain(intargc,charargv[]){unsignedlongseconds;if((argc<2)&&scanf("%lu",&seconds)||(argc>=2)&&sscanf(argv[1],"%lu",&seconds)){printf("%s\n",seconds2string(seconds));returnEXIT_SUCCESS;}returnEXIT_FAILURE;}
#include<inttypes.h> /* requires c99 */#include<stdbool.h> /* requires c99 */#include<stdio.h>#include<stdlib.h>#define N_EL 5uintmax_tsec_to_week(uintmax_t);uintmax_tsec_to_day(uintmax_t);uintmax_tsec_to_hour(uintmax_t);uintmax_tsec_to_min(uintmax_t);uintmax_tweek_to_sec(uintmax_t);uintmax_tday_to_sec(uintmax_t);uintmax_thour_to_sec(uintmax_t);uintmax_tmin_to_sec(uintmax_t);char*format_sec(uintmax_t);/* the primary function */intmain(intargc,char*argv[]){uintmax_tinput;char*a;if(argc<2){printf("usage: %s #seconds\n",argv[0]);return1;}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]);return1;}printf("Number entered: %"PRIuMAX"\n",input);a=format_sec(input);printf(a);free(a);return0;}/* note: must free memory * after using this function */char*format_sec(uintmax_tinput){inti;boolfirst;uintmax_tweeks,days,hours,mins;/*seconds kept in input*/char*retval;FILE*stream;size_tsize;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");return0;}/* 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);returnretval;}uintmax_tsec_to_week(uintmax_tseconds){returnsec_to_day(seconds)/7;}uintmax_tsec_to_day(uintmax_tseconds){returnsec_to_hour(seconds)/24;}uintmax_tsec_to_hour(uintmax_tseconds){returnsec_to_min(seconds)/60;}uintmax_tsec_to_min(uintmax_tseconds){returnseconds/60;}uintmax_tweek_to_sec(uintmax_tweeks){returnday_to_sec(weeks*7);}uintmax_tday_to_sec(uintmax_tdays){returnhour_to_sec(days*24);}uintmax_thour_to_sec(uintmax_thours){returnmin_to_sec(hours*60);}uintmax_tmin_to_sec(uintmax_tminutes){returnminutes*60;}
Number entered: 72592 hr, 59 sec Number entered: 864001 dNumber entered: 60000009 wk, 6 d, 10 hr, 40 min
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;namespaceConvertSecondsToCompoundDuration{classProgram{staticvoidMain(string[]args){foreach(stringarginargs){intduration;boolisValid=int.TryParse(arg,outduration);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));}}privatestaticstringFormatAsDuration(intduration){if(duration<0)thrownewArgumentOutOfRangeException("duration");returnstring.Join(", ",GetDurationParts(duration));}privatestaticIEnumerable<string>GetDurationParts(intduration){varparts=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(varpartinparts){intn=Math.DivRem(duration,part.Length,outduration);if(n>0)yieldreturnstring.Format("{0} {1}",n,part.Name);}}}}
7,259 seconds ==> 2 h, 59 s86,400 seconds ==> 1 d6,000,000 seconds ==> 9 wk, 6 d, 10 h, 40 m
privatestaticstringConvertToCompoundDuration(intseconds){if(seconds<0)thrownewArgumentOutOfRangeException(nameof(seconds));if(seconds==0)return"0 sec";TimeSpanspan=TimeSpan.FromSeconds(seconds);int[]parts={span.Days/7,span.Days%7,span.Hours,span.Minutes,span.Seconds};string[]units={" wk"," d"," hr"," min"," sec"};returnstring.Join(", ",fromindexinEnumerable.Range(0,units.Length)whereparts[index]>0selectparts[index]+units[index]);}
#include<iostream>#include<vector>usingentry=std::pair<int,constchar*>;voidprint(conststd::vector<entry>&entries,std::ostream&out=std::cout){boolfirst=true;for(constauto&e:entries){if(!first)out<<", ";first=false;out<<e.first<<" "<<e.second;}out<<'\n';}std::vector<entry>convert(intseconds){staticconstentrytime_table[]={{7*24*60*60,"wk"},{24*60*60,"d"},{60*60,"hr"},{60,"min"},{1,"sec"}};std::vector<entry>result;for(constauto&e:time_table){inttime=seconds/e.first;if(time!=0)result.emplace_back(time,e.second);seconds%=e.first;}returnresult;}intmain(){std::cout<<" 7259 sec is ";print(convert(7259));std::cout<<" 86400 sec is ";print(convert(86400));std::cout<<"6000000 sec is ";print(convert(6000000));}
7259 sec is 2 hr, 59 sec 86400 sec is 1 d6000000 sec is 9 wk, 6 d, 10 hr, 40 min
(require'[clojure.string:asstring])(defseconds-in-minute60)(defseconds-in-hour(*60seconds-in-minute))(defseconds-in-day(*24seconds-in-hour))(defseconds-in-week(*7seconds-in-day))(defnseconds->duration[seconds](let[weeks((juxtquotrem)secondsseconds-in-week)wk(firstweeks)days((juxtquotrem)(lastweeks)seconds-in-day)d(firstdays)hours((juxtquotrem)(lastdays)seconds-in-hour)hr(firsthours)min(quot(lasthours)seconds-in-minute)sec(rem(lasthours)seconds-in-minute)](string/join", "(filter#(not(string/blank?%))(conj[](when(>wk0)(strwk" wk"))(when(>d0)(strd" d"))(when(>hr0)(strhr" hr"))(when(> min0)(str min" min"))(when(>sec0)(strsec" sec")))))))(seconds->duration7259)(seconds->duration86400)(seconds->duration6000000)
"2 hr, 59 sec""1 d""9 wk, 6 d, 10 hr, 40 min"
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 durationstart_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)) endend start_up
7259 => 2 hr, 59 sec86400 => 1 d6000000 => 9 wk, 6 d, 10 hr, 40 min
identificationdivision.program-id.fmt-dura.datadivision.working-storagesection.1input-secondspic 9(8).1formatted-durationpic x(30)global.1fractions.2weekspic z(3)9.2dayspic z(3)9.2hourspic z(3)9.2minutespic z(3)9.2secondspic z(3)9.1.2weeks-strpic x(4)value"wk".2days-strpic x(4)value"d".2hours-strpic x(4)value"hr".2minutes-strpic x(4)value"min".2seconds-strpic x(4)value"sec".1workbinaryglobal.2str-pospic 9(4).2chars-transferredpic 9(4).proceduredivision.begin.display"Enter duration (seconds): "noadvancingacceptinput-secondsdivideinput-secondsby60givinginput-secondsremaindersecondsdivideinput-secondsby60givinginput-secondsremainderminutesdivideinput-secondsby24givinginput-secondsremainderhoursdivideinput-secondsby7givingweeksremainderdaysmove1tostr-poscall"fmt"usingweeksweeks-strcall"fmt"usingdaysdays-strcall"fmt"usinghourshours-strcall"fmt"usingminutesminutes-strcall"fmt"usingsecondsseconds-strdisplayformatted-durationstoprun.identificationdivision.program-id.fmt.datadivision.working-storagesection.77nothingpic x.linkagesection.1formatted-valuepic x(4).1duration-sizepic x(4).proceduredivisionusingformatted-valueduration-size.begin.iffunctionnumval(formatted-value)not=0performinsert-comma-spaceunstringformatted-valuedelimitedall spaceintonothingformatted-duration(str-pos:)countchars-transferredaddchars-transferredtostr-posstringspacedelimitedsizeduration-sizedelimitedspaceintoformatted-durationpointerstr-posend-ifexitprogram.insert-comma-space.ifstr-pos>1move", "toformatted-duration(str-pos:)add2tostr-posend-if.endprogramfmt.endprogramfmt-dura.
Enter duration (seconds): 72592 hr, 59 secEnter duration (seconds): 864001 dEnter duration (seconds): 60000009 wk, 6 d, 10 hr, 40 min
(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*))(defunseconds->duration(seconds)(multiple-value-bind(weekswk-remainder)(floorseconds+seconds-in-week*)(multiple-value-bind(daysd-remainder)(floorwk-remainder+seconds-in-day*)(multiple-value-bind(hourshr-remainder)(floord-remainder+seconds-in-hour*)(multiple-value-bind(minutessecs)(floorhr-remainder+seconds-in-minute*)(let((chunksnil))(unless(zeropsecs)(push(formatnil"~D sec"secs)chunks))(unless(zeropminutes)(push(formatnil"~D min"minutes)chunks))(unless(zerophours)(push(formatnil"~D hr"hours)chunks))(unless(zeropdays)(push(formatnil"~D d"days)chunks))(unless(zeropweeks)(push(formatnil"~D wk"weeks)chunks))(formatt"~{~A~^, ~}~%"chunks)))))))(seconds->duration7259)(seconds->duration86400)(seconds->duration6000000)
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
Since the main function is general enough, it can be applied to other mixed bases, like the English system of measurements.
structNumberdefto_mixed_radix(*radices)result=Array(self).new(radices.size,0)n=self(0...radices.size).reverse_eachdo|i|breakifn==0divisor=radices[i]ifdivisor==0result[i]=nbreakendresult[i]=n%divisorn//=divisorendresultendenddefto_compound(num,radices,units)num.to_mixed_radix(*radices).zip(units).compact_map{|n,u|ifn!=0"#{n}#{u}"end}.join(", ")enddefsecs_to_compound(secs)to_compoundsecs,{0,7,24,60,60},["wk","d","hr","min","sec"]endputs"The task:"[7259,86400,6000000].eachdo|n|printf"%7s sec = %s\n",n,secs_to_compound(n)endputs"\n(nobody asked for this):"definches_to_compound(inches)to_compoundinches,{0,3,8,10,22,3,12},["lea","mi","fur","ch","yd","ft","in"]end[7259,86400,6000000].eachdo|n|printf"%7s in = %s\n",n,inches_to_compound(n)end
The task: 7259 sec = 2 hr, 59 sec 86400 sec = 1 d6000000 sec = 9 wk, 6 d, 10 hr, 40 min(nobody asked for this): 7259 in = 9 ch, 3 yd, 1 ft, 11 in 86400 in = 1 mi, 2 fur, 9 ch, 2 yd6000000 in = 31 lea, 1 mi, 5 fur, 5 ch, 16 yd, 2 ft
importstd.stdio,std.conv,std.algorithm;immutableuintSECSPERWEEK=604_800;immutableuintSECSPERDAY=86_400;immutableuintSECSPERHOUR=3_600;immutableuintSECSPERMIN=60;stringConvertSeconds(inuintseconds){uintrem=seconds;uintweeks=rem/SECSPERWEEK;rem%=SECSPERWEEK;uintdays=rem/SECSPERDAY;rem%=SECSPERDAY;uinthours=rem/SECSPERHOUR;rem%=SECSPERHOUR;uintmins=rem/SECSPERMIN;rem%=SECSPERMIN;stringformatted="";(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(", "))returnformatted[0..$-2];returnformatted;}voidmain(){7_259.ConvertSeconds.writeln;86_400.ConvertSeconds.writeln;6_000_000.ConvertSeconds.writeln;}
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
constTestData:array[0..2]ofinteger=(7259,86400,6000000);functionSecondsToFormatDate(Sec:integer):string;varDT:TDateTime;varWeeks:integer;varAYear,AMonth,ADay,AHour,AMinute,ASecond,AMilliSecond:Word;constSecPerDay=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}ifaDay<30thenaDay:=aDay+1elseaDay:=aDay-30;Result:='';ifWeeks<>0thenResult:=Result+IntToStr(Weeks)+' wk, ';ifADay<>0thenResult:=Result+IntToStr(ADay)+' d, ';ifAHour<>0thenResult:=Result+IntToStr(AHour)+' hr, ';ifAMinute<>0thenResult:=Result+IntToStr(AMinute)+' min, ';ifASecond<>0thenResult:=Result+IntToStr(ASecond)+' sec, ';end;procedureShowFormatedDataTime(Memo:TMemo);varI:integer;beginforI:=0toHigh(TestData)doMemo.Lines.Add(IntToStr(TestData[I])+' = '+SecondsToFormatDate(TestData[I]));end;
7259 = 2 hr, 59 sec, 86400 = 1 d, 6000000 = 9 wk, 6 d, 10 hr, 40 min, Elapsed Time: 2.900 ms.
createorreplacefunctionnonzero(n,text)as(if(n>0,format('{:d} {:s}',trunc(n),text),''));createorreplacefunctionseconds_to_time(secs)as(if(secs=0,'0 sec',[(secs//60//60//24//7).nonzero('wk'),((secs//60//60//24)%7).nonzero('d'),((secs//60//60)%24).nonzero('hr'),((secs//60)%60).nonzero('min'),(trunc(secs)%60).nonzero('sec')].list_filter(x->x!='').array_to_string(', ')));selectn,seconds_to_time(n)fromunnest([0,7259,86400,6000000])_(n);
┌─────────┬──────────────────────────┐│ n │ seconds_to_time(n) ││ int32 │ varchar │├─────────┼──────────────────────────┤│ 0 │ 0 sec ││ 7259 │ 2 hr, 59 sec ││ 86400 │ 1 d ││ 6000000 │ 9 wk, 6 d, 10 hr, 40 min │└─────────┴──────────────────────────┘
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 7259print split 86400print split 6000000
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
defmoduleConvertdo@minute60@hour@minute*60@day@hour*24@week@day*7@divisor[@week,@day,@hour,@minute,1]defsec_to_str(sec)do{_,[s,m,h,d,w]}=Enum.reduce(@divisor,{sec,[]},fndivisor,{n,acc}->{rem(n,divisor),[div(n,divisor)|acc]}end)["#{w} wk","#{d} d","#{h} hr","#{m} min","#{s} sec"]|>Enum.reject(fnstr->String.starts_with?(str,"0")end)|>Enum.join(", ")endendEnum.each([7259,86400,6000000],fnsec->:io.fwrite"~10w sec : ~s~n",[sec,Convert.sec_to_str(sec)]end)
7259 sec : 2 hr, 59 sec 86400 sec : 1 d 6000000 sec : 9 wk, 6 d, 10 hr, 40 min
Functionmapaccumr/3 is adapted fromhere.
Functionintercalate/2 is copied froma Tim Fletcher's GitHub repository.
-module(convert_seconds).-export([test/0]).test()->lists:map(funconvert/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)/=0end,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(funquotRem/2,N,Xs),[N_|Ys].quotRem(X1,X2)->{X1divX2,X1remX2}.% **************************************************% 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 d6000000 seconds = 9 wk, 6 d, 10 hr, 40 min
openSystemletconvertseconds=letspan=TimeSpan.FromSeconds(seconds|>float)let(wk,day)=Math.DivRem(span.Days,7)letparts=[(wk,"wk");(day,"day");(span.Hours,"hr");(span.Minutes,"min");(span.Seconds,"sec")]letresult=List.foldBack(fun(n,u)acc->(ifn>0thenn.ToString()+" "+uelse"")+(ifn>0&&acc.Length>0then", "else"")+acc)parts""ifresult.Length>0thenresultelse"0 sec"[<EntryPoint>]letmainargv=argv|>Seq.map(funstr->letsec=UInt32.Parsestrin(sec,convertsec))|>Seq.iter(fun(s,v)->printfn"%10i = %s"sv)0
>RosettaCode 7259 86400 6000000 7259 = 2 hr, 59 sec 86400 = 1 day 6000000 = 9 wk, 6 day, 10 hr, 40 min
USING:assocsiokernelmathmath.parserqwsequencessequences.generalizations;:mod/(xy--wz)/modswap;:convert(n--seq)60mod/60mod/24mod/7mod/5narrayreverse;:.time(n--)convert[number>string]mapqw{wkdhrminsec}zip[first"0"=]reject[" "join]map", "joinprint;7259 86400 6000000[.time]tri@
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
CREATEC0,:.,C@IF.","THEN1C!;:.TIME( n --)[6060247***]L/MOD?DUP-IF.,.."wk"THEN[606024**]L/MOD?DUP-IF.,.."d"THEN[6060*]L/MOD?DUP-IF.,.."hr"THEN[60]L/MOD?DUP-IF.,.."min"THEN?DUP-IF.,.."sec"THEN0C!;
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
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.
SUBROUTINEPROUST(T)!Remembrance of time passed.INTEGERT!The time, in seconds. Positive only, please.INTEGERNTYPES!How many types of time?PARAMETER(NTYPES=5)!This should do.INTEGERUSIZE(NTYPES)!Size of the time unit.CHARACTER*3UNAME(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*28TEXT!A scratchpad.INTEGERI,L,N,S!Assistants.S=T!A copy I can mess with.L=0!No text has been generated.DOI=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.1FORMAT(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.Castforththeresult.WRITE(6,*)T,">",TEXT(1:L),"<"!With annotation.END!Simple enough with integers.PROGRAMMARCEL!Stir the cup.CALLPROUST(7259)CALLPROUST(7260)CALLPROUST(86400)CALLPROUST(6000000)CALLPROUST(0)CALLPROUST(-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 version 1.05 32/64 bitSubShow(mAsLong)DimAsLongc(1To5)={604800,86400,3600,60,1}DimAsStringg(1To5)={" Wk"," d"," hr"," min"," sec"},commaDimAsLongb(1To5),flag,m2=mRedimAsLongs(0)FornAsLong=1To5Ifm>=c(n)ThenDoRedimPreserves(Ubound(s)+1)s(Ubound(s))=c(n)m=m-c(n)LoopUntilm<c(n)EndIfNextnFornAsLong=1ToUbound(s)FormAsLong=1To5Ifs(n)=c(m)Thenb(m)+=1NextmNextnPrintm2;" seconds = ";FornAsLong=1To5Ifb(n)Then:comma=Iif(n<5Andalsob(n+1),","," and"):flag+=1Ifflag=1Thencomma=""Printcomma;b(n);g(n);EndIfNextPrintEndSub#definesecondsShow7259secondsShow86400secondsShow6000000secondssleep
Output:
7259 seconds = 2 hr and 59 sec 86400 seconds = 1 d 6000000 seconds = 9 Wk, 6 d, 10 hr and 40 min
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 := weekn = eval[input["Enter duration in seconds: "]]res = n s -> [0, "wk", "d", "hr", "min", "sec", 0]res =~ %s/, 0[^,]+//gprintln[res]
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 nextend fn = stringNSLog(@"%@",fn CompoundDurationString(7259))NSLog(@"%@",fn CompoundDurationString(86400))NSLog(@"%@",fn CompoundDurationString(6000000))HandleEvents
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
Click this link to run this code
PublicSubMain()DimiInputAsInteger[]=[7259,86400,6000000]'Input detailsDimiChecksAsInteger[]=[604800,86400,3600,60]'Weeks, days, hours, mins in secondsDimiTimeAsNewInteger[5]'To store wk, d, hr, min & secDimiOriginal,iSec,iLoopAsInteger'Various integersDimsOrdAsString[]=[" wk"," d"," hr"," min"," sec"]'To add to the output stringDimsOutputAsString'Output stringForEachiSecIniInput'For each iInputiOriginal=iSec'Store orginal value in secondsiTime[4]=iSec'Store seconds in iTime[4]ForiLoop=0To3'Loop through wk, d, hr, min & secIfiTime[4]>=iChecks[iLoop]Then'Check if value is = to wk, d, hr, miniTime[iLoop]=Int(iTime[4]/iChecks[iLoop])'Put the correct value for wk, d, hr, min in iTimeiTime[4]=iTime[4]-(iTime[iLoop]*iChecks[iLoop])'Remove the amount of seconds for wk, d, hr, min from iTime[4]EndifNextForiLoop=0To4'Loop through wk, d, hr, min & secsIfiTime[iLoop]>0ThensOutput&=", "&Str(iTime[iLoop])&sOrd[iLoop]'Add comma and ordinal as neededNextIfLeft(sOutput,2)=", "ThensOutput=Mid(sOutput,3)'Remove unnecessary ", "sOutput=Format(Str(iOriginal),"#######")&" Seconds = "&sOutput'Add original seconds to the output stringPrintsOutput'Print sOutput stringsOutput=""'Clear the sOutput stringiTime=NewInteger[5]'Reset iTime[]NextEnd
Output:
7259 Seconds = 2 hr, 59 sec 86400 Seconds = 1 d6000000 Seconds = 9 wk, 6 d, 10 hr, 40 min
packagemainimport"fmt"funcmain(){fmt.Println(TimeStr(7259))fmt.Println(TimeStr(86400))fmt.Println(TimeStr(6000000))}funcTimeStr(secint)(resstring){wks,sec:=sec/604800,sec%604800ds,sec:=sec/86400,sec%86400hrs,sec:=sec/3600,sec%3600mins,sec:=sec/60,sec%60CommaRequired:=falseifwks!=0{res+=fmt.Sprintf("%d wk",wks)CommaRequired=true}ifds!=0{ifCommaRequired{res+=", "}res+=fmt.Sprintf("%d d",ds)CommaRequired=true}ifhrs!=0{ifCommaRequired{res+=", "}res+=fmt.Sprintf("%d hr",hrs)CommaRequired=true}ifmins!=0{ifCommaRequired{res+=", "}res+=fmt.Sprintf("%d min",mins)CommaRequired=true}ifsec!=0{ifCommaRequired{res+=", "}res+=fmt.Sprintf("%d sec",sec)}return}
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
importControl.Monad(forM_)importData.List(intercalate,mapAccumR)importSystem.Environment(getArgs)importText.Printf(printf)importText.Read(readMaybe)reduceBy::Integrala=>a->[a]->[a]n`reduceBy`xs=n':yswhere(n',ys)=mapAccumRquotRemnxs-- 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)]compdurst=letds=t`reduceBy`(mapfst$taildurLabs)infilter((/=0).fst)$zipds(mapsnddurLabs)-- Compound duration of t seconds. The argument is assumed to be positive.compoundDuration::Integer->StringcompoundDuration=intercalate", ".map(uncurry$printf"%d %s").compdursmain::IO()main=doargs<-getArgsforM_args$\arg->casereadMaybeargofJustn->printf"%7d seconds = %s\n"n(compoundDurationn)Nothing->putStrLn$"Invalid number of seconds: "++arg
7259 seconds = 2 hr, 59 sec 86400 seconds = 1 d6000000 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:
importData.List(intercalate,mapAccumR)---------------- COMPOUND DURATION STRINGS ---------------durationString::String->String->Int->Int->[String]->Int->StringdurationStringcomponentGapnumberLabelGapdaysPerWeekhoursPerDayxsn=intercalatecomponentGap(foldr(timeTagsnumberLabelGap)[](zip(weekPartsdaysPerWeekhoursPerDayn)xs))timeTags::String->(Int,String)->[String]->[String]timeTagsnumberLabelGap(n,s)xs|0<n=intercalatenumberLabelGap[shown,s]:xs|otherwise=xsweekParts::Int->Int->Int->[Int]weekPartsdaysPerWeekhoursPerDay=snd.flip(mapAccumRbyUnits)[0,daysPerWeek,hoursPerDay,60,60]byUnits::Int->Int->(Int,Int)byUnitsrestx=(quot(rest-m)u,m)where(u,m)|0<x=(x,remrestx)|otherwise=(1,rest)--------------------------- TEST -------------------------translation::String->Int->Int->Int->StringtranslationlocaldaysPerWeekhoursPerDayn=intercalate" -> "$[show,durationString", "" "daysPerWeekhoursPerDay(wordslocal)]<*>[n]main::IO()main=doletnames="wk d hr min sec"lettests=[7259,86400,6000000]putStrLn"Assuming 24 hrs per day:"mapM_(putStrLn.translationnames724)testsputStrLn"\nor, at 8 hours per day, 5 days per week:"mapM_(putStrLn.translationnames58)tests
Assuming 24/7:7259 -> 2 hr, 59 sec86400 -> 1 d6000000 -> 9 wk, 6 d, 10 hr, 40 minor, at 8 working hours per day, 5 days per week:7259 -> 2 hr, 59 sec86400 -> 3 d6000000 -> 41 wk, 3 d, 2 hr, 40 min
// @test: [compound(s) | s <- [7259, 86400, 6000000]]compound s = (s / 604800, s % 604800 / 86400, s % 86400 / 3600, s % 3600 / 60, s % 60)
0 0 2 0 590 1 0 0 09 6 10 40 0
Implementation:
fmtsecs=:verbdefineseq=.07246060#:y}:;:inv,(0~:seq)#(8!:0seq),.<;.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:
fmtsecs72592hr,59secfmtsecs864001dfmtsecs60000009wk,6d,10hr,40min
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}This is a relatively simple task in Java, using the modulus-remainder operator.
Stringduration(intseconds){StringBuilderstring=newStringBuilder();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));}returnstring.toString();}
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
An alternate demonstration
publicclassCompoundDuration{publicstaticvoidmain(String[]args){compound(7259);compound(86400);compound(6000_000);}privatestaticvoidcompound(longseconds){StringBuildersb=newStringBuilder();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);}privatestaticlongaddUnit(StringBuildersb,longsec,longunit,Strings){longn;if((n=sec/unit)>0){sb.append(n).append(s);sec%=(n*unit);}returnsec;}}
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
(function(){'use strict';// angloDuration :: Int -> StringfunctionangloDuration(intSeconds){returnzip(weekParts(intSeconds),['wk','d','hr','min','sec']).reduce(function(a,x){returna.concat(x[0]?([(x[0].toString()+' '+x[1])]):[]);},[]).join(', ');}// weekParts :: Int -> [Int]functionweekParts(intSeconds){return[undefined,7,24,60,60].reduceRight(function(a,x){varintRest=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)]functionzip(xs,ys){returnxs.length===ys.length?(xs.map(function(x,i){return[x,ys[i]];})):undefined;}// TESTreturn[7259,86400,6000000].map(function(intSeconds){returnintSeconds.toString()+' -> '+angloDuration(intSeconds);}).join('\n');})();
7259 -> 2 hr, 59 sec86400 -> 1 d6000000 -> 9 wk, 6 d, 10 hr, 40 min
(()=>{"use strict";// ---------------- COMPOUND DURATION ----------------// compoundDuration :: [String] -> Int -> StringconstcompoundDuration=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]constweekParts=nSeconds=>[0,7,24,60,60].reduceRight((a,x)=>{constr=a[0],mod=x!==0?r%x:r;return[(r-mod)/(x||1),[mod,...a[1]]];},[nSeconds,[]])[1];// ---------------------- TEST -----------------------// main :: IO ()constmain=()=>{constlocalNames=["wk","d","hr","min","sec"];return[7259,86400,6E6].map(nSeconds=>`${nSeconds} ->${compoundDuration(localNames)(nSeconds)}`).join("\n");};// MAIN ---returnmain();})();
7259 -> 2 hr, 59 sec86400 -> 1 d6000000 -> 9 wk, 6 d, 10 hr, 40 min
Also works with gojq, the Go implementation
The program shown below will also work with jaq, the Rust implementation of jq, provided `%` is replaced everywhere by `| floor %`.The program so altered would still run using the C and Go implementations of jq.
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)"
$jq-r-n-fConvert_seconds_to_compound_duration.jq0:0sec7259:2hr,59sec86400:1d6000000:9wk,6d,10hr,40min
# 1.xfunctionduration(sec::Integer)::Stringt=Array{Int}([])fordmin(60,60,24,7)sec,m=divrem(sec,dm)pushfirst!(t,m)endpushfirst!(t,sec)returnjoin(["$num$unit"for(num,unit)inzip(t,["w","d","h","m","s"])ifnum>0],", ")end@showduration(7259)@showduration(86400)@showduration(6000000)
duration(7259) = "2h, 59s"duration(86400) = "1d"duration(6000000) = "9w, 6d, 10h, 40m"
F:{", "/" "/'+($x[s]),s:,&0<x}(" "\"wk d hr min sec")!07246060\
Examples:
F100"1 min, 40 sec"F7259"2 hr, 59 sec"F86400"1 d"F6000000"9 wk, 6 d, 10 hr, 40 min"
tested in ngn/k
funcompoundDuration(n:Int):String{if(n<0)return""// task doesn't ask for negative integers to be convertedif(n==0)return"0 sec"valweeks:Intvaldays:Intvalhours:Intvalminutes:Intvalseconds:Intvardivisor:Int=7*24*60*60varrem:Intvarresult=""weeks=n/divisorrem=n%divisordivisor/=7days=rem/divisorrem%=divisordivisor/=24hours=rem/divisorrem%=divisordivisor/=60minutes=rem/divisorseconds=rem%divisorif(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"elseresult=result.substring(0,result.length-2)returnresult}funmain(args:Array<String>){valdurations=intArrayOf(0,7,84,7259,86400,6000000)durations.forEach{println("$it\t-> ${compoundDuration(it)}")}}
0 -> 0 sec7 -> 7 sec84 -> 1 min, 24 sec7259 -> 2 hr, 59 sec86400 -> 1 d6000000 -> 9 wk, 6 d, 10 hr, 40 min
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]}}"] }, by=", ")}7259 sec = 2 hr, 59 sec 86400 sec = 1 d6000000 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.
I got a bit carried away and added 'years'...
[start]input "Enter SECONDS: "; secondsseconds=int(abs(seconds))if seconds=0 then print "Program complete.": endUnitsFound=0: LastFound$=""years=int(seconds/31449600): seconds=seconds mod 31449600if years then LastFound$="years"weeks=int(seconds/604800): seconds=seconds mod 604800if weeks then LastFound$="weeks"days=int(seconds/86400): seconds=seconds mod 86400if days then LastFound$="days"hours=int(seconds/3600): seconds=seconds mod 3600if hours then LastFound$="hours"minutes=int(seconds/60): seconds=seconds mod 60if 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 selectselect 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 selectselect 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 selectselect 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 selectselect 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 selectselect 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 selectprintgoto [start]
Enter SECONDS: 72592 hours and 59 secondsEnter SECONDS: 864001 dayEnter SECONDS: 60000009 weeks, 6 days, 10 hours and 40 minutesEnter SECONDS: 98765432131 years, 21 weeks, 4 hours, 25 minutes and 21 secondsEnter SECONDS:Program complete.
functionduration(secs)localunits,dur={"wk","d","hr","min"},""fori,vinipairs({604800,86400,3600,60})doifsecs>=vthendur=dur..math.floor(secs/v).." "..units[i]..", "secs=secs%vendendifsecs==0thenreturndur:sub(1,-3)elsereturndur..secs.." sec"endendprint(duration(7259))print(duration(86400))print(duration(6000000))
tim:=proc(s)localweeks,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)))endproc;
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}]
7259secs =2 hr, 59 sec86400secs =1 d, 6000000secs =9 wk, 6 d, 10 hr, 40 min,
fromstrutilsimportaddSepconstUnits=[" 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)varduration=secvaridx=0whileduration!=0:letq=durationdivQuantities[idx]ifq!=0:duration=durationmodQuantities[idx]result.addSep(", ",0)result.add($q&Units[idx])incidx#———————————————————————————————————————————————————————————————————————————————————————————————————whenisMainModule:forsecin[7259,86400,6000000]:echosec,"s = ",$$sec
7259s = 2 hr, 59 sec86400s = 1 d6000000s = 9 wk, 6 d, 10 hr, 40 min
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).
importtimesfromalgorithmimportreversedfromstrutilsimportaddSepconstUnits=[" 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)varduration=initDuration(seconds=sec)letparts=reversed(duration.toParts[Seconds..Weeks])foridx,partinparts:ifpart!=0:result.addSep(", ",0)result.add($part&Units[idx])#———————————————————————————————————————————————————————————————————————————————————————————————————whenisMainModule:forsecin[7259,86400,6000000]:echosec,"s = ",$$sec
Output is the same.
letdivisors=[(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")] *)letcompute_durationsecs=letrecdoloopremainres=function|[]->res|(n,s)::ds->doloop(remain/n)((remainmodn,s)::res)dsindoloopsecs[](List.revdivisors)(* 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" *)letpretty_printdur=List.filter(fun(d,_)->d<>0)dur|>List.map(fun(d,l)->Printf.sprintf"%d %s"dl)|>String.concat", "(* Transform a number of seconds into the corresponding compound duration * string. * Not sure what to do with 0... *)letcompound=function|nwhenn>0->compute_durationn|>pretty_print|nwhenn=0->string_of_int0^"..."|_->invalid_arg"Number of seconds must be positive"(* Some testing... *)let()=lettest_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")]inlettestit(n,s)=letcalc=compoundninPrintf.printf"[%s] %d seconds -> %s; expected: %s\n"(ifcalc=sthen"PASS"else"FAIL")ncalcsinList.itertestittest_cases
[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
Note: my own string function ssubstr() was used. You can find it here on RosettaCode Wiki.
\\ Convert seconds to compound duration\\ 4/11/16 aevsecs2compdur(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));}2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
programconvertSecondsToCompoundDuration(output);constsuffixUnitWeek='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;typewholeNumber=0..maxInt;naturalNumber=1..maxInt;canonicalTimeSpan=recordweeks: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}functiongetCanonicalTimeSpan(duration:wholeNumber):canonicalTimeSpan;{ Perform `div`ision and update `duration`. }functionsplit(protectedunit:naturalNumber):wholeNumber;beginsplit:=durationdivunit;duration:=durationmodunitend;varresult:canonicalTimeSpan;beginwithresultdobeginweeks:=split(week);days:=split(day);hours:=split(hour);minutes:=split(minute);seconds:=durationend;{ In Pascal there needs to be _exactly_ one assignment to the }{ result variable bearing the same name as of the `function`. }getCanonicalTimeSpan:=resultend;{\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}functiontimeSpanString(protectedn:naturalNumber):stringFitForTimeSpan;constqs=quantitySeparator;varresult:stringFitForTimeSpan;beginwithgetCanonicalTimeSpan(n)dobegin{ `: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));ifdays>0thenbeginwriteStr(result,result,qs:ord(length(result)>0)*length(qs),days:1,suffixSeparator,suffixUnitDay);end;ifhours>0thenbeginwriteStr(result,result,qs:ord(length(result)>0)*length(qs),hours:1,suffixSeparator,suffixUnitHour);end;ifminutes>0thenbeginwriteStr(result,result,qs:ord(length(result)>0)*length(qs),minutes:1,suffixSeparator,suffixUnitMinute);end;ifseconds>0thenbeginwriteStr(result,result,qs:ord(length(result)>0)*length(qs),seconds:1,suffixSeparator,suffixUnitSecond);endend;timeSpanString:=resultend;{ === MAIN ============================================================= }beginwriteLn(7259,' seconds are “',timeSpanString(7259),'”');writeLn(86400,' seconds are “',timeSpanString(86400),'”');writeLn(6000000,' seconds are “',timeSpanString(6000000),'”')end.
7259 seconds are “2 hr, 59 sec” 86400 seconds are “1 d” 6000000 seconds are “9 wk, 6 d, 10 hr, 40 min”
usestrict;usewarnings;subcompound_duration{my$sec=shift;nowarnings'numeric';returnjoin', ',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($_)}
7259 sec = 2 hr, 59 sec 86400 sec = 1 d6000000 sec = 9 wk, 6 d, 10 hr, 40 min
More general approach for mixed-radix conversions.
usestrict;usewarnings;useMath::AnyNum'polymod';subcompound_duration{my$seconds=shift;my@terms;my@durations=reversepolymod($seconds,60,60,24,7);my@timespans=<wkdhrminsec>;while(my$d=shift@durations,my$t=shift@timespans){push@terms,"$d $t"if$d}join', ',@terms}for(<72598640060000003380521>){printf"%7d sec = %s\n",$_,compound_duration($_)}
7259 sec = 2 hr, 59 sec 86400 sec = 1 d6000000 sec = 9 wk, 6 d, 10 hr, 40 min3380521 sec = 5 wk, 4 d, 3 hr, 2 min, 1 sec
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)
withjavascript_semantics?elapsed(7259)?elapsed(86400)?elapsed(6000000)
"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:
withjavascript_semanticsincludetimedate.e?elapsed(6000000-timedelta(days:=6,hours:=10))
"9 weeks, 40 minutes"
(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 sec86400 1 d6000000 9 wk, 6 d, 10 hr, 40 min
/* 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 sec3 more to come.
localfunctionduration(s)ifs<1thenreturn"0 sec"endlocaldur=""localdivs={7,24,60,60,1}localunits={"wk","d","hr","min","sec"}localt=divs:reduce(|prod,div|->prod*div,1)fori=1,#divsdolocalu=s//tifu>0thendur..=$"{u} {units[i]}, "s%=tendt//=divs[i]endifdur:endswith(", ")thendur=dur:sub(1,-3)endreturndurendfor{7259,86400,6000000}assdoprint(duration(s))end
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
functionGet-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-PropertyWeeks,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", ")}}
PS C:\Scripts> 7259, 86400, 6000000 | ForEach-Object { Get-Time -Seconds $_ }2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 minPS C:\Scripts> Get-Time -Start 3/10/2016 -End 1/20/201745 wk, 1 dPS C:\Scripts> Get-Time -Seconds 6000000 -AsObjectWeeks : 9RemainingDays : 6Days : 69Hours : 10Minutes : 40Seconds : 0Milliseconds : 0Ticks : 60000000000000TotalDays : 69.4444444444444TotalHours : 1666.66666666667TotalMinutes : 100000TotalSeconds : 6000000TotalMilliseconds : 6000000000Works 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#=NmodDiv,times(T,Rem,Rest).% specifify the different time split typestime_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).
?- maplist(compound_time, [7259,86400,6000000]), !.7259: 2 hr, 59 sec86400: 1 d6000000: 9 wk, 6 d, 10 hr, 40 mintrue.?- times(N, [[wk, 9],[d, 6],[hr,10],[min,40]]), !.N = 6000000.
EnableExplicitProcedure.sConvertSeconds(NbSeconds)Protectedweeks,days,hours,minutes,secondsProtecteddivisor,remainderProtectedduration$=""divisor=7*24*60*60;secondsinaweekweeks=NbSeconds/divisorremainder=NbSeconds%divisordivisor/7;secondsinadaydays=remainder/divisorremainder%divisordivisor/24;secondsinanhourhours=remainder/divisorremainder%divisordivisor/60;secondsinaminuteminutes=remainder/divisorseconds=remainder%divisorIfweeks>0duration$+Str(weeks)+" wk, "EndIfIfdays>0duration$+Str(days)+" d, "EndIfIfhours>0duration$+Str(hours)+" hr, "EndIfIfminutes>0duration$+Str(minutes)+" min, "EndIfIfseconds>0duration$+Str(seconds)+" sec"EndIfIfRight(duration$,2)=", "duration$=Mid(duration$,0,Len(duration$)-2)EndIfProcedureReturnduration$EndProcedureIfOpenConsole()PrintN(ConvertSeconds(7259))PrintN(ConvertSeconds(86400))PrintN(ConvertSeconds(6000000))PrintN("")PrintN("Press any key to close the console")Repeat:Delay(10):UntilInkey()<>""CloseConsole()EndIf
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
>>>defduration(seconds):t=[]fordmin(60,60,24,7):seconds,m=divmod(seconds,dm)t.append(m)t.append(seconds)return', '.join('%d%s'%(num,unit)fornum,unitinzip(t[::-1],'wk d hr min sec'.split())ifnum)>>>forsecondsin[7259,86400,6000000]:print("%7d sec =%s"%(seconds,duration(seconds)))7259sec=2hr,59sec86400sec=1d6000000sec=9wk,6d,10hr,40min>>>
>>>defduration(seconds,_maxweeks=99999999999):return', '.join('%d%s'%(num,unit)fornum,unitinzip([(seconds//d)%mford,min((604800,_maxweeks),(86400,7),(3600,24),(60,60),(1,60))],['wk','d','hr','min','sec'])ifnum)>>>forsecondsin[7259,86400,6000000]:print("%7d sec =%s"%(seconds,duration(seconds)))7259sec=2hr,59sec86400sec=1d6000000sec=9wk,6d,10hr,40min>>>
Or, composing a solution from pure curried functions, including themapAccumR abstraction (a combination of ofmap andreduce, 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'''fromfunctoolsimportreducefromitertoolsimportchain# compoundDurationFromUnits :: [Num] -> [String] -> Num -> [(Num, String)]defcompoundDurationFromUnits(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. '''returnlambdaks:lambdan:list(chain.from_iterable(map(lambdav,k:[(v,k)]if0<velse[],mapAccumR(lambdaa,x:divmod(a,x)if0<xelse(1,a))(n)(qs)[1],ks)))# --------------------------TEST---------------------------# main :: IO ()defmain():'''Tests of various durations, with a particular set of units and labels. '''print(fTable('Compound durations from numbers of seconds:\n')(str)(quoted("'"))(lambdan:', '.join([str(v)+' '+kforv,kincompoundDurationFromUnits([0,7,24,60,60])(['wk','d','hr','min','sec'])(n)]))([7259,86400,6000000]))# -------------------------GENERIC-------------------------# fTable :: String -> (a -> String) -># (b -> String) -> (a -> b) -> [a] -> StringdeffTable(s):'''Heading -> x display function -> fx display function -> f -> xs -> tabular string. '''defgo(xShow,fxShow,f,xs):ys=[xShow(x)forxinxs]w=max(map(len,ys))returns+'\n'+'\n'.join(map(lambdax,y:y.rjust(w,' ')+' -> '+fxShow(f(x)),xs,ys))returnlambdaxShow:lambdafxShow:lambdaf:lambdaxs:go(xShow,fxShow,f,xs)# mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])defmapAccumR(f):'''A tuple of an accumulation and a list derived by a combined map and fold, with accumulation from right to left. '''defgo(a,x):acc,y=f(a[0],x)return(acc,[y]+a[1])returnlambdaacc:lambdaxs:(reduce(go,reversed(xs),(acc,[])))# quoted :: Char -> String -> Stringdefquoted(c):'''A string flanked on both sides by a specified quote character. '''returnlambdas:c+s+c# MAIN ---if__name__=='__main__':main()
Compound durations from numbers of seconds: 7259 -> '2 hr, 59 sec' 86400 -> '1 d'6000000 -> '9 wk, 6 d, 10 hr, 40 min'
[ ' [ 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 ]
7259 seconds is 2 hr, 59 sec.86400 seconds is 1 d.6000000 seconds is 9 wk, 6 d, 10 hr, 40 min.
duration<-function(t){max_units<-c("sec"=60,"min"=60,"hr"=24,"d"=7)times<-numeric(4)for(iin1:4){times[i]<-t%%max_units[i]t<-t%/%max_units[i]}times<-c(times,t)names(times)<-c(names(max_units),"wk")times<-rev(Filter(`+`,times))cat(paste(times,names(times)),sep=", ")cat("\n")}lapply(c(7259,86400,6000000),duration)|>invisible()
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
#langracket/base(requireracket/stringracket/list)(define(seconds->compound-durationss)(define-values(wd.h.m.s)(for/fold((prev-qs)(rs(list)))((Q(in-list(list6060247))))(define-values(qr)(quotient/remainderprev-qQ))(valuesq(consrrs))))(conswd.h.m.s))(define(maybe-suffixvn)(and(positive?v)(format"~a ~a"vn)))(define(seconds->compound-duration-strings)(string-join(filter-mapmaybe-suffix(seconds->compound-durationss)'("wk""d""hr""min""sec"))", "))(module+test(requirerackunit)(check-equal?(seconds->compound-durations7259)(list002059))(check-equal?(seconds->compound-durations86400)(list01000))(check-equal?(seconds->compound-durations6000000)(list9610400))(check-equal?(seconds->compound-duration-string7259)"2 hr, 59 sec")(check-equal?(seconds->compound-duration-string86400)"1 d")(check-equal?(seconds->compound-duration-string6000000)"9 wk, 6 d, 10 hr, 40 min"));; Tim Brown 2015-07-21
All tests pass... there is no output.
(formerly Perl 6)
The built-inpolymod method (which is a generalization of thedivmod function known from other languages), is a perfect match for a task like this:
subcompound-duration ($seconds) { ($seconds.polymod(60,60,24,7)Z<sec min hr d wk>) .grep(*[0]).reverse.join(", ")}# Demonstration:for7259,86400,6000000 {say"{.fmt: '%7d'} sec = {compound-duration $_}";}
7259 sec = 2 hr, 59 sec 86400 sec = 1 d6000000 sec = 9 wk, 6 d, 10 hr, 40 min
/* REXX ---------------------------------------------------------------* Format seconds into a time string*--------------------------------------------------------------------*/Calltest7259,'2 hr, 59 sec'Calltest86400,'1 d'Calltest6000000,'9 wk, 6 d, 10 hr, 40 min'Calltest123.50,'2 min, 3.5 sec'Calltest123.00,'2 min, 3 sec'Calltest0.00,'0 sec'Exittest:Parseargsecs,xresres=sec2ct(secs)SayresIfres<>xresThenSay'**ERROR**'Returnsec2ct:ParseArgs/*m=s%60; s=s//60h=m%60; m=m//60d=h%24; h=h//24w=d%7; d=d//7*/Ifs=0ThenReturn'0 sec'ParseValuesplit(s,60)withmsParseValuesplit(m,60)withhmParseValuesplit(h,24)withdhParseValuesplit(d,7)withwdol=''Ifw>0Thenol=olw'wk,'Ifd>0Thenol=old'd,'Ifh>0Thenol=olh'hr,'Ifm>0Thenol=olm'min,'Ifs>0Thenol=ol(s/1)'sec'ol=strip(ol)ol=strip(ol,,',')Returnolsplit:ProcedureParseArgwhat,howa=what%howb=what//howReturnab
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min2 min, 3.5 sec2 min, 3 sec0 sec
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.*/parsearg@;if@=''then@=7259864006000000/*Not specified? Then use the default.*/doj=1forwords(@);z=word(@,j)/* [↓] process each number in the list*/sayright(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:parseargx/*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 " " */ifx\==0thens=word(s0,1)+x'sec'/*handle fractional (residual) seconds.*/$=strip(space(wdhms),,",");if$==''thenz=0"sec"/*handle 0 sec.*/return$/*──────────────────────────────────────────────────────────────────────────────────────*/timeU:parseargu,$;_=x%u;if_==0thenreturn'';x=x-_*u;return_$","
7259 seconds: 2 hr, 59 sec 86400 seconds: 1 d 6000000 seconds: 9 wk, 6 d, 10 hr, 40 min
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
sec = 6000005week = floor(sec/60/60/24/7)if week > 0 see sec see " seconds is " + week + " weeks " okday = floor(sec/60/60/24) % 7if day > 0 see day see " days " ok hour = floor(sec/60/60) % 24if hour > 0 see hour see " hours " ok minute = floor(sec/60) % 60if minute > 0 see minute see " minutes " oksecond = sec % 60if second > 0 see second see " seconds" + nl ok
≪ MOD LAST / FLOOR ≫ 'DIVMOD' STO≪ {" wk" " d" " hr" " min" " sec" } → unit ≪ 60DIVMOD 60DIVMOD 24DIVMOD 7DIVMOD 1 SF "" 1 unit SIZEFOR jIF SWAPTHEN LAST →STR unit j GET +IF 1 FC?CTHEN ", " SWAP +END +ENDNEXT≫ ≫ '→CDUR' STO
Users of HP-48G and newer models can replace the60DIVMOD 60DIVMOD 24DIVMOD 7DIVMOD line by:
{ 60 60 24 7 } 1 ≪ MOD LAST / FLOOR ≫ DOSUBS OBJ→ DROP7259→CDUR86400→CDUR6000000→CDUR10!→CDUR
4: "2 hr, 59 sec"3: "1 d"2: "9 wk, 6 d, 10 hr, 40 min"1: "6 wk"
MINUTE=60HOUR=MINUTE*60DAY=HOUR*24WEEK=DAY*7defsec_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 sec86400: 1 d6000000: 9 wk, 6 d, 10 h, 40 min
sec = 6000005week= int(sec/60/60/24/7)day= int(sec/60/60/24) mod 7hour= int(sec/60/60) mod 24minute= int(sec/60) mod 60second= sec mod 60print 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"
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.
usestd::fmt;structCompoundTime{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;)+}}}implCompoundTime{#[inline]fnnew(w:usize,d:usize,h:usize,m:usize,s:usize)->Self{CompoundTime{w:w,d:d,h:h,m:m,s:s,}}#[inline]fnbalance(&mutself){reduce!(self,(s,m,60),(m,h,60),(h,d,24),(d,w,7));}}implfmt::DisplayforCompoundTime{fnfmt(&self,f:&mutfmt::Formatter)->fmt::Result{write!(f,"{}w {}d {}h {}m {}s",self.w,self.d,self.h,self.m,self.s)}}fnmain(){letmutct=CompoundTime::new(0,3,182,345,2412);println!("Before: {}",ct);ct.balance();println!("After: {}",ct);}
//Converting Seconds to Compound Durationobjectseconds{defmain(args:Array[String]){println("Enter the no.")valinput=scala.io.StdIn.readInt()varweek_r:Int=input%604800varweek:Int=(input-week_r)/604800varday_r:Int=week_r%86400varday:Int=(week_r-day_r)/86400varhour_r:Int=day_r%3600varhour:Int=(day_r-hour_r)/3600varminute_r:Int=hour_r%60varminute:Int=(hour_r-minute_r)/60varsec:Int=minute_r%60println("Week = "+week)println("Day = "+day)println("Hour = "+hour)println("Minute = "+minute)println("Second = "+sec)}}
This version uses delete from SRFI 1 and string-join from SRFI 13:
(import(schemebase)(schemewrite)(srfi1)(only(srfi13)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->durationseconds)(define(formatvalunit)(if(zero?val)""(string-append(number->stringval)" "unit)))(let*-values(((weekswk-remainder)(floor/seconds*seconds-in-week*))((daysdy-remainder)(floor/wk-remainder*seconds-in-day*))((hourshr-remainder)(floor/dy-remainder*seconds-in-hour*))((minutesmn-remainder)(floor/hr-remainder*seconds-in-minute*)))(string-join(delete""(list(formatweeks"wk")(formatdays"d")(formathours"hr")(formatminutes"min")(formatmn-remainder"sec"))string=?)", ")))(display(seconds->duration7259))(newline)(display(seconds->duration86400))(newline)(display(seconds->duration6000000))(newline)
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
funcpolymod(n,*divs){gather{divs.each{|i|varm=take(n%i)(n-=m)/=i}take(n)}}funccompound_duration(seconds){(polymod(seconds,60,60,24,7)~Z<secminhrdwk>).grep{|a|a[0]>0}.reverse.map{.join(' ')}.join(', ')}[7259,86400,6000000].each{|s|say"#{'%7d'%s} sec =#{compound_duration(s)}"}
7259 sec = 2 hr, 59 sec 86400 sec = 1 d6000000 sec = 9 wk, 6 d, 10 hr, 40 min
localfunfmtNonZero(0,_,list)=list|fmtNonZero(n,s,list)=Int.toStringn^" "^s::listfundivModHead(_,[])=[]|divModHead(d,head::tail)=headdivd::headmodd::tailinfuncompoundDurationseconds=letvaldigits=foldldivModHead[seconds][60,60,24,7]andunits=["wk","d","hr","min","sec"]inString.concatWith", "(ListPair.foldrfmtNonZero[](digits,units))endendval()=app(fns=>print(compoundDurations^"\n"))[7259,86400,6000000]
funcduration(_secs:Int)->String{ifsecs<=0{return""}letunits=[(604800,"wk"),(86400,"d"),(3600,"hr"),(60,"min")]varsecs=secsvarresult=""for(period,unit)inunits{ifsecs>=period{result+="\(secs/period)\(unit), "secs=secs%period}}ifsecs==0{result.removeLast(2)// remove ", "}else{result+="\(secs) sec"}returnresult}print(duration(7259))print(duration(86400))print(duration(6000000))
The data-driven procedure below can be customised to use different breakpoints, simply by editing the dictionary.
procsec2str{i}{setfactors{sec60min60hr24d7wkInf}setresult""foreach{labelmax}$factors{if{$i>=$max}{setr[expr{$i%$max}]seti[expr{$i/$max}]if{$r}{lappendresult"$r $label"}}else{if{$i>0}{lappendresult"$i $label"}break}}join[lreverse$result]", "}proccheck{cmdres}{setr[uplevel1$cmd]if{$req$res}{puts"Ok! $cmd \t = $res"}else{puts"ERROR: $cmd = $r \t expected $res"}}check{sec2str7259}{2hr,59sec}check{sec2str86400}{1d}check{sec2str6000000}{9wk,6d,10hr,40min}
Ok! sec2str 7259 = 2 hr, 59 secOk! sec2str 86400 = 1 dOk! sec2str 6000000 = 9 wk, 6 d, 10 hr, 40 min
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? PrintReturn_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 EndIfReturn (a@)_wk Print " wk"; : Return_d Print " d"; : Return_hr Print " hr"; : Return_min Print " min"; : Return
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min0 OK, 0:94
# Builds a string representation of a time periodUnits ← {"second" "minute" "hour" "day" "week"}Durations ← [60 60 24 7 9999]Parts ← ⇌◌∧(⊙⊂⊃(⌊÷|◿))Durations⊙[] # seconds -> [S M H D W]Sunit ← /⍚$"_ _"⍥⍜(⊡1|⍚⊂⊙@s)≠□"1"⊢. # Stringify a unit, add plurals.String ← /◇$"_, _"⇌≡Sunit▽⊃(±|⍉⇌⊟Units°⋕) Parts # Build full string.≡(&p$"_s \t= _"⟜String)[7259 86400 6000000 14000000 31449599 31449601]7259s = 2 hours, 59 seconds86400s = 1 day6000000s = 9 weeks, 6 days, 10 hours, 40 minutes14000000s = 23 weeks, 1 day, 53 minutes, 20 seconds31449599s = 51 weeks, 6 days, 23 hours, 59 minutes, 59 seconds31449601s = 52 weeks, 1 second
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;}PrivateFunctioncompound_duration(ByValsecondsAsLong)AsStringminutes=60hours=60*minutesdays_=24*hoursweeks=7*days_DimoutAsStringw=seconds\weeksseconds=seconds-w*weeksd=seconds\days_seconds=seconds-d*days_h=seconds\hoursseconds=seconds-h*hoursm=seconds\minutess=secondsModminutesout=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","")IfRight(out,2)=", "Thencompound_duration=Left(out,Len(out)-2)Elsecompound_duration=outEndIfEndFunctionPublicSubcstcd()Debug.Printcompound_duration(7259)Debug.Printcompound_duration(86400)Debug.Printcompound_duration(6000000)EndSub
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
Functioncompound_duration(n)DoUntiln=0Ifn>=604800Thenwk=Int(n/604800)n=n-(604800*wk)compound_duration=compound_duration&wk&" wk"EndIfIfn>=86400Thend=Int(n/86400)n=n-(86400*d)Ifwk>0Thencompound_duration=compound_duration&", "EndIfcompound_duration=compound_duration&d&" d"EndIfIfn>=3600Thenhr=Int(n/3600)n=n-(3600*hr)Ifd>0Thencompound_duration=compound_duration&", "EndIfcompound_duration=compound_duration&hr&" hr"EndIfIfn>=60Thenmin=Int(n/60)n=n-(60*min)Ifhr>0Thencompound_duration=compound_duration&", "EndIfcompound_duration=compound_duration&min&" min"EndIfIfn>0ThenIfmin>0Thencompound_duration=compound_duration&", "EndIfcompound_duration=compound_duration&", "&n&" sec"n=0EndIfLoopEndFunction'validating the functionWScript.StdOut.WriteLinecompound_duration(7259)WScript.StdOut.WriteLinecompound_duration(86400)WScript.StdOut.WriteLinecompound_duration(6000000)
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
varduration=Fn.new{|s|if(s<1)return"0 sec"vardur=""vardivs=[7,24,60,60,1]varunits=["wk","d","hr","min","sec"]vart=divs.reduce{|prod,div|prod*div}for(iin0...divs.count){varu=(s/t).floorif(u>0){dur=dur+"%(u)%(units[i]), "s=s%t}t=t/divs[i]}if(dur.endsWith(", "))dur=dur[0..-3]returndur}for(sin[7259,86400,6000000])System.print(duration.call(s))
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
char Str(80);func Duration(Sec); \Convert seconds to compound durationint 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+LFI:= 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));]
2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
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();}2 hr, 59 sec1 d9 wk, 6 d, 10 hr, 40 min
10LETm=60:LETh=60*m:LETd=h*24:LETw=d*720DATA10,7259,86400,6000000,0,1,60,3600,604799,604800,69486130READn40FORi=1TOn50READs60LETnweek=0:LETnday=0:LETnhour=0:LETnmin=0:LETnsec=0:LETs$=""70PRINTs;" = ";80IFs>=wTHENLETnweek=INT(s/w):LETs=FNm(s,w)90IFs>=dTHENLETnday=INT(s/d):LETs=FNm(s,d)100IFs>=hTHENLETnhour=INT(s/h):LETs=FNm(s,h)110IFs>=mTHENLETnmin=INT(s/m):LETs=FNm(s,m)120LETnsec=INT(s)130IFnweek>0THENLETs$=s$+STR$nweek+" wk, "140IFnday>0THENLETs$=s$+STR$nday+" d, "150IFnhour>0THENLETs$=s$+STR$nhour+" hr, "160IFnmin>0THENLETs$=s$+STR$nmin+" min, "170IFnsec>0THENLETs$=s$+STR$nsec+" sec"180IFs$<>""THENIFs$(LENs$-1)=","THENLETs$=s$(TOLENs$-2)190PRINTs$200NEXTi210STOP220DEF FNm(a,b)=a-INT(a/b)*b