Convert seconds to hours, minutes, seconds

前端 未结 13 988
梦谈多话
梦谈多话 2020-12-02 14:08

How can I convert seconds to hours, minutes and seconds?

show_time() {
  ?????
}

show_time 36 # 00:00:36
show_time 1036 # 00:17:26
show_time 91925 # 25:32:0         


        
相关标签:
13条回答
  • 2020-12-02 14:48

    I couldn't get Vaulter's/chepner's code to work correctly. I think that the correct code is:

    convertsecs() {
        h=$(($1/3600))
        m=$((($1/60)%60))
        s=$(($1%60))
        printf "02d:%02d:%02d\n $h $m $s
    }
    
    0 讨论(0)
  • 2020-12-02 14:49

    Simple one-liner

    $ secs=236521
    $ printf '%dh:%dm:%ds\n' $(($secs/3600)) $(($secs%3600/60)) $(($secs%60))
    65h:42m:1s
    

    With leading zeroes

    $ secs=236521
    $ printf '%02dh:%02dm:%02ds\n' $(($secs/3600)) $(($secs%3600/60)) $(($secs%60))
    65h:42m:01s
    

    With days

    $ secs=236521
    $ printf '%dd:%dh:%dm:%ds\n' $(($secs/86400)) $(($secs%86400/3600)) $(($secs%3600/60)) \
      $(($secs%60))
    2d:17h:42m:1s
    

    With nanoseconds

    $ secs=21218.6474912
    $ printf '%02dh:%02dm:%02fs\n' $(echo -e "$secs/3600\n$secs%3600/60\n$secs%60"| bc | xargs echo)
    05h:53m:38.647491s
    

    Based on https://stackoverflow.com/a/28451379/188159 but edit got rejected.

    0 讨论(0)
  • 2020-12-02 14:55

    Using dc:

    $ echo '12345.678' | dc -e '?1~r60~r60~r[[0]P]szn[:]ndZ2>zn[:]ndZ2>zn[[.]n]sad0=ap'
    3:25:45.678
    

    The expression ?1~r60~r60~rn[:]nn[:]nn[[.]n]sad0=ap does the following:

    ?   read a line from stdin
    1   push one
    ~   pop two values, divide, push the quotient followed by the remainder
    r   reverse the top two values on the stack
    60  push sixty
    ~   pop two values, divide, push the quotient followed by the remainder
    r   reverse the top two values on the stack
    60  push sixty
    ~   pop two values, divide, push the quotient followed by the remainder
    r   reverse the top two values on the stack
    [   interpret everything until the closing ] as a string
      [0]   push the literal string '0' to the stack
      n     pop the top value from the stack and print it with no newline
    ]   end of string, push the whole thing to the stack
    sz  pop the top value (the string above) and store it in register z
    n   pop the top value from the stack and print it with no newline
    [:] push the literal string ':' to the stack
    n   pop the top value from the stack and print it with no newline
    d   duplicate the top value on the stack
    Z   pop the top value from the stack and push the number of digits it has
    2   push two
    >z  pop the top two values and executes register z if the original top-of-stack is greater
    n   pop the top value from the stack and print it with no newline
    [:] push the literal string ':' to the stack
    n   pop the top value from the stack and print it with no newline
    d   duplicate the top value on the stack
    Z   pop the top value from the stack and push the number of digits it has
    2   push two
    >z  pop the top two values and executes register z if the original top-of-stack is greater
    n   pop the top value from the stack and print it with no newline
    [   interpret everything until the closing ] as a string
      [.]   push the literal string '.' to the stack
      n     pop the top value from the stack and print it with no newline
    ]   end of string, push the whole thing to the stack
    sa  pop the top value (the string above) and store it in register a
    d   duplicate the top value on the stack
    0   push zero
    =a  pop two values and execute register a if they are equal
    p   pop the top value and print it with a newline
    

    An example execution with the stack state after each operation:

        : <empty stack>
    ?   : 12345.678
    1   : 1, 12345.678
    ~   : .678, 12345
    r   : 12345, .678  # stack is now seconds, fractional seconds
    60  : 60, 12345, .678
    ~   : 45, 205, .678
    r   : 205, 45, .678  # stack is now minutes, seconds, fractional seconds
    60  : 60, 205, 45, .678
    ~   : 25, 3, 45, .678
    r   : 3, 25, 45, .678  # stack is now hours, minutes, seconds, fractional seconds
    
    [[0]n]  : [0]n, 3, 25, 45, .678
    sz  : 3, 25, 45, .678  # '[0]n' stored in register z
    
    n   : 25, 45, .678  # accumulated stdout: '3'
    [:] : :, 25, 45, .678
    n   : 25, 45, .678  # accumulated stdout: '3:'
    d   : 25, 25, 45, .678
    Z   : 2, 25, 45, .678
    2   : 2, 2, 25, 45, .678
    >z  : 25, 45, .678  # not greater, so register z is not executed
    n   : 45, .678  # accumulated stdout: '3:25'
    [:] : :, 45, .678
    n   : 45, .678  # accumulated stdout: '3:25:'
    d   : 45, 45, .678
    Z   : 2, 45, 45, .678
    2   : 2, 2, 45, .678
    >z  : 45, .678  # not greater, so register z is not executed
    n   : .678  # accumulated stdout: '3:25:45'
    
    [[.]n]  : [.]n, .678
    sa  : .678  # '[.]n' stored to register a
    d   : .678, .678
    0   : 0, .678, .678
    =a  : .678  # not equal, so register a not executed
    p   : <empty stack>  # accumulated stdout: '3:25:45.678\n'
    

    In the case of 0 fractional seconds:

        : 3, 25, 45, 0  # starting just before we begin to print
    
    n   : 25, 45, .678  # accumulated stdout: '3'
    [:] : :, 25, 45, .678
    n   : 25, 45, .678  # accumulated stdout: '3:'
    d   : 25, 25, 45, .678
    Z   : 2, 25, 45, .678
    2   : 2, 2, 25, 45, .678
    >z  : 25, 45, .678  # not greater, so register z is not executed
    n   : 45, .678  # accumulated stdout: '3:25'
    [:] : :, 45, .678
    n   : 45, .678  # accumulated stdout: '3:25:'
    d   : 45, 45, .678
    Z   : 2, 45, 45, .678
    2   : 2, 2, 45, .678
    >z  : 45, .678  # not greater, so register z is not executed
    n   : .678  # accumulated stdout: '3:25:45'
    
    [[.]n]  : [.]n, 0
    sa  : 0  # '[.]n' stored to register a
    d   : 0, 0
    0   : 0, 0, 0
    =a  : 0  # equal, so register a executed
      [.] : ., 0
      n   : 0  # accumulated stdout: '3:35:45.'
    p   : <empty stack>  # accumulated stdout: '3:25:45.0\n'
    

    In case of a minutes value less than 10:

        : 3, 9, 45, 0  # starting just before we begin to print
    
    n   : 9, 45, .678  # accumulated stdout: '3'
    [:] : :, 9, 45, .678
    n   : 9, 45, .678  # accumulated stdout: '3:'
    d   : 9, 9, 45, .678
    Z   : 1, 9, 45, .678
    2   : 2, 1, 9, 45, .678
    >z  : 9, 45, .678  # greater, so register z is executed
      [0]   : 0, 9, 45, .678
      n     : 9, 45, .678  # accumulated stdout: '3:0' 
    n   : 9, .678  # accumulated stdout: '3:09'
    # ...and continues as above
    

    EDIT: this had a bug where strings like 7:7:34.123 could be printed. I have modified it to print a leading zero if necessary.

    0 讨论(0)
  • 2020-12-02 14:58

    For us lazy people: ready-made script available at https://github.com/k0smik0/FaCRI/blob/master/fbcmd/bin/displaytime :

    #!/bin/bash
    
    function displaytime {
      local T=$1
      local D=$((T/60/60/24))
      local H=$((T/60/60%24))
      local M=$((T/60%60))
      local S=$((T%60))
      [[ $D > 0 ]] && printf '%d days ' $D
      [[ $H > 0 ]] && printf '%d hours ' $H
      [[ $M > 0 ]] && printf '%d minutes ' $M
      [[ $D > 0 || $H > 0 || $M > 0 ]] && printf 'and '
      printf '%d seconds\n' $S
    }
    
    displaytime $1
    

    Basically just another spin on the other solutions, but has the added bonus of suppressing empty time units (f.e. 10 seconds instead of 0 hours 0 minutes 10 seconds). Couldn't quite track down the original source of the function, occurs in multiple git repos..

    0 讨论(0)
  • 2020-12-02 14:58
    t=12345;printf %02d:%02d:%02d\\n $((t/3600)) $((t%3600/60)) $((t%60)) # POSIX
    echo 12345|awk '{printf "%02d:%02d:%02d",$0/3600,$0%3600/60,$0%60}' # POSIX awk
    date -d @12345 +%T # GNU date
    date -r 12345 +%T # OS X's date
    

    If others were searching for how to do the reverse:

    IFS=: read h m s<<<03:25:45;echo $((h*3600+m*60+s)) # POSIX
    echo 03:25:45|awk -F: '{print 3600*$1+60*$2+$3}' # POSIX awk
    
    0 讨论(0)
  • 2020-12-02 15:00

    This is old post ovbioius -- but, for those who might are looking for the actual time elapsed but in military format (00:05:15:22 - instead of 0:5:15:22 )

    !#/bin/bash
        num=$1
        min=0
        hour=0
        day=0
        if((num>59));then
            ((sec=num%60))
            ((num=num/60))
                if((num>59));then
                ((min=num%60))
                ((num=num/60))
                    if((num>23));then
                        ((hour=num%24))
                        ((day=num/24))
                    else
                        ((hour=num))
                    fi
                else
                    ((min=num))
                fi
            else
            ((sec=num))
        fi
        day=`seq -w 00 $day | tail -n 1`
        hour=`seq -w 00 $hour | tail -n 1`
        min=`seq -w 00 $min | tail -n 1`
        sec=`seq -w 00 $sec | tail -n 1`
        printf "$day:$hour:$min:$sec"
     exit 0
    
    0 讨论(0)
提交回复
热议问题