Wie bekomme ich Millisekunden seit der Unix-Epoche?

30

Ich möchte ein Bash-Skript erstellen, das die Startzeit eines Browsers misst, für das ich einen HTML-Code verwende, der den Zeitstempel in Millisekunden mithilfe von JavaScript beim Laden abruft.

Im Shell-Skript, kurz bevor ich den Browser aufrufe, erhalte ich den Zeitstempel mit:

date +%s

Das Problem ist, dass es den Zeitstempel in Sekunden erhält, und ich brauche ihn in Millisekunden, da der Browser manchmal, wenn er ein zweites Mal ausgeführt wird, in weniger als einer Sekunde startet und ich in der Lage sein muss, diese Zeit präzise mit Millisekunden anstelle von Sekunden zu messen.

Wie kann ich den Zeitstempel in Millisekunden aus einem Bash-Skript abrufen?

Eduard Florinescu
quelle

Antworten:

28

date +%s.%Nwird Ihnen z. B. geben 1364391019.877418748. % N ist die Anzahl der Nanosekunden, die in der aktuellen Sekunde vergangen sind. Beachten Sie, dass es 9 Stellen hat und das Datum dies standardmäßig mit Nullen auffüllt, wenn es kleiner als 100000000 ist. Dies ist eigentlich ein Problem, wenn wir mit der Zahl rechnen möchten, da Bash Zahlen mit einer führenden Null als Oktal behandelt . Diese Auffüllung kann deaktiviert werden, indem ein Bindestrich in der Feldspezifikation verwendet wird.

echo $((`date +%s`*1000+`date +%-N`/1000000))

würde Ihnen naiv Millisekunden seit der Epoche geben.

Wie Stephane Chazelas im folgenden Kommentar ausführt, handelt es sich jedoch um zwei verschiedene dateAnrufe, die zwei leicht unterschiedliche Zeiten ergeben. Wenn die Sekunde dazwischen liegt, wird die Berechnung um eine ganze Sekunde verschoben. So:

echo $(($(date +'%s * 1000 + %-N / 1000000')))

Oder optimiert (dank Kommentaren unten, obwohl dies offensichtlich gewesen sein sollte):

echo $(( $(date '+%s%N') / 1000000));
Goldlöckchen
quelle
Ich habe es versucht und es funktioniert, danke + 1 / akzeptieren!
Eduard Florinescu
7
Beachten Sie, dass zwischen dem ersten und dem zweiten Datum möglicherweise mehrere Millionen Nanosekunden vergangen sind und es möglicherweise nicht einmal dieselbe Sekunde ist. Am besten machen $(($(date +'%s * 1000 + %N / 1000000'))). Das macht noch nicht viel Sinn, wäre aber zuverlässiger.
Stéphane Chazelas
1
Korrektur durch Deaktivieren der
3
%Nist in BSD und OS X nicht verfügbar.
orkoden
1
Warum nicht einfach echo $(( $(date '+%s%N') / 1000000))?
Hitechcomputergeek
47

Mit der GNU- oder Ast-Open-Implementierung von date(oder busybox ', wenn diese FEATURE_DATE_NANOOption aktiviert ist) würde ich Folgendes verwenden:

$ date +%s%3N

Dies gibt Millisekunden seit der Unix-Epoche zurück.

javabeangrinder
quelle
5
Elegant, nett, +1
Eduard Florinescu
1
Upvoting für Eleganz
schläfrig
In der Tat elegant, +1. Wenn du wie ich sichergehen willst, dass %3Ndie erforderliche Auffüllung mit der linken Null erfolgt (ohne die Dokumente zu lesen. ;-), kannst du while sleep 0.05; do date +%s%3N; doneund ja, die erforderlichen Nullen sind da.
Terry Brown
Vielen Dank, Terry! Ist %3Naber in der Tat null gepolstert. Außerdem glaube ich nicht, dass Ihre Lösung Nullen hinzufügen würde, sondern nur die Antwort so wenig verzögern würde.
Javabeangrinder
javabeangrinder, @ TerryBrowns Code war keine Lösung , testen Sie einfach den Code, um zu überprüfen, ob er %3Ntatsächlich mit 0 aufgefüllt ist.
Stéphane Chazelas
10

Falls mit jemand anderen Shells als bash, ksh93und zshhaben eine Gleitkomma - $SECONDSVariable , wenn Sie ein tun , typeset -F SECONDSwas sehr praktisch sein kann , Zeit mit Genauigkeit zu messen:

$ typeset -F SECONDS=0
$ do-something
something done
$ echo "$SECONDS seconds have elapsed"
18.3994340000 seconds have elapsed

Seit Version 4.3.13 (2011) zshgibt es $EPOCHREALTIMEim zsh/datetimeModul eine spezielle Gleitkommavariable :

$ zmodload zsh/datetime
$ echo $EPOCHREALTIME
1364401642.2725396156
$ printf '%d\n' $((EPOCHREALTIME*1000))
1364401755993

Beachten Sie, dass dies von den zwei Ganzzahlen (für Sekunden und Nanosekunden) abgeleitet ist, die von zurückgegeben werden clock_gettime(). Auf den meisten Systemen ist dies präziser als eine einzelne C- doubleGleitkommazahl, sodass Sie an Genauigkeit verlieren, wenn Sie sie in arithmetischen Ausdrücken verwenden (mit Ausnahme von Datumsangaben in den ersten Monaten des Jahres 1970).

$ t=$EPOCHREALTIME
$ echo $t $((t))
1568473231.6078064442 1568473231.6078064

Um Zeitunterschiede mit hoher Genauigkeit zu berechnen (obwohl ich bezweifle, dass Sie eine Genauigkeit von mehr als Millisekunden benötigen würden), möchten Sie möglicherweise $epochtimestattdessen das spezielle Array verwenden (das die Sekunden und Nanosekunden als zwei separate Elemente enthält).

Seit Version 5.7 (2018) unterstützt die strftimeeingebaute Shell auch ein %NNanosekundenformat à la GNU dateund ein %., um die Genauigkeit anzugeben, sodass die Anzahl der Millisekunden seit der Epoche auch abgerufen werden kann mit:

zmodload zsh/datetime
strftime %s%3. $epochtime

(oder in einer Variablen gespeichert mit -s var)

Stéphane Chazelas
quelle
Beachten Sie, dass die Variable "$ SECONDS" nicht mit der EPOCH-Zeit verbunden ist. Der Bruchteil (Millisekunden, Mikrosekunden und Nanosekunden) kann in jedem ganz unterschiedlich sein.
Isaac,
8

Um Berechnungen zu vermeiden, die Millisekunden benötigen, können Befehlszeilen-JavaScript-Interpreter helfen:

bash-4.2$ node -e 'console.log(new Date().getTime())' # node.js
1364391220596

bash-4.2$ js60 -e 'print(new Date().getTime())'       # SpiderMonkey
1364391220610

bash-4.2$ jsc -e 'print(new Date().getTime())'        # WebKit 
1364391220622

bash-4.2$ seed -e 'new Date().getTime()'              # GNOME object bridge
1364391220669

Pakete, die diese Interpreter für Ubuntu Eoan enthalten:

Mann bei der Arbeit
quelle
2

In bash 5+ gibt es eine Variable mit Mikrosekunde Granularität: $EPOCHREALTIME.

So:

$ echo "$(( ${EPOCHREALTIME//.} / 1000 ))"
1568385422635

Gibt die Zeit seit dem 1. Januar 1970 in Millisekunden aus.

Andernfalls müssen Sie das Datum verwenden. Entweder das GNU-Datum:

echo "$(date +'%s%3N')"

Eine der in https://serverfault.com/a/423642/465827 aufgeführten Alternativen

Oder brew install coreutilsfür OS X

Oder, wenn alles andere fehlschlägt, kompilieren Sie (gcc epochInµsec.c) dieses c-Programm (passen Sie es nach Bedarf an):

#include <stdio.h>
#include <sys/time.h>
int main(void)
{
  struct timeval time_now;
    gettimeofday(&time_now,NULL);
    printf ("%ld secs, %ld usecs\n",time_now.tv_sec,time_now.tv_usec);

    return 0;
}

Beachten Sie, dass das Aufrufen eines externen Programms einige Zeit benötigt, um von der Festplatte gelesen und geladen, gestartet, ausgeführt und schließlich zum Drucken der Ausgabe verwendet zu werden. Das dauert einige Millisekunden. Dies ist die Mindestgenauigkeit, die mit einem externen Werkzeug (einschließlich Datum) erreicht werden kann.

Isaac
quelle