Como obter a hora atual como um número inteiro de 13 dígitos em Ruby?

88

Tenho esta jQueryfunção que retorna a hora atual como o número de milissegundos desde a época (1 de janeiro de 1970):

time = new Date().getTime();

Existe uma maneira de fazer o mesmo em Ruby?

No momento, estou usando Ruby, Time.now.to_ique funciona muito bem, mas retorna um número inteiro de 10 dígitos (número de segundos)

Como faço para que ele exiba o número de milissegundos, como em jQuery?

Tintin81
fonte
5
Isso não é uma "função jQuery", é apenas um ECMAScript (javascript). Talvez tenha sido isso que levou ao -1, um pouco severo.
RobG
Consulte também stackoverflow.com/q/20001883/238886
Wayne Conrad

Respostas:

155
require 'date'

p DateTime.now.strftime('%s') # "1384526946" (seconds)
p DateTime.now.strftime('%Q') # "1384526946523" (milliseconds)
Steenslag
fonte
31
Nota para usuários Rails: o strftimemétodo fornecido por ActiveSupport::TimeWithZonenão inclui os especificadores %se %Q. Você precisará converter para um Ruby simples DateTimeprimeiro, usando o to_datetimemétodo.
Lonnon Foster
6
@LonnonFoster Agora funciona (testado recentemente no console Rails).
Nikola Stojaković
Olá, como posso fazer a mesma coisa, mas não por enquanto, mas sim a partir de um campo de data?
Tomer
Observe que isso trunca em vez de arredondar (como você pode ver no exemplo - 1384526946523ms deve arredondar para 1384526947s).
David Moles
102

O Javascript gettime()retorna o número de milissegundos desde a época.

O Ruby Time.now.to_ifornecerá o número de segundos desde a época. Se você alterar para Time.now.to_f, ainda terá segundos, mas com um componente fracionário. Basta multiplicar isso por 1.000 e você terá milissegundos. Em seguida, use #to_ipara convertê-lo em um inteiro. E você acaba com:

(Time.now.to_f * 1000).to_i
Anthony DeSimone
fonte
Muito obrigado pela explicação! Ainda é novo para essa coisa toda ... Na verdade, não sei qual resposta marcar como a correta ...
Tintin81
1
Só para maiores informações, Time.nowvem do Ruby já que Time.currentvem do Rails. Portanto, Time.currenté reconhecido pelo fuso horário do aplicativo Rails e Time.nowestá usando o fuso horário do servidor. Na minha experiência, sempre use Time.currentem seu aplicativo Rails para consistência de fuso horário
vutran
1
Não, você não deve usar Time.currentaqui, leva mais tempo para construir, e como você está convertendo imediatamente para um carimbo de data / hora unix, você não se preocupa com a consistência do fuso horário. (Carimbos de data / hora Unix sempre se relacionam ao UTC). Portanto, embora o que você está dizendo seja verdade em 99% dos casos, este em termos de desempenho cai nos últimos 1%.
The Pellmeister
1
Esta é minha abordagem preferida. Uma coisa que gosto de fazer é aumentar a classe Time para adicionar um :epochmétodo: class Time def epoch (self.to_f * 1000) .to_i end end
Matt Welke
@brauliobo Importa-se de explicar como ele falsifica milissegundos? Sua declaração é enganosa, a resposta de OP está absolutamente certa.
coisnepe
31

(Time.now.to_f * 1000).to_i deve fazer a mesma coisa.

Zach Kemp
fonte
1
@brauliobo o que são milissegundos falsos?
Erik Rothoff
1
@brauliobo Não to_finclui , pois inclui os milissegundos como um decimal.
CashIsClay
21

Usando strftime, você pode obter o número de segundos e acrescentar milissegundos fracionários (ou unidades menores, se necessário):

2.2.2 :001 > t = Time.new
 => 2015-06-02 12:16:56 -0700 
2.2.2 :002 > t.strftime('%s%3N')
 => "1433272616888" 

Observe que isso não é arredondado, ele trunca, como você pode ver com to_fou se chegar a microssegundos:

2.2.2 :003 > t.to_f
 => 1433272616.888615
2.2.2 :004 > t.usec
 => 888615 

e a solução to_f/ to_item o mesmo problema:

2.2.2 :009 > (t.to_f * 1000).to_i
 => 1433272616888

então, se você realmente se preocupa com a precisão de milissegundos, uma aposta melhor pode ser to_fcom round:

2.2.2 :010 > (t.to_f * 1000).round
 => 1433272616889

Dito isso, conforme observado nos documentos , "IEEE 754 double não é preciso o suficiente para representar o número de nanossegundos desde a época", portanto, se você realmente se importa, considere em to_rvez de to_f-

2.2.2 :011 > (t.to_r * 1000).round
 => 1433272616889 

- embora se você estiver apenas arredondando para milissegundos, provavelmente estará bem.

David Moles
fonte
18

Tenha cuidado, não se confunda. O fato de Ruby suportar a ideia de segundos fracionários como um número flutuante não o torna um número de ponto flutuante. Tive problemas com isso quando estava fazendo comparações de tempo de carimbo de data / hora do Wireshark em Python ... os cálculos de tempo no pcap-ng simplesmente não estavam funcionando. Somente quando tratei as duas partes (segundos inteiros e nanossegundos inteiros) como ambos os inteiros, pude obter os números adequados.

Isso ocorre porque os números de ponto flutuante têm problemas de precisão . De fato, um pouco de Ruby irá mostrar a você que to_f não é igual, digamos, nsec:

irb(main):019:0> t=Time.now
=> 2015-04-10 16:41:35 -0500
irb(main):020:0> puts "#{t.to_f}; #{t.nsec}"
1428702095.1435847; 143584844

Advertência Programador. Você pode estar seguro com 3 dígitos significativos, mas o fato permanece: os números de ponto flutuante em computadores são aproximações. Os contadores de nanossegundos em computadores modernos são inteiros.

Mike S
fonte
A melhor resposta. Obrigado. O formato de diretiva .strftime("%9N")também pode ser usado. ruby-doc.org/core-2.3.1/Time.html#method-i-strftime
rplaurindo
13

Obtenha um objeto Time com Time.now, a chamada #to_iretorna um carimbo de data / hora Unix (segundos da época). #to_ffornece segundos fracionários que você pode usar para obter milissegundos da época:

Time.now.to_f * 1000
levinalex
fonte
3
isso falsifica os milissegundos
brauliobo
@brauliobo Como isso "falsa milissegundos"? Você se deu ao trabalho de executar o código e verificar por si mesmo?
coisnepe
0

O typecast Integer (1e6 * Time.now.to_f) retorna um Bignum que pode conter os milissegundos

chava
fonte