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


232

Як я можу отримати поточний час Unix у мілісекундах (тобто кількість мілісекунд з часу епохи Unix 1 січня 1970 р.)?

Відповіді:


264

Це:

date +%s 

поверне кількість секунд з епохи.

Це:

date +%s%N

повертає секунди та поточні наносекунди.

Тому:

date +%s%N | cut -b1-13

дасть вам кількість мілісекунд з епохи - поточні секунди плюс ліві три наносекунди.


і від MikeyB - echo $(($(date +%s%N)/1000000))(ділення на 1000 приводить до мікросекунд)


39
Цікаво, скільки мс додає скорочення :-)
Кайл Брандт,

13
Або якщо ви хочете зробити все це в оболонці, уникаючи дорогого режиму додаткового процесу (насправді ми echo $(($(date +%s%N)/1000))
уникаємо

5
Це принцип справи ... уникайте магічних чисел і кодуйте те, що ви насправді маєте на увазі .
MikeyB

25
Я думаю, що варто відзначити, що людина запитував Unix, а не Linux, і поточна відповідь (дата +% s% N) не працює в моїй системі AIX.
Піт

12
@Pete +1 Те саме для OS X та FreeBSD
ocodo

99

Ви можете просто використати %3Nдля обрізання наносекунд до трьох найбільш значущих цифр (які потім є мілісекундами):

$ date +%s%3N
1397392146866

Це працює, наприклад, на моєму kubuntu 12.04.

Але майте на увазі, що це %Nможе бути не реалізовано залежно від вашої цільової системи. Напр. Тестування на вбудованій системі (rootroot rootfs, складеному за допомогою інструментального ланцюга не-HF arm cross) не було %N:

$ date +%s%3N
1397392146%3N

(А також у мого (не вкоріненого) Android планшета немає %N).


1
@warren: Я бачив, що ви відредагували та змінили 1397392146%3Nна 1397392146%N, але результат - 1397392146%3Nце те, що я насправді бачив на консолі зайнятого планшета Android. Чи можете ви пояснити свою редакцію?
Джо

коментар Уоррена з історії "змінено з 3 на 6, оскільки 3 приведе вас лише до мікросекунд". Його редакція видається цілком хибною; ви повинні повернути його назад.
bukzor

1
Це особливість GNU coreutils саме. Зрештою, це реалізовано в gnulib тут: github.com/gagern/gnulib/blob/… .
телоторцій

напевно, крапка там має сенс. date +%s.%3Nвідбитки 1510718281.134.
темний

Це має бути прийнятою відповіддю.
Ной Суссман

61

date +%N не працює в OS X, але ви можете використовувати один із

  • рубін: ruby -e 'puts Time.now.to_f'
  • пітон: python -c 'import time; print time.time()'
  • node.js: node -e 'console.log(Date.now())'
  • PHP: php -r 'echo microtime(TRUE);'
  • Еліксир: DateTime.utc_now() |> DateTime.to_unix(:millisecond)
  • Інтернети: wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
  • або на мілісекунди, округлені до найближчої секунди date +%s000

1
для повноти ...node -e 'console.log(Date.now())'
slf

1
Використання PHP:php -r 'echo microtime(TRUE);'
TachyonVortex

8
Звичайно, вам просто потрібно дочекатися, коли ті перекладачі підігріються. Це теж працює:wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
Каміло Мартін,

8
Або якщо вам справді не потрібні мілісекунди, а лише правильний формат:date +%s000
Ленар Хойт

1
apple.stackexchange.com/questions/135742/… має вказівки робити це в OSX через Brew'scoreutils
самий

9

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

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

9

Моє рішення не найкраще, але працювало на мене.

date +%s000

Мені просто потрібно було конвертувати таку дату, як 2012-05-05, в мілісекунди.


1
Amazing hack, lol :)
k06a

7
Ти, мабуть, хтось із моїх колег.
Накілон

7

Для людей, які пропонують запустити зовнішні програми, щоб отримати мілілі секунди ... з такою швидкістю, ви можете також зробити це:

wget -qO- http://www.timeapi.org/utc/now?\\s.\\N

Справа в тому, що: перш ніж вибирати будь-яку відповідь звідси, майте на увазі, що не всі програми працюватимуть протягом однієї цілої секунди. Міряй!


Ти не питаєш місцевої системи поки що. Що я гадаю, мається на увазі у питанні. Ви також залежите від підключення до мережі.
orkoden

2
@orkoden Питання прямо вимагає "кількість мілісекунд з епохи Unix 1 січня 1970 року". Крім того, я більше вказую, як ви ніколи не повинні запускати цілий Ruby або Python (або wget), щоб отримати час - або це робиться через швидкий канал, або мілісекунди не мають значення.
Каміло Мартін

2
Так, я зрозумів, що ви даєте гірше рішення, щоб виділити недоліки поганих рішень. Я спробував кілька рішень і виміряв час. lpaste.net/119499 Результати цікаві. Навіть на дуже швидкій машині i7 dateпотрібно тривати 3 мс.
orkoden

@orkoden Приємне тестування! Яка ОС? Це може бути пов'язано з нерестуванням накладних витрат.
Каміло Мартін

1
@Nakilon, і саме тому не слід покладатися на зручності для завивки, подібні до тих, що виробляють що-небудь
Каміло Мартін

4

це рішення працює на macOS.

якщо ви розглядаєте можливість використання bash-скрипту та наявний python, ви можете використовувати цей код:

#!/bin/bash

python -c 'from time import time; print int(round(time() * 1000))'

чому голос "за"?
Френк Тоніг

Не видається особливо виправданим. Підказка на стрілці вниз говорить "Ця відповідь не корисна", але ІМО корисна. Можливо, вони хотіли, щоб ви зробили це замість сценарію Python. Це було б простіше, а також добре працюватиме як команда bash.
Ендрю Шульман

Не переживайте занадто сильно про похідні канали (це не було моє) ... особливо, якщо вони анонімні (звідки не можна дізнатися, що здається, не так, правда?). Просто для hlep ви обробляєте це ... тут іде ще +1 ... здогадуйтесь що: ВАМ також можете "голосувати" зараз, правда?
Pierre.Vriens

Зниження голосування, як видається, було викликано проблемою з системою. Відтоді система знову була видалена.
Майкл Хемптон

2

Якщо ви шукаєте спосіб відображення тривалості запуску сценарію, наступний результат забезпечить (не зовсім точний) результат:

Наближайтеся до початку сценарію, введіть наступне

basetime=$(date +%s%N)

Це дасть вам початкове значення приблизно на зразок 1361802943996000000

В кінці сценарію використовуйте наступне

echo "runtime: $(echo "scale=3;($(date +%s%N) - ${basetime})/(1*10^09)" | bc) seconds"

який відображатиме щось подібне

runtime: 12.383 seconds

Примітки:

(1 * 10 ^ 09) при бажанні можна замінити на 1000000000

"scale=3"- досить рідкісна установка, яка змушує bcробити те, що ви хочете. Є ще багато!

Я тестував це лише на Win7 / MinGW ... У мене немає належного * nix-коробки.


3
або ви могли просто скористатисяtime <script>
warren

2

Ось як отримати час у мілісекундах, не виконуючи ділення. Можливо, це швидше ...

# test=`date +%s%N`
# testnum=${#test}
# echo ${test:0:$testnum-6}
1297327781715

Оновлення: Ще одна альтернатива pure bash, яка працює лише з bash 4.2+такою ж, як вище, але використовувати printfдля отримання дати. Це, безумовно, буде швидше, оскільки жоден процес не відхиляється від основного.

printf -v test '%(%s%N)T' -1
testnum=${#test}
echo ${test:0:$testnum-6}

Ще один прихильність тут полягає в тому, що ваша strftimeреалізація повинна підтримувати, %sа %Nце НЕ має місце на моїй тестовій машині. Дивіться man strftimeпідтримувані варіанти. Також дивіться, man bashщоб побачити printfсинтаксис. -1і -2є особливими значеннями для часу.


Здається, моя strftime(3)не підтримує, %Nтому немає можливості printfдрукувати наносекунди. Я використовую Ubuntu 14.04.
haridsv

@haridsv, так, це не в glibc. dateвидається більш надійним варіантом.
акостадінов

2

Найбільш точна мітка часу, яку ми можемо отримати (принаймні для Mac OS X), мабуть, така:

python -c 'import datetime; print datetime.datetime.now().strftime("%s.%f")'

1490665305.021699

Але нам потрібно пам’ятати, що для запуску потрібно близько 30 мілісекунд. Ми можемо вирізати його до шкали дробової частки і на самому початку обчислити середній накладний обсяг часу читання, а потім зняти його з вимірювання. Ось приклад:

function getTimestamp {
  echo `python -c 'import datetime; print datetime.datetime.now().strftime("%s.%f")' | cut -b1-13` 
}
function getDiff {
  echo "$2-$1-$MeasuringCost" | bc
}
prev_a=`getTimestamp`
acc=0
ITERATIONS=30
for i in `seq 1 $ITERATIONS`;do 
  #echo -n $i 
  a=`getTimestamp`
  #echo -n "   $a"
  b=`echo "$a-$prev_a" | bc`
  prev_a=$a
  #echo "  diff=$b"
  acc=`echo "$acc+$b" | bc`
done
MeasuringCost=`echo "scale=2; $acc/$ITERATIONS" | bc`
echo "average: $MeasuringCost sec"
t1=`getTimestamp`
sleep 2
t2=`getTimestamp`
echo "measured seconds: `getDiff $t1 $t2`"

Ви можете коментувати команди ехо, щоб побачити, як воно працює.

Результати для цього сценарію зазвичай є одним із цих 3 результатів:

measured seconds: 1.99
measured seconds: 2.00
measured seconds: 2.01

1

Використовуючи дату та expr, ви можете потрапити туди, тобто

X=$(expr \`date +%H\` \\* 3600 + \`date +%M\` \\* 60 + \`date +%S\`)
echo $X

Просто розгорніть його, щоб робити все, що завгодно

Я усвідомлюю, що це не дає мілісекунд з епохи, але це все-таки може бути корисним як відповідь на деякі випадки, все залежить від того, для чого вам це потрібно, помножте на 1000, якщо вам потрібно мілісекундне число: D

Найпростішим способом було б зробити невеликий виконуваний файл (від C f.ex.) і зробити його доступним для сценарію.


Можлива проблема, яка працює dateкілька разів. У деяких випадках дата або час можуть змінюватися між запусками, коли буде написана ваша команда. Краще запустити dateодин раз і розібрати деталі і зробити свій розрахунок. Один із кількох способів зробити це було б t=$(date +%H%M%S); (( x = ${t:0:2} * 3600 + ${t:2:2} * 60 + ${t:4:2} )); echo "$x". Для цього використовується синтаксис Bash, оскільки питання позначено тегом bash . Як ви натякаєте, ваша відповідь (і моя мінливість) дає лише секунди на поточний день поки що, а не з епохи, а не в мілі.
Денніс Вільямсон

1

(повторити зверху) date +%Nне працює в OS X, але ви також можете використовувати:

Perl (потрібен модуль Time :: Format). Мабуть, не найкращий модуль CPAN для використання, але робота виконується. Час :: Формат, як правило, доступний з дистрибутивами.

perl -w -e'use Time::Format; printf STDOUT ("%s.%s\n", time, $time{"mmm"})'

ОП спеціально просила способи зробити це за допомогою bash. Як це баш, крім методу запуску чогось іншого?
MadHatter

Я використовую це у своїх скриптах bash shell ... під OSX. Таким чином, dateйого не можна використовувати, і немає команд, що відповідають лише вимогам ".
TVNshack

Досить справедливо. Якщо ви повинні уточнити, чому OSX dateне може використовуватися як частина вашої відповіді , я б видалив свій звуковий запис.
MadHatter

Це було пояснено декількома відповідями вище. Я не міг додати як коментар ту команду, якої бракувало із запропонованим списком. Тому я додав його сюди.
TVNshack

Досить справедливо, я приймаю це корисне доповнення до канону. +1 від мене!
MadHatter

1

Збирання всіх разом попередніх відповідей, коли в OSX

ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G31+

ви можете робити так, як

microtime() {
    python -c 'import time; print time.time()'
}
compute() {
    local START=$(microtime)
    #$1 is command $2 are args
    local END=$(microtime)
    DIFF=$(echo "$END - $START" | bc)
    echo "$1\t$2\t$DIFF"
}

0

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

now() {
    python -c 'import datetime; print datetime.datetime.now().strftime("%s.%f")'
}
seismo:~$ x=`now`
seismo:~$ y=`now`
seismo:~$ echo "$y - $x" | bc
5.212514

0

Для альпійського Linux (багато зображень докера) та, можливо, інших мінімальних середовищ Linux ви можете зловживати adjtimex:

adjtimex | awk '/(time.tv_usec):/ { printf("%06d\n", $2) }' | head -c3

adjtimexвикористовується для зчитування (і встановлення) змінних часу ядра. З awkвами можна отримати мікросекунди, з них headможна використовувати лише перші 3 цифри.

Я поняття не маю, наскільки надійна ця команда.

Примітка: Безсоромно вкрадено з цієї відповіді

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