Як отримати мілісекунди з епохи Unix?


30

Я хочу зробити скрипт bash, який вимірює час запуску браузера, для цього я використовую html, який отримує часову марку при завантаженні в мілісекундах за допомогою JavaScript.

У скрипті оболонки безпосередньо перед тим, як зателефонувати в браузер, я отримую позначку часу:

date +%s

Проблема полягає в тому, що він отримує позначку часу в секундах, і мені це потрібно в мілісекундах, оскільки іноді при запуску вдруге браузер запускається за секунду, і мені потрібно бути в змозі точно виміряти цей час, використовуючи мілісекунди замість секунд.

Як я можу отримати мітку часу в мілісекундах від баш-скрипту?

Відповіді:


28

date +%s.%Nдасть вам, напр., 1364391019.877418748. % N - кількість наносекунд, минулих у поточній секунді. Зауважте, що це 9 цифр, і за замовчуванням дата зафіксує нулі, якщо вона менше 100000000. Це насправді проблема, якщо ми хочемо зробити математику з числом, тому що bash розглядає числа з провідним нулем як вісімковий . Цю прокладку можна відключити, використовуючи дефіс у специфікації поля, так:

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

наївно би дало тобі мілісекунди з епохи.

Однак , як в коментарі нижче зазначає Стефан Шазелас, це два різні dateдзвінки, які принесуть два дещо інші часи. Якщо другий перекинувся між ними, обчислення буде виключено цілу секунду. Так:

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

Або оптимізовано (завдяки коментарям нижче, хоча це мало бути очевидним):

echo $(( $(date '+%s%N') / 1000000));

Я спробував це і працює, спасибі + 1 / прийняти!
Едуард Флорінеску

7
Зауважте, що між часом запуску першої дати та другої дати може пройти кілька мільйонів наносекунд, і це може бути навіть не одна і та ж секунда. Найкраще робити $(($(date +'%s * 1000 + %N / 1000000'))). Це все ще не має великого сенсу, але було б більш надійним.
Стефан Шазелас

1
Виправлено вимкненням нульової прокладки, як зазначено в даті (1)
Alois Mahdal

3
%Nнедоступний у BSD та OS X.
orkoden

1
Чому б не просто echo $(( $(date '+%s%N') / 1000000))?
Hitechcomputergeek

47

З реалізацією GNU або відкритою dateастмою (або зайнятим ящиком ', якщо він створений з FEATURE_DATE_NANOувімкненою опцією), я б використовував:

$ date +%s%3N

що повертає мілісекунди з епохи Unix.


5
Елегантний, приємний, +1
Едуард Флорінеску

1
Оголошення на витонченість
сонливий

Дійсно елегантний, +1. Якщо ви схожі на мене, ви хочете бути впевнені, %3Nчи потрібні ліві нульові прокладки (не читаючи документів. ;-), ви можете зробити while sleep 0.05; do date +%s%3N; done, і так, потрібні нулі знаходяться там.
Террі Браун

Дякую, Террі! Однак %3Nнасправді нульова підкладка. Крім того, я не думаю, що ваше рішення не додасть нулів, просто затримайте відповідь так мало.
javabeangrinder

javabeangrinder, код @ TerryBrown не був рішенням , просто тестовий код, щоб переконатися, що %3Nце дійсно 0-padded.
Стефан Шазелас

10

У випадку, якщо хтось використовує інші оболонки, ніж bash, ksh93і zshмає $SECONDSзмінну з плаваючою точкою, якщо ви це зробите, typeset -F SECONDSяка може бути зручною для точності вимірювання часу:

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

Оскільки версія 4.3.13 (2011) у модулі zshмає $EPOCHREALTIMEспеціальну змінну з плаваючою точкою zsh/datetime:

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

Зауважте, що це походить від двох цілих чисел (за секунди та наносекунди), повернені о clock_gettime(). У більшості систем ця точність є більшою, ніж doubleможе посісти одне число з плаваючою точкою С , тому ви втратите точність, використовуючи її в арифметичних виразах (за винятком дат у перші кілька місяців 1970 року).

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

Для обчислення високої різниці в часі (хоча, я сумніваюся, вам знадобиться більше, ніж мілісекундна точність), ви можете $epochtimeзамість цього використати спеціальний масив (який містить секунди та наносекунди як два окремих елемента).

Оскільки версія 5.7 (2018) strftimeвбудована оболонка також підтримує %Nнаносекундний формат à la GNU dateта a, %.щоб вказати точність, тому кількість мілісекунд після епохи також можна отримати за допомогою:

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

(або зберігається у змінній з -s var)


Зауважте, що змінна "$ SECONDS" не підключена / пов'язана з часом EPOCH. Дробова частина (мілісекунди, мікросекунди та наносекунди) може бути в кожній різній.
Ісаак

8

Щоб уникнути обчислень для отримання мілісекунд, інтерпретатори JavaScript командного рядка можуть допомогти:

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

Пакети, що містять цих перекладачів на Ubuntu Eoan:


2

У Баш 5+ є змінна з мікро-другий зернистості: $EPOCHREALTIME.

Так:

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

Друкує час з епохи (1/1/70) у мілісекундах.

Якщо цього не вдалося, потрібно використовувати дату. Або дата GNU:

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

Одна з альтернатив, перелічених у https://serverfault.com/a/423642/465827

Або brew install coreutilsдля OS X

Або, якщо все інше не вдалося, компілюйте (gcc epochInµsec.c) цю програму c (коригуйте за потребою):

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

Зауважте, що для виклику будь-якої зовнішньої програми потрібен час для читання та завантаження з диска, запуску, запуску та нарешті для друку результатів. Це займе кілька мілісекунд. Це мінімальна точність, яку можна досягти будь-яким зовнішнім інструментом (включаючи дату).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.