Convert seconds to hours, minutes, seconds

前端 未结 13 1049
梦谈多话
梦谈多话 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: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:

        : 
    ?   : 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   :   # 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   :   # 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.

提交回复
热议问题