Como obter milissegundos desde a época do Unix?

30

Quero fazer um script bash que meça o tempo de inicialização de um navegador, pois estou usando um html que obtém o carimbo de data e hora em carga em milissegundos usando JavaScript.

No script shell, pouco antes de ligar para o navegador, recebo o carimbo de data / hora com:

date +%s

O problema é que ele obtém o registro de data e hora em segundos, e eu preciso dele em milissegundos, já que, às vezes, quando é executado pela segunda vez, o navegador inicia em menos de um segundo e preciso poder medir esse tempo com precisão usando milissegundos em vez de segundos.

Como posso obter o carimbo de hora em milissegundos a partir de um script bash?

Eduard Florinescu
fonte

Respostas:

28

date +%s.%Nlhe dará, por exemplo 1364391019.877418748,. O% N é o número de nanossegundos decorridos no segundo atual. Observe que ele tem 9 dígitos e, por padrão, a data irá preenchê-lo com zeros se for menor que 100000000. Isso é realmente um problema se quisermos fazer contas com o número, porque o bash trata números com um zero inicial como octal . Esse preenchimento pode ser desativado usando um hífen na especificação do campo, portanto:

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

ingenuamente lhe daria milissegundos desde a época.

No entanto , como Stephane Chazelas aponta no comentário abaixo, são duas datechamadas diferentes que renderão dois tempos ligeiramente diferentes. Se o segundo rolou entre eles, o cálculo será um segundo inteiro. Tão:

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

Ou otimizado (graças aos comentários abaixo, embora isso deva ter sido óbvio):

echo $(( $(date '+%s%N') / 1000000));
Cachinhos Dourados
fonte
Eu tentei e funciona, obrigado + 1 / aceito!
Eduard Florinescu 27/03
7
Observe que entre o momento em que você executa a primeira e a segunda data, vários milhões de nanossegundos podem ter passado e talvez nem seja o mesmo segundo. Melhor para fazer $(($(date +'%s * 1000 + %N / 1000000'))). Isso ainda não faz muito sentido, mas seria mais confiável.
Stéphane Chazelas 27/03
11
Corrigido desativando o preenchimento zero, conforme observado na data (1)
Alois Mahdal 27/03
3
%Nnão está disponível no BSD e no OS X.
orkoden
11
Por que não apenas echo $(( $(date '+%s%N') / 1000000))?
Hitechcomputergeek 21/11
47

Com a implementação GNU ou ast-open de date(ou busybox 'se criada com a FEATURE_DATE_NANOopção ativada), eu usaria:

$ date +%s%3N

que retorna milissegundos desde a época do Unix.

javabeangrinder
fonte
5
Elegante, agradável, +1
Eduard Florinescu 08/04
11
Promovendo a elegância
sleepycal
De fato elegante, +1. Se, como eu, você quiser ter certeza de %3Nque o preenchimento zero necessário é deixado à esquerda (sem ler os documentos. ;-), você pode fazer while sleep 0.05; do date +%s%3N; done, e sim, os zeros necessários estão lá.
Terry Brown
Obrigado Terry! No entanto, %3Né de fato zero preenchido. Além disso, não acho que a sua solução adicione zeros, apenas adie a resposta para tão pouco.
javabeangrinder
javabeangrinder, o código do @ TerryBrown não era uma solução , apenas o código de teste para verificar %3Nse realmente é preenchido com 0.
Stéphane Chazelas 22/11
10

Caso alguém esteja usando outras conchas além de bash, ksh93e zshtenha uma variável de ponto flutuante $SECONDS, se você fizer uma typeset -F SECONDSque possa ser útil para medir o tempo com precisão:

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

Desde a versão 4.3.13 (2011), zshhá uma $EPOCHREALTIMEvariável especial de ponto flutuante no zsh/datetimemódulo:

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

Observe que isso é derivado dos dois números inteiros (por segundos e nanossegundos) retornados por clock_gettime(). Na maioria dos sistemas, isso é mais preciso do que um único doublenúmero de ponto flutuante C pode suportar; portanto, você perderá a precisão ao usá-lo em expressões aritméticas (exceto para datas nos primeiros meses de 1970).

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

Para calcular diferenças de tempo de alta precisão (embora eu duvide que você precise mais do que milissegundos de precisão), convém usar a $epochtimematriz especial (que contém os segundos e os nanossegundos como dois elementos separados).

Desde a versão 5.7 (2018), o strftimeshell interno também suporta um %Nformato de nanossegundo à GNU datee a %.para especificar a precisão, portanto, o número de milissegundos desde a época também pode ser recuperado com:

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

(ou armazenado em uma variável com -s var)

Stéphane Chazelas
fonte
Observe que a variável "$ SECONDS" não está conectada / relacionada ao tempo do EPOCH. A parte fracionária (milissegundos, microssegundos e nanossegundos) pode ser bem diferente em cada uma.
Isaac
8

Para evitar cálculos para obter os milissegundos, os intérpretes JavaScript da linha de comandos podem ajudar:

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

Pacotes que contêm esses intérpretes no Ubuntu Eoan:

homem a trabalhar
fonte
2

Em festa 5+ não é uma variável com micro-segundo granularidade: $EPOCHREALTIME.

Tão:

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

Imprime o tempo desde a época (1/1/70) em milissegundos.

Na sua falta, você deve usar a data. A data do GNU:

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

Uma das alternativas listadas em https://serverfault.com/a/423642/465827

Ou brew install coreutilspara OS X

Ou, se tudo mais falhar, compile (gcc epochInµsec.c) este programa c (ajuste conforme necessário):

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

Observe que a chamada para qualquer programa externo precisa de tempo para ser lida e carregada do disco, iniciada, executada e, finalmente, para imprimir a saída. Isso levará vários milissegundos. Essa é a precisão mínima que poderia ser alcançada com qualquer ferramenta externa (incluindo a data).

Isaac
fonte