Как получить миллисекунды с эпохи Unix?

30

Я хочу сделать bash-скрипт, который измеряет время запуска браузера, для этого я использую HTML, который получает метку времени при загрузке в миллисекундах с помощью JavaScript.

В сценарии оболочки перед вызовом браузера я получаю метку времени:

date +%s

Проблема в том, что он получает отметку времени в секундах, а мне она нужна в миллисекундах, поскольку иногда при повторном запуске браузер запускается менее чем за секунду, и мне нужно иметь возможность точно измерить это время, используя миллисекунды вместо секунд.

Как я могу получить метку времени в миллисекундах из скрипта bash?

Эдуард Флоринеску
источник

Ответы:

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)
Алоис Махдал
3
%Nнедоступно в BSD и OS X.
orkoden
1
Почему не просто echo $(( $(date '+%s%N') / 1000000))?
Hitechcomputergeek
47

С реализацией GNU или ast-open date(или busybox ', если она собрана с FEATURE_DATE_NANOвключенной опцией), я бы использовал:

$ date +%s%3N

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

javabeangrinder
источник
5
Элегантно, красиво, +1
Эдуард Флоринеску
1
Голосование за элегантность
сонный
Действительно элегантно, +1. Если, как и я, вы хотите быть уверенным, %3Nвыполняет ли необходимое заполнение нулями слева (не читая документы. ;-), вы можете сделать while sleep 0.05; do date +%s%3N; done, и да, там есть необходимые нули.
Терри Браун
Спасибо, Терри! Тем не менее, %3Nэто действительно ноль. Кроме того, я не думаю, что ваше решение добавит нули, просто немного задержит ответ.
Джавабангриндер
javabeangrinder, код @ TerryBrown не был решением , просто протестируйте код, чтобы убедиться, что %3Nон действительно дополнен нулями.
Стефан Шазелас
10

В случае, если кто-то использует другие оболочки, кроме bash, ksh93и zshимеет $SECONDSпеременную с плавающей запятой, если вы делаете a, 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может удерживать одно число с плавающей запятой C , поэтому вы потеряете точность, если будете использовать его в арифметических выражениях (за исключением дат в первые несколько месяцев 1970 года).

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

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

Начиная с версии 5.7 (2018) strftimeвстроенная оболочка также поддерживает %Nнаносекундный формат, например, 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:

manatwork
источник
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;
}

Обратите внимание, что вызов любой внешней программы требует времени для чтения и загрузки с диска, запуска, запуска и, наконец, для вывода на печать. Это займет несколько миллисекунд. Это минимальная точность, которую можно достичь с помощью любого внешнего инструмента (включая дату).

Исаак
источник