Jak uzyskać bieżący czas uniksowy w milisekundach w bash?


232

Jak uzyskać bieżący czas uniksowy w milisekundach (tj. Liczbę milisekund od epoki Uniksa 1 stycznia 1970 r.)?

Odpowiedzi:


264

To:

date +%s 

zwróci liczbę sekund od epoki.

To:

date +%s%N

zwraca sekundy i bieżące nanosekundy.

Więc:

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

poda liczbę milisekund od epoki - bieżące sekundy plus trzy lewe nanosekundy.


i od MikeyB - echo $(($(date +%s%N)/1000000))(dzielenie przez 1000 powoduje tylko mikrosekundy)


39
Zastanawiam się, ile ms dodaje cięcie :-)
Kyle Brandt

13
Lub jeśli chcesz zrobić to wszystko w powłoce, unikając kosztownych kosztów dodatkowych procesu (w rzeczywistości echo $(($(date +%s%N)/1000))
unikamy

5
Jest to podstawowa zasada: unikaj magicznych liczb i koduj, co masz na myśli .
MikeyB

25
Myślę, że warto zauważyć, że mężczyzna poprosił o Unixa, a nie Linuksa, a aktualna najwyższa odpowiedź (data +% s% N) nie działa w moim systemie AIX.
Pete,

12
@Pete +1 Same dla OS X i FreeBSD
ocodo

99

Możesz po prostu %3Nskrócić nanosekundy do 3 najbardziej znaczących cyfr (które następnie są milisekundami):

$ date +%s%3N
1397392146866

Działa to np. Na moim kubuntu 12.04.

Należy jednak pamiętać, że %Nmoże to nie zostać zaimplementowane w zależności od systemu docelowego. Np. Przetestowany na systemie wbudowanym (rootro-y rootkompilacji, skompilowane przy użyciu łańcucha krzyżowego ramienia innego niż HF) nie było %N:

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

(A także mój (nie zrootowany) tablet z Androidem nie ma %N).


1
@warren: Widziałem, że edytowane i zmienił 1397392146%3Nsię 1397392146%N, ale wyjście 1397392146%3Njest to, że co bym nie widział na konsoli BusyBox mojego Android tabletki. Czy możesz wyjaśnić swoją edycję?
Joe

komentarz Warrena z historii został „zmieniony z 3 na 6, ponieważ 3 zabiera cię w mikrosekundy”. Jego edycja wydaje się całkowicie fałszywa; powinieneś to wycofać.
bukzor

1
Jest to cecha szczególnie jądra GNU. Ostatecznie jest to zaimplementowane w gnulib tutaj: github.com/gagern/gnulib/blob/… .
telotortium

prawdopodobnie kropka ma sens. date +%s.%3Nodbitki 1510718281.134.
darksky

To powinna być zaakceptowana odpowiedź.
Noah Sussman

61

date +%N nie działa w systemie OS X, ale możesz użyć jednego z nich

  • rubin: ruby -e 'puts Time.now.to_f'
  • pyton: python -c 'import time; print time.time()'
  • node.js: node -e 'console.log(Date.now())'
  • PHP: php -r 'echo microtime(TRUE);'
  • Eliksir: DateTime.utc_now() |> DateTime.to_unix(:millisecond)
  • internety: wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
  • lub przez milisekundy zaokrąglone do najbliższej sekundy date +%s000

1
dla kompletności ...node -e 'console.log(Date.now())'
slf 10.10.13

1
Za pomocą PHP:php -r 'echo microtime(TRUE);'
TachyonVortex

8
Jasne, musisz tylko poczekać, aż tłumacze się rozgrzeją. To też działa:wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
Camilo Martin

8
Lub, jeśli tak naprawdę nie potrzebujesz milisekund, ale tylko prawidłowy format:date +%s000
Lenar Hoyt

1
apple.stackexchange.com/questions/135742/... zawiera instrukcje dotyczące wykonywania tego w OSX za pośrednictwem Brew'scoreutils
sameers

9

Po prostu to wyrzucamy, ale myślę, że poprawna formuła z podziałem będzie:

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

9

Moje rozwiązanie nie jest najlepsze, ale zadziałało dla mnie.

date +%s000

Po prostu potrzebowałem przekonwertować datę taką jak 2012-05-05 na milisekundy.


1
Niesamowity hack, lol :)
k06a 24.03.16

7
Musisz być kimś z moich współpracowników.
Nakilon

7

Dla osób, które sugerują uruchomienie programów zewnętrznych, aby uzyskać milisekundy ... w tym tempie, równie dobrze możesz to zrobić:

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

Chodzi o to: przed wybraniem jakiejkolwiek odpowiedzi z tego miejsca, pamiętaj, że nie wszystkie programy będą działać w ciągu jednej sekundy. Pomiar!


Na razie nie pytasz lokalnego systemu. Wydaje mi się, że sugeruje to pytanie. Jesteś także zależny od połączenia sieciowego.
orkoden

2
@orkoden Pytanie wyraźnie dotyczy „liczby milisekund od epoki Uniksa 1 stycznia 1970 r.”. Ponadto bardziej wskazuję, że nie powinieneś nigdy uruchamiać całego Ruby lub Pythona (lub wget) tylko po to, aby uzyskać czas - albo odbywa się to przez szybki kanał, albo milisekundy nie mają znaczenia.
Camilo Martin

2
Tak, zrozumiałem, że dałeś gorsze rozwiązanie, aby podkreślić wady złych rozwiązań. Wypróbowałem kilka rozwiązań i zmierzyłem czas. lpaste.net/119499 Wyniki są dość interesujące. dateUruchomienie nawet na bardzo szybkiej maszynie i7 zajmuje 3 ms.
orkoden

@orkoden Ładne testy! Jaki system operacyjny Może to mieć związek z narzutem procesu odrzutu.
Camilo Martin

1
@Nakilon i dlatego nie należy polegać na zwijanych udogodnieniach, takich jak te do jakiejkolwiek produkcji.
Camilo Martin

4

to rozwiązanie działa w systemie macOS.

jeśli rozważasz użycie skryptu bash i masz dostępny Python, możesz użyć tego kodu:

#!/bin/bash

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

dlaczego głosowanie w dół?
Frank Thonig,

Nie wydaje się to szczególnie uzasadnione. Wskazówka na strzałce w dół mówi „Ta odpowiedź nie jest przydatna”, ale IMO jest przydatna. Może chcieli, żebyś zamiast tego stworzył skrypt w języku Python. To byłoby prostsze i działałoby również jako polecenie bash.
Andrew Schulman,

Nie przejmuj się zbytnio głosami negatywnymi (to nie było moje) ... zwłaszcza jeśli są one anonimowe (z których nie można się dowiedzieć, co wydaje się złe, prawda?). Tylko po to, żeby to przetworzyć ... oto kolejna +1 ... zgadnij co: MOŻESZ także teraz „głosować”, prawda?
Pierre.Vriens

Wydaje się, że opinia negatywna została spowodowana przez problem z systemem. Od tego czasu został ponownie usunięty przez system.
Michael Hampton

2

Jeśli szukasz sposobu na wyświetlenie czasu działania skryptu, poniższe wyniki zapewnią (nie do końca dokładny) wynik:

Tak blisko początku skryptu, jak to możliwe, wprowadź następujące dane

basetime=$(date +%s%N)

To da ci wartość początkową czegoś takiego jak 1361802943996000000

Na końcu skryptu użyj następujących poleceń

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

który wyświetli coś podobnego

runtime: 12.383 seconds

Uwagi:

(1 * 10 ^ 09) można zastąpić 1000000000, jeśli chcesz

"scale=3"to raczej rzadkie ustawienie, które zmusza bcdo robienia tego, co chcesz. Jest o wiele więcej!

Testowałem to tylko na Win7 / MinGW ... Nie mam pod ręką odpowiedniego * nix boxa.


3
lub możesz po prostu użyćtime <script>
warren,

2

Oto, jak uzyskać czas w milisekundach bez wykonywania podziału. Może jest szybciej ...

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

Aktualizacja: Kolejna alternatywa w czystym bashu, która działa tylko z, bash 4.2+jest taka sama jak powyżej, ale użyj, printfaby uzyskać datę. Będzie to zdecydowanie szybsze, ponieważ żaden główny proces nie zostanie rozwidlony.

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

Innym haczykiem jest to, że twoja strftimeimplementacja powinna obsługiwać, %sa %Nto NIE jest przypadek na mojej maszynie testowej. Zobacz man strftimeobsługiwane opcje. Zobacz także man bashzobacz printfskładnię. -1i -2są specjalnymi wartościami dla czasu.


Wygląda na to, że mój strftime(3)nie obsługuje, %Nwięc nie ma mowy o printfdrukowaniu nanosekund. Używam Ubuntu 14.04.
haridsv

@haridsv, tak, nie ma go w glibc. datewydaje się bardziej niezawodną opcją.
akostadinov

2

Najdokładniejszy znacznik czasu, jaki możemy uzyskać (przynajmniej dla Mac OS X), to prawdopodobnie:

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

1490665305.021699

Musimy jednak pamiętać, że uruchomienie zajmuje około 30 milisekund. Możemy go wyciąć do skali ułamka dwucyfrowego i na samym początku obliczyć średni narzut odczytu czasu, a następnie usunąć go z pomiaru. Oto przykład:

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`"

Możesz odkomentować polecenia echa, aby zobaczyć, jak to działa.

Wyniki dla tego skryptu są zwykle jednym z 3 następujących wyników:

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

1

Użycie daty i wyrażenia może cię tam doprowadzić, tj

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

Po prostu rozwiń, aby zrobić, co chcesz

Zdaję sobie sprawę, że to nie daje milisekund od epoki, ale nadal może być przydatne jako odpowiedź na niektóre przypadki, wszystko zależy od tego, do czego tak naprawdę potrzebujesz, pomnóż przez 1000, jeśli potrzebujesz liczby milisekund: D

Najprostszym sposobem byłoby stworzenie małego pliku wykonywalnego (od C np.) I udostępnienie go skryptowi.


Istnieje potencjalny problem z datewielokrotnym uruchomieniem . W niektórych przypadkach data lub godzina mogą się zmieniać między uruchomieniami w miarę zapisywania polecenia. Lepiej uruchomić dateraz, przeanalizować części i wykonać obliczenia. Byłby to jeden z kilku sposobów t=$(date +%H%M%S); (( x = ${t:0:2} * 3600 + ${t:2:2} * 60 + ${t:4:2} )); echo "$x". To używa składni Bash, ponieważ pytanie jest oznaczone jako bash . Jak wspominasz, twoja odpowiedź (i moja odmiana) daje tylko sekundy dla bieżącego dnia, a nie od Epoki, a nie w milach.
Dennis Williamson,

1

(powtórz z góry) date +%Nnie działa w systemie OS X, ale możesz również użyć:

Perl (wymaga modułu Time :: Format). Być może nie jest to najlepszy moduł CPAN do użycia, ale wykonuje zadanie. Time :: Format jest ogólnie udostępniany z dystrybucjami.

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

OP specjalnie poprosił o sposoby na zrobienie tego za pomocą bash. Jak to bash, zapisać jako metodę uruchomienia czegoś innego?
MadHatter

Używam tego w moich skryptach powłoki bash ... w OSX. Tak więc datenie można go użyć i nie ma poleceń typu bash, które zaspokoją potrzebę.
TVNshack,

Słusznie. Jeśli miałbyś wyjaśnić, dlaczego OSX datenie może być użyty jako część twojej odpowiedzi , usunę moją opinię.
MadHatter

Wyjaśniono to kilka odpowiedzi powyżej. Nie mogłem dodać jako komentarza tego polecenia, którego brakowało w proponowanej liście. Więc dodałem to tutaj.
TVNshack,

W porządku, akceptuję, że jest to użyteczny dodatek do kanonu. +1 ode mnie!
MadHatter

1

Łącząc wszystkie poprzednie odpowiedzi w systemie OSX

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

możesz to zrobić

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

Jeśli chcesz wykonać proste obliczenia dotyczące powłoki, jest to łatwe i przenośne, korzystając z powyższej odpowiedzi:

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

W przypadku alpejskiego linuxa (wiele obrazów dokerów) i ewentualnie innych minimalnych środowisk linuksowych możesz nadużywać adjtimex:

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

adjtimexsłuży do odczytu (i ustawiania) zmiennych czasowych jądra. Dzięki awkmożesz uzyskać mikrosekundy, headmożesz użyć tylko pierwszych 3 cyfr.

Nie mam pojęcia, jak wiarygodne jest to polecenie.

Uwaga: bezwstydnie skradzione z tej odpowiedzi

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.