Как найти разницу между двумя временными метками с точностью до миллисекунд?

10

Я новичок в сценариях оболочки. Суть моего сценария - найти разницу между двумя временными метками с точностью до миллисекунд. У меня есть файл с содержанием отметок времени только как

2012-09-13 15:00:29,290 2012-09-13 15:00:29,297
2012-09-13 15:00:29,428 2012-09-13 15:00:29,447

Таким образом, у меня есть около 30 тыс. Записей, где я не должен сталкиваться с проблемами производительности при выполнении скрипта. Многие факторы, такие как високосный год, месяцы с 31 днем ​​и т. Д., Появляются, когда я пытаюсь написать сценарий для этого.

Может ли кто-нибудь помочь мне в этом, пожалуйста?

Вамши Г
источник
1
DST входит в картину? Високосные секунды? Каковы правила DST? Изменились ли они со временем в вашей стране? Приходится ли вам иметь дело с датами до 1970 года или до перехода на григорианский календарь?
Стефан Шазелас

Ответы:

13

Не нужно делать сложный разбор, сделает всю магию за вас, с помощью своего друга, :

#!/bin/bash
while read d1_1 d1_2 d2_1 d2_2; do
  secdiff=$((
    $(date -d "$d2_1 $d2_2" +%s) - $(date -d "$d1_1 $d1_2" +%s)
  ))
  nanosecdiff=$((
    $(date -d "$d2_1 $d2_2" +%N) - $(date -d "$d1_1 $d1_2" +%N)
  ))
  printf "%s %s - %s %s = %d milliseconds\n" $d2_1 $d2_2 $d1_1 $d1_2 $((
    (secdiff * 1000) + (nanosecdiff / 1000000)
  ))
done < YOUR_FILE.txt

ВЫВОД

2012-09-13 15:00:29,297 - 2012-09-13 15:00:29,290 = 7 milliseconds
2012-09-13 15:00:29,447 - 2012-09-13 15:00:29,428 = 19 milliseconds

Увидеть man date

НОТА

  • date -d очень полезно, он конвертирует метки времени
  • %sвремя эпохи (в секундах с 01-01-1970)
  • %Nэто наносекунды
  • $(( ))и (( ))для bashарифметики, см. http://mywiki.wooledge.org/ArithmeticExpression
  • $( ) обозначает command substitution

Это также соответствует вашим потребностям?

Жиль Квено
источник
1
Исправлена арифметическая ошибка (конкатенация секунд и наносекунд). Теперь я сначала вычисляю секунды (OP не просил об этом, но для полноты и надежности при повторном использовании)
Жиль Квено
0

Язык сценариев, такой как Perl, Python или Ruby, будет быстрым и не потребует особых усилий. Например, с помощью Perl и Date :: Parse :

perl -MDate::Parse -l -ne 's/,/./g; split; print str2time("$_[2] $_[3]") - str2time("$_[0] $_[1]")'

(Для каждой строки, заменить ,на ., разделить строку на слова $_[0]через $_[3], разобрать даты , образованные первых двух и последующих двух слов, и печатать разницу.)

Жиль "ТАК - перестань быть злым"
источник
«Небольшое усилие» довольно условно. Конечно, если вы программист X и знаете о библиотеке Y, это просто. Вот как это всегда. На самом деле, я удивлен, что программист на Python еще не запрыгнул сюда. Я полагаю, что это просто вопрос времени ...: - \
Майк С
Вот почему люди дают полное решение здесь. Таким образом, вам не нужно быть программистом X или знать о библиотеке Y. И вы по-прежнему извлекаете выгоду из «небольшого усилия», когда в вашем сценарии есть одна строка, а не 10.
CherryDT
0

Я только что наткнулся на этот пост, есть - по крайней мере, сегодня - более простое dateрешение на основе. Используя фреймворк в ответе @Gilles Quenot (написал бы комментарий к своему ответчику, но недостаточно репутации):

while read d1_1 d1_2 d2_1 d2_2
do
    date -d "$d2_1 $d2_2 $(date -d "$d1_1 $d1_2" +%s.%N) seconds ago" +%s.%N
done << END
2012-09-13 15:00:29,290 2012-09-13 15:00:29,297
END

Результат:

$ ./time_elapsed.sh 
0.007000000

Использование %3Nвместо %Nбудет обрезать вывод до миллисекунд.

Золтан К.
источник