Search code examples
bashdatetimetimetimerdata-conversion

Bash: Display Seconds in Days, Hours, Minutes, Seconds


I have a function, inspired by hms from here, but I wish to extend it to include handling and displaying Days.

I started editing the script but quickly realized I'm out of my depth with handling the logic of hours running into days and visa versa...

Here's what I have so far:

#!/bin/bash

rendertimer(){
    # convert seconds to Days, Hours, Minutes, Seconds
    # thanks to https://www.shellscript.sh/tips/hms/
    local seconds D H M S MM D_TAG H_TAG M_TAG S_TAG
    seconds=${1:-0}
    S=$((seconds%60))
    MM=$((seconds/60)) # total number of minutes
    M=$((MM%60))
    H=$((MM/60))
    D=$((H/24))

    # set up "x day(s), x hour(s), x minute(s) and x second(s)" format
    [ "$D" -eq "1" ] && D_TAG="day" || D_TAG="days"
    [ "$H" -eq "1" ] && H_TAG="hour" || H_TAG="hours"
    [ "$M" -eq "1" ] && M_TAG="minute" || M_TAG="minutes"
    [ "$S" -eq "1" ] && S_TAG="second" || S_TAG="seconds"
    # logic for handling display
    [ "$D" -gt "0" ] && printf "%d %s " $D "${D_TAG},"
    [ "$H" -gt "0" ] && printf "%d %s " $H "${H_TAG},"
    [ "$seconds" -ge "60" ] && printf "%d %s " $M "${M_TAG} and"
    printf "%d %s\n" $S "${S_TAG}"
}

duration=${1}

howlong="$(rendertimer $duration)"
echo "That took ${howlong} to run."

Desired output

349261 seconds: "That took 4 days, 1 hour, 1 minute and 1 second to run."

127932 seconds: "That took 1 day, 11 hours, 32 minutes and 12 seconds to run."

86400 seconds: "That took 1 day to run."

Actual output

349261 seconds: "That took 4 days, 97 hours, 1 minute and 1 second to run."

127932 seconds: "That took 1 day, 35 hours, 32 minutes and 12 seconds to run."

86400 seconds: "That took 1 day, 24 hours, 0 minutes and 0 seconds to run."

Can someone help me figure this out?


Solution

  • Thanks to @BeardOverflow and @NikolaySidorov, this works great:

    #!/bin/bash
    
    rendertimer(){
        # convert seconds to Days, Hours, Minutes, Seconds
        # thanks to Nikolay Sidorov and https://www.shellscript.sh/tips/hms/
        local parts seconds D H M S D_TAG H_TAG M_TAG S_TAG
        seconds=${1:-0}
        # all days
        D=$((seconds / 60 / 60 / 24))
        # all hours
        H=$((seconds / 60 / 60))
        H=$((H % 24))
        # all minutes
        M=$((seconds / 60))
        M=$((M % 60))
        # all seconds
        S=$((seconds % 60))
    
        # set up "x day(s), x hour(s), x minute(s) and x second(s)" language
        [ "$D" -eq "1" ] && D_TAG="day" || D_TAG="days"
        [ "$H" -eq "1" ] && H_TAG="hour" || H_TAG="hours"
        [ "$M" -eq "1" ] && M_TAG="minute" || M_TAG="minutes"
        [ "$S" -eq "1" ] && S_TAG="second" || S_TAG="seconds"
    
        # put parts from above that exist into an array for sentence formatting
        parts=()
        [ "$D" -gt "0" ] && parts+=("$D $D_TAG")
        [ "$H" -gt "0" ] && parts+=("$H $H_TAG")
        [ "$M" -gt "0" ] && parts+=("$M $M_TAG")
        [ "$S" -gt "0" ] && parts+=("$S $S_TAG")
    
        # construct the sentence
        result=""
        lengthofparts=${#parts[@]}
        for (( currentpart = 0; currentpart < lengthofparts; currentpart++ )); do
            result+="${parts[$currentpart]}"
            # if current part is not the last portion of the sentence, append a comma
            [ $currentpart -ne $((lengthofparts-1)) ] && result+=", "
        done
        echo "$result"
    }
    
    duration=$1
    howlong="$(rendertimer "${duration}")"
    echo "That took ${howlong} to run."