Affichage des secondes en jours / heures / minutes / secondes?

31

Est-il possible de formater facilement les secondes en temps lisible par l'homme en bash?

Je ne veux pas le formater comme une date, mais comme le nombre de jours / heures / minutes, etc ...

Tyilo
la source
Pourriez-vous fournir un exemple / plusieurs exemples s'il vous plaît?
gabe.
1
Voulez-vous dire que vous avez un intervalle ou une date depuis l'époque?
Paul Tomblin

Réponses:

41

Vous pouvez utiliser quelque chose comme ceci:

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
}

Exemples:

$ displaytime 11617
3 hours 13 minutes and 37 seconds
$ displaytime 42
42 seconds
$ displaytime 666
11 minutes and 6 seconds
Stéphane Gimenez
la source
11

Le moyen le plus simple et le plus propre est celui-ci (en supposant ici GNU date):

Si le nombre de secondes est, dites:

seconds=123456789 # as in one of the answers above

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

-> sortie: 1428 days 21 hours 33 minutes 09 seconds

Jacques
la source
Si votre durée sera toujours moins d'un jour , vous pouvez utiliser le +%Tformat pour les heures: minutes: secondes pour cette date +%T "1970-01-01 + ${seconds} seconds"obtenir21:33:09
Ýzmir Ramirez
7

Le mérite revient à Stéphane Gimenez, mais si quelqu'un souhaite afficher les secondes uniquement si une période est inférieure à une minute, voici ma version modifiée que j'utilise (également avec une pluralisation fixe):

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
}

Un autre exemple dans 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'
}
dimir
la source
Cela a très bien fonctionné. J'ai simplement collé la fonction dans mon script et j'ai couru convert $spour obtenir une jolie sortie.
flickerfly
3

Je le ferais comme ça:

$ 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
$

Voici la doublure ci-dessus, décomposée afin qu'elle soit plus facile à comprendre:

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

Dans ce qui précède, je fais écho à la sortie d'une autre commande qui est exécutée à l'intérieur de la $( ... )sous-commande. Cette sous-commande fait cela, calculant le nombre de jours (secondes / 86400), puis utilisant la datecommande dans une autre sous-commande $(date -d ... ), pour générer les heures, les minutes et les secondes pour un nombre donné de secondes.

atti
la source
2

J'ai modifié la fonction d'affichage ci-dessus ... comme suit:

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
}

parce que je veux toujours voir HH: MM: SS, même si ce sont des zéros.

Larry Helms
la source
1

Je m'appuie sur la réponse d'atti que j'ai aimé comme idée.

Vous pouvez le faire avec la commande bash printfqui prendra les secondes depuis l'époque comme argument. Pas besoin de bifurquer pour courir date.

Vous devez définir le fuseau horaire sur UTC printfcar il formate l'heure dans votre fuseau horaire local et vous obtiendrez la mauvaise réponse si vous n'êtes pas en heure UTC.

$ 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

Dans mon heure locale (qui est actuellement NZDT - +1300), la réponse est fausse si je ne règle pas le fuseau horaire

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

Avec et sans réglage du fuseau horaire

$ 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
Bill Ryder
la source
Notez que bash a printfintroduit cette %(datefmt)Tnotation en commençant par bash-4.2-alpha.
évêque
-1

En voici un

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

Sortie:

4d 9h:7m:24s
Shirish Shukla
la source
-2

date --date '@1005454800'vous donne Sun Nov 11 00:00:00 EST 2001, qui est 1005454800 secondes après l'époque Unix. Vous pouvez formater cela avec l'option date + FORMAT.

Paul Tomblin
la source
7
C'est une date, pas une durée, sur laquelle portait la question.
Gilles 'SO- arrête d'être méchant'