¿Cómo obtener el tiempo actual de Unix en milisegundos en bash?

232

¿Cómo obtengo el tiempo actual de Unix en milisegundos (es decir, el número de milisegundos desde la época de Unix el 1 de enero de 1970)?

Ricardo
fuente

Respuestas:

265

Esta:

date +%s 

devolverá el número de segundos desde la época.

Esta:

date +%s%N

devuelve los segundos y nanosegundos actuales.

Entonces:

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

le dará la cantidad de milisegundos desde la época - segundos actuales más los tres nanosegundos restantes.


y de MikeyB - echo $(($(date +%s%N)/1000000))(dividir entre 1000 solo lleva a microsegundos)

madriguera
fuente
39
Me pregunto cuántos ms agrega el corte :-)
Kyle Brandt
13
O si desea hacerlo todo en el shell, evitando la sobrecarga costosa de un proceso adicional (en realidad, estamos evitando el problema cuando cambia el número de dígitos en% + s + N):echo $(($(date +%s%N)/1000))
MikeyB
55
Es el principio del asunto ... evite los números mágicos y codifique lo que realmente quiere decir .
MikeyB
25
Creo que vale la pena señalar que el hombre pidió Unix, no Linux, y la respuesta principal actual (fecha +% s% N) no funciona en mi sistema AIX.
Pete
12
@Pete +1 Igual para OS X y FreeBSD
ocodo
100

Simplemente puede usar %3Npara truncar los nanosegundos a los 3 dígitos más significativos (que luego son milisegundos):

$ date +%s%3N
1397392146866

Esto funciona, por ejemplo, en mi kubuntu 12.04.

Pero tenga en cuenta que eso %Npuede no implementarse dependiendo de su sistema de destino. Por ejemplo, probado en un sistema integrado (buildroot rootfs, compilado usando una cadena de herramientas cruzadas de brazo no HF) no había %N:

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

(Y también mi tableta Android (no rooteada) no tiene %N).

Joe
fuente
1
@warren: Vi que editaste y cambiaste 1397392146%3Na 1397392146%N, pero el resultado de 1397392146%3Neso es lo que realmente había visto en la consola busybox de mi tableta Android. ¿Podrías explicar tu edición?
Joe
El comentario de Warren del historial se "cambió de 3 a 6, ya que 3 solo te lleva a microsegundos". Su edición parece completamente espuria; deberías revertirlo.
bukzor
1
Esta es una característica específica de GNU coreutils. En última instancia, esto se implementa en gnulib aquí: github.com/gagern/gnulib/blob/… .
telotortium el
probablemente un punto allí tiene sentido. date +%s.%3Nimpresiones 1510718281.134.
darksky
Esta debería ser la respuesta aceptada.
Noah Sussman
61

date +%N no funciona en OS X, pero podría usar uno de

  • rubí: ruby -e 'puts Time.now.to_f'
  • pitón: python -c 'import time; print time.time()'
  • node.js: node -e 'console.log(Date.now())'
  • PHP: php -r 'echo microtime(TRUE);'
  • Elixir: DateTime.utc_now() |> DateTime.to_unix(:millisecond)
  • los internet: wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
  • o por milisegundos redondeados al segundo más cercano date +%s000
Lri
fuente
1
para completar ...node -e 'console.log(Date.now())'
slf
1
Usando PHP:php -r 'echo microtime(TRUE);'
TachyonVortex
8
Claro, solo tienes que esperar a que esos intérpretes se calienten. Esto también funciona:wget -qO- http://www.timeapi.org/utc/now?\\s.\\N
Camilo Martin
8
O, si realmente no necesita los milisegundos, sino el formato correcto:date +%s000
Lenar Hoyt
1
apple.stackexchange.com/questions/135742/… tiene instrucciones para hacerlo en OSX a través de Brew'scoreutils
sameers el
10

Solo lanzando esto, pero creo que la fórmula correcta con la división sería:

echo $(($(date +%s%N)/1000000))
splattne
fuente
10

Mi solución no es la mejor, pero funcionó para mí.

date +%s000

Solo necesitaba convertir una fecha como 2012-05-05 a milisegundos.

Pablo
fuente
1
Amazing hack, lol :)
k06a
77
Debes ser alguien entre mis compañeros de trabajo.
Nakilon
7

Para las personas que sugieren ejecutar programas externos para obtener los milisegundos ... a ese ritmo, también podría hacer esto:

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

El punto es: antes de elegir cualquier respuesta desde aquí, tenga en cuenta que no todos los programas se ejecutarán en un segundo entero. ¡Medida!

Camilo Martin
fuente
No le estás preguntando al sistema local por el momento. Lo que supongo está implícito en la pregunta. También depende de una conexión de red.
orkoden
2
@orkoden La pregunta pide explícitamente "número de milisegundos desde la época de Unix el 1 de enero de 1970". Además, estoy más señalando cómo nunca deberías encender Ruby o Python (o wget) solo para obtener el tiempo, ya sea esto a través de un canal rápido o milisegundos no importan.
Camilo Martin el
2
Sí, entendí que estaba dando una solución peor para resaltar los defectos de las malas soluciones. Probé varias soluciones y medí el tiempo. lpaste.net/119499 Los resultados son bastante interesantes. Incluso en una máquina i7 muy rápida, datetarda 3 ms en ejecutarse.
orkoden
@orkoden ¡Buenas pruebas! Que sistema operativo Esto podría tener que ver con el proceso de generación de gastos generales.
Camilo Martin
1
@Nakilon y esta es la razón por la que no se debe confiar en comodidades rizables como esas para cualquier producción.
Camilo Martin
4

Esta solución funciona en macOS.

Si considera usar un script bash y tiene Python disponible, puede usar este código:

#!/bin/bash

python -c 'from time import time; print int(round(time() * 1000))'
Frank Thonig
fuente
¿Por qué el voto negativo?
Frank Thonig
No parece particularmente justificado. La sugerencia en la flecha hacia abajo dice "Esta respuesta no es útil", pero IMO es útil. Tal vez querían que lo convirtieras en un script de Python. Eso sería más simple y también funcionaría bien como un comando bash.
Andrew Schulman
No se preocupe demasiado por los votos negativos (no fue mío) ... especialmente si son anónimos (de los cuales uno no puede aprender lo que parece estar mal, ¿verdad?). Solo para ayudarte a procesarlo ... aquí va otro +1 ... adivina qué: TÚ también puedes "votar" ahora, ¿verdad?
Pierre.Vriens
El voto negativo parece haber sido causado por un problema con el sistema. Desde entonces ha sido eliminado, nuevamente por el sistema.
Michael Hampton
2

Si está buscando una manera de mostrar la cantidad de tiempo que se ejecutó su script, lo siguiente proporcionará un resultado (no completamente preciso):

Tan cerca como pueda del comienzo de su secuencia de comandos, ingrese lo siguiente

basetime=$(date +%s%N)

Esto le dará un valor inicial de algo como 1361802943996000000

Al final de su secuencia de comandos, use lo siguiente

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

que mostrará algo como

runtime: 12.383 seconds

Notas:

(1 * 10 ^ 09) se puede reemplazar con 1000000000 si lo desea

"scale=3"es un entorno bastante raro que obliga bca hacer lo que quieres. ¡Hay muchos más!

Solo probé esto en Win7 / MinGW ... No tengo una caja * nix adecuada a mano.

usuario161733
fuente
3
o simplemente podrías usarlotime <script>
warren
2

Aquí se explica cómo obtener tiempo en milisegundos sin realizar la división. Quizás sea más rápido ...

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

Actualización: Otra alternativa en pure bash que solo funciona bash 4.2+es la misma que la anterior, pero se usa printfpara obtener la fecha. Definitivamente será más rápido porque ningún proceso se bifurca fuera del principal.

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

Sin embargo, otro inconveniente aquí es que su strftimeimplementación debería ser compatible %sy %Nque NO es el caso en mi máquina de prueba. Consulte las man strftimeopciones compatibles. Ver también man bashpara ver la printfsintaxis. -1y -2son valores especiales para el tiempo.

akostadinov
fuente
Parece que mi strftime(3)no es compatible, %Npor lo que no hay forma de printfimprimir nanosegundos. Estoy usando Ubuntu 14.04.
haridsv
@haridsv, sí, no está en glibc. dateParece la opción más confiable.
akostadinov
2

La marca de tiempo más precisa que podemos obtener (al menos para Mac OS X) es probablemente esta:

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

1490665305.021699

Pero debemos tener en cuenta que se necesitan alrededor de 30 milisegundos para ejecutarse. Podemos cortarlo a la escala de la fracción de 2 dígitos y, al comienzo, calcular la sobrecarga promedio de lectura del tiempo y luego eliminarlo de la medición. Aquí hay un ejemplo:

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

Puede descomentar los comandos de eco para ver mejor cómo funciona.

Los resultados de este script suelen ser uno de estos 3 resultados:

measured seconds: 1.99
measured seconds: 2.00
measured seconds: 2.01
ishahak
fuente
1

Usar date y expr puede llevarte allí, es decir

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

Solo amplíalo para hacer lo que quieras

Me doy cuenta de que esto no da milisegundos desde la época, pero aún puede ser útil como respuesta para algunos de los casos, todo depende de lo que realmente necesita, multiplique por 1000 si necesita un número de milisegundos: D

La forma más sencilla sería hacer un pequeño ejecutable (de C f.ex.) y ponerlo a disposición del script.

Johan Andersson
fuente
Existe un problema potencial que se ejecuta datevarias veces. En algunos casos, la fecha o la hora pueden cambiar entre ejecuciones a medida que se escribe su comando. Es mejor ejecutar dateuna vez y analizar las partes y hacer su cálculo. Una de varias maneras de hacerlo sería t=$(date +%H%M%S); (( x = ${t:0:2} * 3600 + ${t:2:2} * 60 + ${t:4:2} )); echo "$x". Utiliza la sintaxis de Bash ya que la pregunta está etiquetada como bash . Como aludes, tu respuesta (y mi variación) solo da segundos para el día actual hasta ahora y no desde la época y no en milis.
Dennis Williamson el
1

(repetir desde arriba) date +%Nno funciona en OS X, pero podría usar también:

Perl (requiere Time :: Módulo de formato). Quizás no sea el mejor módulo de CPAN para usar, pero hace el trabajo. Time :: Format generalmente está disponible con distribuciones.

perl -w -e'use Time::Format; printf STDOUT ("%s.%s\n", time, $time{"mmm"})'
TVNshack
fuente
El OP solicitó específicamente formas de hacerlo usando bash. ¿Cómo es este bash, guardar como método para lanzar algo más?
MadHatter
Lo uso en mis scripts de shell bash ... bajo OSX. Por lo tanto, dateno se puede usar y no hay comandos solo de bash que respondan a la necesidad.
TVNshack
Lo suficientemente justo. Si datetuviera que aclarar por qué los OSX no se pueden usar como parte de su respuesta , eliminaría mi voto negativo.
MadHatter
Esto se explicó algunas de las respuestas anteriores. No pude agregar como comentario ese comando que faltaba con la lista propuesta. Así que lo agregué aquí.
TVNshack
Es justo, acepto que esta es una adición útil al canon. +1 de mi parte!
MadHatter
1

Poniendo todas las respuestas anteriores juntas, cuando en OSX

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

puedes hacer como

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"
}
loretoparisi
fuente
0

Si desea un cómputo transcurrido de shell simple, esto es fácil y portátil, utilizando la respuesta anterior:

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
Bill Cheswick
fuente
0

Para alpine linux (muchas imágenes acoplables) y posiblemente otros entornos mínimos de linux, puede abusar de adjtimex:

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

adjtimexse usa para leer (y configurar) las variables de tiempo del núcleo. Con awkusted puede obtener los microsegundos, con headusted puede usar solo los primeros 3 dígitos.

No tengo idea de cuán confiable es este comando.

Nota: descaradamente robado de esta respuesta

Qw3ry
fuente