Wyświetlasz sekundy jako dni / godziny / minuty / sekundy?


31

Czy w bashu można łatwo sformatować sekundy jako czas czytelny dla człowieka?

Nie chcę formatować go jako daty, ale jako liczbę dni / godzin / minut itp.


Czy możesz podać przykład / kilka przykładów?
Gabe.

1
Czy mówisz, że masz epokę lub randkę od epoki?
Paul Tomblin

Odpowiedzi:


41

Możesz użyć czegoś takiego:

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
}

Przykłady:

$ displaytime 11617
3 hours 13 minutes and 37 seconds
$ displaytime 42
42 seconds
$ displaytime 666
11 minutes and 6 seconds

11

Najłatwiejszym i najczystszym sposobem jest ta jedna linijka (tutaj przy założeniu GNU date):

Jeśli liczba sekund wynosi, powiedz:

seconds=123456789 # as in one of the answers above

eval "echo $(date -ud "@$seconds" +'$((%s/3600/24)) days %H hours %M minutes %S seconds')"

-> wyjście: 1428 days 21 hours 33 minutes 09 seconds


Jeśli twój czas trwania będzie zawsze krótszy niż jeden dzień, możesz użyć +%Tformatu Godziny: Minuty: Sekundy, aby to date +%T "1970-01-01 + ${seconds} seconds"uzyskać21:33:09
Yzmir Ramirez

7

Zasługa Stéphane Gimenez ale jeśli ktoś chciałby, aby wyświetlić sekund tylko wtedy, gdy okres ten wynosi mniej niż minutę tutaj jest moja wersja zmodyfikowana, że używam (również ze stałym liczby mnogiej):

converts()
{
    local t=$1

    local d=$((t/60/60/24))
    local h=$((t/60/60%24))
    local m=$((t/60%60))
    local s=$((t%60))

    if [[ $d > 0 ]]; then
            [[ $d = 1 ]] && echo -n "$d day " || echo -n "$d days "
    fi
    if [[ $h > 0 ]]; then
            [[ $h = 1 ]] && echo -n "$h hour " || echo -n "$h hours "
    fi
    if [[ $m > 0 ]]; then
            [[ $m = 1 ]] && echo -n "$m minute " || echo -n "$m minutes "
    fi
    if [[ $d = 0 && $h = 0 && $m = 0 ]]; then
            [[ $s = 1 ]] && echo -n "$s second" || echo -n "$s seconds"
    fi  
    echo
}

Alternatywny przykład w POSIX:

converts(){
    t=$1

    d=$((t/60/60/24))
    h=$((t/60/60%24))
    m=$((t/60%60))
    s=$((t%60))

    if [ $d -gt 0 ]; then
            [ $d = 1 ] && printf "%d day " $d || printf "%d days " $d
    fi
    if [ $h -gt 0 ]; then
            [ $h = 1 ] && printf "%d hour " $h || printf "%d hours " $h
    fi
    if [ $m -gt 0 ]; then
            [ $m = 1 ] && printf "%d minute " $m || printf "%d minutes " $m
    fi
    if [ $d = 0 ] && [ $h = 0 ] && [ $m = 0 ]; then
            [ $s = 1 ] && printf "%d second" $s || printf "%d seconds" $s
    fi
    printf '\n'
}

To działało naprawdę dobrze. Po prostu wkleiłem tę funkcję do mojego skryptu i pobiegłem, convert $saby uzyskać niezłe wyniki.
flickerfly,

3

Zrobiłbym to w ten sposób:

$ seconds=123456789; echo $((seconds/86400))" days "$(date -d "1970-01-01 + $seconds seconds" "+%H hours %M minutes %S seconds")
1428 days 21 hours 33 minutes 09 seconds
$

Oto jeden linijka powyżej, podzielony, aby łatwiej było zrozumieć:

$ seconds=123456789
$ echo $((seconds/86400))" days"\
     $(date -d "1970-01-01 + $seconds seconds" "+%H hours %M minutes %S seconds")

W powyższym wyrażam echo wyjścia innego polecenia, które jest uruchamiane wewnątrz polecenia $( ... )podrzędnego. To polecenie podrzędne robi to, obliczając liczbę dni (sekundy / 86400), a następnie używa datepolecenia w innym poleceniu podrzędnym $(date -d ... ), aby wygenerować godziny, minuty i sekundy dla określonej liczby sekund.


2

Zmodyfikowałem funkcję displaytime powyżej ... w następujący sposób:

seconds2time ()
{
   T=$1
   D=$((T/60/60/24))
   H=$((T/60/60%24))
   M=$((T/60%60))
   S=$((T%60))

   if [[ ${D} != 0 ]]
   then
      printf '%d days %02d:%02d:%02d' $D $H $M $S
   else
      printf '%02d:%02d:%02d' $H $M $S
   fi
}

ponieważ zawsze chcę widzieć HH: MM: SS, nawet jeśli są zerami.


1

Opieram się na odpowiedzi atti, która spodobała mi się jako pomysł.

Możesz to zrobić za pomocą wbudowanego basha, printfktóry zajmie kilka sekund od epoki jako argument. Nie trzeba widelca, aby uruchomić date.

Musisz ustawić strefę czasową na UTC, printfponieważ formatuje ona czas w lokalnej strefie czasowej, a jeśli nie jesteś w czasie UTC, otrzymasz błędną odpowiedź.

$ seconds=123456789
$ TZ=UTC printf "%d days %(%H hours %M minutes %S seconds)T\n" $((seconds/86400)) $seconds
1428 days 21 hours 33 minutes 09 seconds

W moim czasie lokalnym (obecnie NZDT - +1300) odpowiedź jest błędna, jeśli nie ustawię strefy czasowej

$ seconds=123456789
$ printf "%d days %(%H hours %M minutes %S seconds)T\n" $((seconds/86400)) $seconds
1428 days 09 hours 33 minutes 09 seconds

Z ustawieniem strefy czasowej i bez

$ seconds=$(( 3600 * 25))
$ printf "%d days %(%H hours %M minutes %S seconds)T\n" $((seconds/86400)) $seconds
1 days 13 hours 00 minutes 00 seconds

$ TZ=UTC printf "%d days %(%H hours %M minutes %S seconds)T\n" $((seconds/86400)) $seconds
1 days 01 hours 00 minutes 00 seconds

Zauważ, że bash printfwprowadził tę %(datefmt)Tnotację zaczynając od bash-4.2-alpha.
biskup

-1

Tutaj jeden

secs=378444
echo $(($secs/86400))d $(($(($secs - $secs/86400*86400))/3600))h:$(($(($secs - $secs/86400*86400))%3600/60))m:$(($(($secs - $secs/86400*86400))%60))s

Wydajność:

4d 9h:7m:24s

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.