secondi
Per misurare il tempo trascorso (in secondi) abbiamo bisogno di:
- un numero intero che rappresenta il conteggio dei secondi trascorsi e
- un modo per convertire tale numero intero in un formato utilizzabile.
Un valore intero di secondi trascorsi:
Converti tale numero intero in un formato utilizzabile
Il bash interno printf
può farlo direttamente:
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45
allo stesso modo
$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34
ma questo non funzionerà per una durata superiore a 24 ore, poiché in realtà stampiamo un tempo di orologio da parete, non proprio una durata:
$ hours=30;mins=12;secs=24
$ elapsedseconds=$(( ((($hours*60)+$mins)*60)+$secs ))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
06:12:24
Per gli amanti dei dettagli, da bash-hackers.org :
%(FORMAT)T
genera la stringa data-ora risultante dall'uso di FORMATO come stringa di formato per strftime(3)
. L'argomento associato è il numero di secondi trascorsi Epoch , o -1 (ora attuale) o -2 (tempo di avvio shell). Se non viene fornito alcun argomento corrispondente, l'ora corrente viene utilizzata come impostazione predefinita.
Quindi potresti voler chiamare solo textifyDuration $elpasedseconds
dove textifyDuration
c'è ancora un'altra implementazione della stampa della durata:
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)"
}
Data GNU.
Per ottenere il tempo formulato dovremmo usare uno strumento esterno (data GNU) in diversi modi per arrivare fino a quasi un anno e inclusi i nanosecondi.
Appuntamento matematico.
Non c'è bisogno di aritmetica esterna, fai tutto in un solo passaggio date
:
date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
Sì, c'è uno 0
zero nella stringa di comando. È necessario.
Ciò presuppone che sia possibile modificare il date +"%T"
comando in un date +"%s"
comando in modo che i valori vengano memorizzati (stampati) in pochi secondi.
Si noti che il comando è limitato a:
- Valori positivi di
$StartDate
e $FinalDate
secondi.
- Il valore in
$FinalDate
è maggiore (più avanti nel tempo) di $StartDate
.
- Differenza di tempo inferiore a 24 ore.
- Accettate un formato di output con Ore, Minuti e Secondi. Molto facile da cambiare.
- È accettabile usare -u volte UTC. Per evitare "DST" e correzioni dell'ora locale.
Se devi usare la 10:33:56
stringa, beh, convertila in secondi,
inoltre, la parola secondi potrebbe essere abbreviata in 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"
Si noti che la conversione del tempo in secondi (come presentato sopra) è relativa all'inizio di "questo" giorno (Oggi).
Il concetto potrebbe essere esteso a nanosecondi, in questo modo:
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"
Se è necessario calcolare differenze di tempo più lunghe (fino a 364 giorni), dobbiamo utilizzare l'inizio di (alcuni) anni come riferimento e il valore del formato %j
(il numero del giorno nell'anno):
Simile a:
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
Purtroppo, in questo caso, dobbiamo sottrarre manualmente 1
ONE dal numero di giorni. Il comando data visualizza il primo giorno dell'anno come 1. Non così 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'uso di un lungo numero di secondi è valido e documentato qui:
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
Data di occupato
Uno strumento utilizzato in dispositivi più piccoli (un eseguibile molto piccolo da installare): Busybox.
O crea un collegamento a busybox chiamato date:
$ ln -s /bin/busybox date
Usalo quindi chiamando questo date
(posizionalo in una directory inclusa PERCORSO).
O crea un alias come:
$ alias date='busybox date'
La data di Busybox ha una bella opzione MrGreen per ricevere il formato dell'ora di input. Questo apre molti formati da usare come tempo. Usando l'opzione -D possiamo convertire direttamente l'ora 10:33:56:
date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"
E come puoi vedere dall'output del comando sopra, si presume che il giorno sia "oggi". Per iniziare a partire dall'epoca:
$ 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 data di Busybox può persino ricevere l'ora (nel formato sopra) senza -D:
$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
E il formato di output potrebbe anche essere secondi dall'epoca.
$ date -u -d "1970.01.01-$string1" +"%s"
52436
Per entrambe le volte, e un po 'di matematica bash (la scatola occupata non può ancora fare la matematica):
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 ))
O formattato:
$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14
time
comando?