Secondes
Pour mesurer le temps écoulé (en secondes), nous avons besoin de:
- un entier qui représente le nombre de secondes écoulées et
- un moyen de convertir un tel entier dans un format utilisable.
Une valeur entière de secondes écoulées:
Convertir un tel entier dans un format utilisable
Le bash internal printf
peut le faire directement:
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45
De même
$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34
mais cela échouera pour des durées de plus de 24 heures, car nous imprimons en fait une heure d'horloge murale, pas vraiment une durée:
$ hours=30;mins=12;secs=24
$ elapsedseconds=$(( ((($hours*60)+$mins)*60)+$secs ))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
06:12:24
Pour les amoureux du détail, sur bash-hackers.org :
%(FORMAT)T
renvoie la chaîne date-heure résultant de l'utilisation de FORMAT comme chaîne de format pour strftime(3)
. L'argument associé est le nombre de secondes depuis Epoch , ou -1 (heure actuelle) ou -2 (heure de démarrage du shell). Si aucun argument correspondant n'est fourni, l'heure actuelle est utilisée par défaut.
Vous pouvez donc simplement appeler textifyDuration $elpasedseconds
où se textifyDuration
trouve une autre implémentation de l'impression de durée:
textifyDuration() {
local duration=$1
local shiff=$duration
local secs=$((shiff % 60)); shiff=$((shiff / 60));
local mins=$((shiff % 60)); shiff=$((shiff / 60));
local hours=$shiff
local splur; if [ $secs -eq 1 ]; then splur=''; else splur='s'; fi
local mplur; if [ $mins -eq 1 ]; then mplur=''; else mplur='s'; fi
local hplur; if [ $hours -eq 1 ]; then hplur=''; else hplur='s'; fi
if [[ $hours -gt 0 ]]; then
txt="$hours hour$hplur, $mins minute$mplur, $secs second$splur"
elif [[ $mins -gt 0 ]]; then
txt="$mins minute$mplur, $secs second$splur"
else
txt="$secs second$splur"
fi
echo "$txt (from $duration seconds)"
}
Date GNU.
Pour obtenir du temps formaté, nous devons utiliser un outil externe (date GNU) de plusieurs manières pour obtenir une durée pouvant atteindre près d'un an, y compris les nanosecondes.
Math à l'intérieur de la date.
Il n'y a pas besoin d'arithmétique externe, faites tout en une seule étape à l'intérieur date
:
date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
Oui, il y a un 0
zéro dans la chaîne de commande. C'est nécessaire.
Cela suppose que vous pouvez modifier la date +"%T"
commande en une date +"%s"
commande afin que les valeurs soient stockées (imprimées) en quelques secondes.
Notez que la commande est limitée à:
- Valeurs positives
$StartDate
et $FinalDate
secondes.
- La valeur de
$FinalDate
est plus grande (plus tard dans le temps) que $StartDate
.
- Différence horaire inférieure à 24 heures.
- Vous acceptez un format de sortie avec heures, minutes et secondes. Très facile à changer.
- Il est acceptable d'utiliser -u UTC fois. Pour éviter "DST" et les corrections d'heure locale.
Si vous devez utiliser la 10:33:56
chaîne, eh bien, convertissez-la simplement en secondes,
aussi, le mot secondes pourrait être abrégé en sec:
string1="10:33:56"
string2="10:36:10"
StartDate=$(date -u -d "$string1" +"%s")
FinalDate=$(date -u -d "$string2" +"%s")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S"
Notez que la conversion de temps en secondes (comme présenté ci-dessus) est relative au début de "ce" jour (Aujourd'hui).
Le concept pourrait être étendu aux nanosecondes, comme ceci:
string1="10:33:56.5400022"
string2="10:36:10.8800056"
StartDate=$(date -u -d "$string1" +"%s.%N")
FinalDate=$(date -u -d "$string2" +"%s.%N")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S.%N"
S'il est nécessaire de calculer des décalages horaires plus longs (jusqu'à 364 jours), nous devons utiliser le début de (certaines) années comme référence et la valeur de format %j
(le numéro du jour dans l'année):
Semblable à:
string1="+10 days 10:33:56.5400022"
string2="+35 days 10:36:10.8800056"
StartDate=$(date -u -d "2000/1/1 $string1" +"%s.%N")
FinalDate=$(date -u -d "2000/1/1 $string2" +"%s.%N")
date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N"
Output:
026 days 00:02:14.340003400
Malheureusement, dans ce cas, nous devons soustraire manuellement 1
UN du nombre de jours. La commande date considère le premier jour de l'année comme 1. Pas si difficile ...
a=( $(date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N") )
a[0]=$((10#${a[0]}-1)); echo "${a[@]}"
L'utilisation d'un long nombre de secondes est valide et documentée ici:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
Date de la boîte occupée
Un outil utilisé dans les petits appareils (un très petit exécutable à installer): Busybox.
Faites un lien vers la boîte occupée appelée date:
$ ln -s /bin/busybox date
Utilisez-le ensuite en l'appelant date
(placez-le dans un répertoire PATH inclus).
Ou créez un alias comme:
$ alias date='busybox date'
La date Busybox a une option intéressante: -D pour recevoir le format de l'heure d'entrée. Cela ouvre de nombreux formats à utiliser comme temps. En utilisant l'option -D, nous pouvons convertir directement l'heure 10:33:56:
date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"
Et comme vous pouvez le voir sur la sortie de la commande ci-dessus, le jour est supposé être "aujourd'hui". Pour que l'heure commence à l'époque:
$ string1="10:33:56"
$ date -u -D "%Y.%m.%d-%H:%M:%S" -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
La date Busybox peut même recevoir l'heure (dans le format ci-dessus) sans -D:
$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
Et le format de sortie pourrait même être de quelques secondes depuis l'époque.
$ date -u -d "1970.01.01-$string1" +"%s"
52436
Pour les deux fois, et un peu de maths bash (busybox ne peut pas encore faire le calcul):
string1="10:33:56"
string2="10:36:10"
t1=$(date -u -d "1970.01.01-$string1" +"%s")
t2=$(date -u -d "1970.01.01-$string2" +"%s")
echo $(( t2 - t1 ))
Ou formaté:
$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14
time
commande?