Comment obtenir des millisecondes depuis l'époque Unix?

30

Je veux faire un script bash qui mesure l'heure de lancement d'un navigateur pour cela j'utilise un html qui obtient l'horodatage en charge en millisecondes en utilisant JavaScript.

Dans le script shell juste avant d'appeler le navigateur, j'obtiens l'horodatage avec:

date +%s

Le problème est qu'il obtient l'horodatage en secondes, et j'en ai besoin en millisecondes car parfois lorsqu'il est exécuté une deuxième fois, le navigateur démarre en moins d'une seconde et je dois pouvoir mesurer ce temps avec précision en utilisant des millisecondes au lieu de secondes.

Comment puis-je obtenir l'horodatage en millisecondes à partir d'un script bash?

Eduard Florinescu
la source

Réponses:

28

date +%s.%Nvous donnera, par exemple., 1364391019.877418748. Le% N est le nombre de nanosecondes écoulées dans la seconde actuelle. Remarquez qu'il s'agit de 9 chiffres, et par défaut, la date remplira ceci avec des zéros s'il est inférieur à 100000000. C'est en fait un problème si nous voulons faire des calculs avec le nombre, car bash traite les nombres avec un zéro de tête comme octal . Ce remplissage peut être désactivé en utilisant un trait d'union dans la spécification de champ, donc:

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

vous donnerait naïvement des millisecondes depuis l'époque.

Cependant , comme le souligne Stéphane Chazelas dans le commentaire ci-dessous, ce sont deux dateappels différents qui donneront deux temps légèrement différents. Si la seconde est passée entre eux, le calcul sera une seconde entière. Alors:

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

Ou optimisé (grâce aux commentaires ci-dessous, bien que cela aurait dû être évident):

echo $(( $(date '+%s%N') / 1000000));
boucle d'or
la source
Je l'ai essayé et ça marche, merci + 1 / accepte!
Eduard Florinescu
7
Notez qu'entre le moment où vous exécutez la première date et la deuxième date, plusieurs millions de nanosecondes peuvent s'être écoulées et il se peut même que ce ne soit pas la même seconde. Le mieux à faire $(($(date +'%s * 1000 + %N / 1000000'))). Cela n'a toujours pas beaucoup de sens, mais serait plus fiable.
Stéphane Chazelas
1
Corrigé en désactivant le remplissage zéro comme indiqué dans la date (1)
Alois Mahdal
3
%Nn'est pas disponible dans BSD et OS X.
orkoden
1
Pourquoi pas juste echo $(( $(date '+%s%N') / 1000000))?
Hitechcomputergeek
47

Avec l'implémentation GNU ou ast-open de date(ou busybox 'si construit avec l' FEATURE_DATE_NANOoption activée), j'utiliserais:

$ date +%s%3N

qui renvoie des millisecondes depuis l'époque Unix.

javabeangrinder
la source
5
Élégant, agréable, +1
Eduard Florinescu
1
Votez pour l'élégance
sleepycal
En effet élégant, +1. Si, comme moi, vous voulez vous assurer %3Nque le remplissage à gauche est nécessaire (sans lire les documents. ;-), vous pouvez le faire while sleep 0.05; do date +%s%3N; done, et oui, les zéros nécessaires sont là.
Terry Brown
Merci Terry! Cependant, %3Nc'est en effet zéro rembourré. De plus, je ne pense pas que votre solution ajouterait des zéros, retardez simplement la réponse.
javabeangrinder
javabeangrinder, le code de @ TerryBrown n'était pas une solution , testez simplement le code pour vérifier qu'il %3Nest bien 0.
Stéphane Chazelas
10

Dans le cas où quelqu'un utilise d'autres coquilles que bash, ksh93et zsha une variable à virgule flottante $SECONDSsi vous en faites une typeset -F SECONDSqui peut être pratique pour mesurer le temps avec précision:

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

Depuis la version 4.3.13 (2011) zsha une $EPOCHREALTIMEvariable spéciale à virgule flottante dans le zsh/datetimemodule:

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

Notez que cela est dérivé des deux entiers (pour les secondes et les nanosecondes) renvoyés par clock_gettime(). Sur la plupart des systèmes, c'est plus de précision qu'un seul doublenombre à virgule flottante C peut contenir, donc vous perdrez de la précision lorsque vous l'utiliserez dans des expressions arithmétiques (sauf pour les dates des premiers mois de 1970).

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

Pour calculer des différences de temps de haute précision (bien que je doute que vous ayez besoin d'une précision supérieure à la milliseconde), vous pouvez utiliser le $epochtime tableau spécial à la place (qui contient les secondes et les nanosecondes comme deux éléments distincts).

Depuis la version 5.7 (2018), le strftimeshell intégré prend également en charge un %Nformat nanoseconde à la GNU dateet a %.pour spécifier la précision, donc le nombre de millisecondes depuis l'époque peut également être récupéré avec:

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

(ou stocké dans une variable avec -s var)

Stéphane Chazelas
la source
Notez que la variable "$ SECONDS" n'est pas connectée / liée à l'heure EPOCH. La partie fractionnaire (millisecondes, microsecondes et nanosecondes) peut être assez différente dans chacun.
Isaac
8

Pour éviter les calculs pour obtenir les millisecondes, les interprètes JavaScript en ligne de commande peuvent aider:

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

Paquets contenant ces interprètes sur Ubuntu Eoan:

homme au travail
la source
2

Dans bash 5+ il existe une variable avec une granularité de micro-secondes: $EPOCHREALTIME.

Alors:

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

Imprime le temps depuis l'époque (1/1/70) en millisecondes.

A défaut, vous devez utiliser la date. Soit la date GNU:

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

L'une des alternatives répertoriées dans https://serverfault.com/a/423642/465827

Ou brew install coreutilspour OS X

Ou, si tout le reste échoue, compilez (gcc epochInµsec.c) ce programme c (ajustez si nécessaire):

#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;
}

Notez que l'appel à n'importe quel programme externe nécessite du temps pour être lu et chargé à partir du disque, démarré, exécuté et enfin pour imprimer la sortie. Cela prendra plusieurs millisecondes. C'est la précision minimale qui pourrait être obtenue avec n'importe quel outil externe (y compris la date).

Isaac
la source