Bagaimana cara mendapatkan milidetik sejak zaman Unix?

30

Saya ingin melakukan skrip bash yang mengukur waktu peluncuran browser untuk itu saya menggunakan html yang mendapat cap waktu di-load dalam milidetik menggunakan JavaScript.

Dalam skrip shell tepat sebelum saya memanggil browser saya mendapatkan cap waktu dengan:

date +%s

Masalahnya adalah ia mendapat cap waktu dalam hitungan detik, dan saya membutuhkannya dalam milidetik karena kadang-kadang ketika berjalan kedua kalinya browser mulai di bawah satu detik dan saya harus dapat mengukur waktu itu secara tepat menggunakan milidetik alih-alih detik.

Bagaimana saya bisa mendapatkan cap waktu dalam milidetik dari skrip bash?

Eduard Florinescu
sumber

Jawaban:

28

date +%s.%Nakan memberi Anda, mis., 1364391019.877418748. % N adalah jumlah nanodetik yang berlalu dalam detik saat ini. Perhatikan itu 9 digit, dan secara default tanggal akan pad ini dengan nol jika kurang dari 100000000. Ini sebenarnya masalah jika kita ingin melakukan matematika dengan angka, karena bash memperlakukan angka dengan nol di depan sebagai oktal . Padding ini dapat dinonaktifkan dengan menggunakan tanda hubung di spec bidang, jadi:

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

naif akan memberi Anda milidetik sejak zaman.

Namun , seperti yang ditunjukkan Stephane Chazelas dalam komentar di bawah, itu adalah dua datepanggilan berbeda yang akan menghasilkan dua waktu yang sedikit berbeda. Jika yang kedua telah berguling di antara mereka, perhitungan akan menjadi seluruh detik. Begitu:

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

Atau dioptimalkan (terima kasih atas komentar di bawah, meskipun ini seharusnya sudah jelas):

echo $(( $(date '+%s%N') / 1000000));
goldilocks
sumber
Saya mencobanya dan berhasil, terima kasih +1 / terima!
Eduard Florinescu
7
Perhatikan bahwa di antara waktu Anda menjalankan kencan pertama dan kencan kedua, beberapa juta nanodetik mungkin telah berlalu dan bahkan mungkin bukan detik yang sama. Terbaik untuk dilakukan $(($(date +'%s * 1000 + %N / 1000000'))). Itu masih tidak masuk akal, tetapi akan lebih dapat diandalkan.
Stéphane Chazelas
1
Diperbaiki dengan mematikan bantalan nol seperti yang disebutkan pada tanggal (1)
Alois Mahdal
3
%Ntidak tersedia di BSD dan OS X.
orkoden
1
Kenapa tidak adil echo $(( $(date '+%s%N') / 1000000))?
Hitechcomputergeek
47

Dengan GNU atau implementasi ast-open date(atau busybox 'jika dibangun dengan FEATURE_DATE_NANOopsi diaktifkan), saya akan menggunakan:

$ date +%s%3N

yang mengembalikan milidetik sejak zaman Unix.

javabeangrinder
sumber
5
Elegan, bagus, +1
Eduard Florinescu
1
Terpilih untuk keanggunan
sleepycal
Memang elegan, +1. Jika seperti saya, Anda ingin memastikan %3Napakah bantalan nol kiri yang diperlukan (tanpa membaca dokumen. ;-), Anda dapat melakukannya while sleep 0.05; do date +%s%3N; done, dan ya, nol yang diperlukan ada di sana.
Terry Brown
Terry terima kasih! Namun %3Nmemang nol empuk. Selain itu saya tidak berpikir solusi Anda akan menambah nol, cukup tunda respons yang sangat sedikit.
javabeangrinder
javabeangrinder, kode @ TerryBrown bukan solusi , hanya menguji kode untuk memverifikasi yang %3Nmemang 0-empuk.
Stéphane Chazelas
10

Seandainya ada orang yang menggunakan cangkang selain bash, ksh93dan zshmemiliki $SECONDSvariabel floating point jika Anda melakukan typeset -F SECONDSyang dapat berguna untuk mengukur waktu dengan akurat:

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

Sejak versi 4.3.13 (2011) zshmemiliki $EPOCHREALTIMEvariabel floating point khusus dalam zsh/datetimemodul:

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

Perhatikan bahwa itu berasal dari dua bilangan bulat (untuk detik dan nanodetik) yang dikembalikan oleh clock_gettime(). Pada kebanyakan sistem, itu lebih presisi daripada yang doublebisa dimiliki oleh angka C floating point tunggal , sehingga Anda akan kehilangan presisi ketika Anda menggunakannya dalam ekspresi aritmatika (kecuali untuk tanggal dalam beberapa bulan pertama tahun 1970).

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

Untuk menghitung perbedaan waktu presisi tinggi (meskipun saya ragu Anda akan membutuhkan lebih dari presisi milidetik), Anda mungkin ingin menggunakan $epochtimearray khusus sebagai gantinya (yang berisi detik dan nanodetik sebagai dua elemen terpisah).

Sejak versi 5.7 (2018) strftimeshell builtin juga mendukung %Nformat nanodetik à la GNU datedan a %.untuk menentukan presisi, sehingga jumlah milidetik sejak zaman juga dapat diambil dengan:

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

(atau disimpan dalam variabel dengan -s var)

Stéphane Chazelas
sumber
Perhatikan bahwa variabel "$ DETIK" tidak terhubung / terkait dengan waktu EPOCH. Bagian fraksional (milidetik, mikrodetik dan nanodetik) mungkin sangat berbeda di masing-masing.
Isaac
8

Untuk menghindari perhitungan untuk mendapatkan milidetik, penerjemah baris perintah JavaScript dapat membantu:

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

Paket-paket yang mengandung juru bahasa itu di Ubuntu Eoan:

manatwork
sumber
2

Di bash 5 + ada variabel dengan rincian mikro-detik: $EPOCHREALTIME.

Begitu:

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

Mencetak waktu sejak zaman (1/1/70) dalam milidetik.

Gagal itu, Anda harus menggunakan tanggal. Entah tanggal GNU:

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

Salah satu alternatif yang tercantum di https://serverfault.com/a/423642/465827

Atau brew install coreutilsuntuk OS X

Atau, jika semuanya gagal, kompilasi (gcc epochInµsec.c) program c ini (sesuaikan sesuai kebutuhan):

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

Perhatikan bahwa memanggil program eksternal apa pun perlu waktu untuk dibaca dan dimuat dari disk, mulai, jalankan dan akhirnya untuk mencetak hasilnya. Itu akan membutuhkan beberapa milidetik. Itu adalah ketepatan minimum yang dapat dicapai dengan alat eksternal apa pun (termasuk tanggal).

Ishak
sumber