Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

264
Visualizações
Rails / MySQL: How to query for a record by its full 'created_at' timestamp?

I want to be able to find a User record by its created_at timestamp (which in this case is: 2020-08-07 11:30:28.5934908).

But the result is this:

User.where(created_at: '2020-08-07 11:30:28.5934908').first
=> nil

The reason that this (existing) User record is not found seems to become evident in the MySQL query that Rails generated:

User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`created_at` = '2020-08-07 11:30:28.593490' ORDER BY `users`.`id` ASC LIMIT 1

...where for some reason the last digit 8 is dropped from the timestamp 2020-08-07 11:30:28.5934908 used in the MySQL query.

What is the problem here? Does Rails shorten the timestamp in the query? Or does MySQL do this? How do I solve this?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

Based on your comments I think that the main problem is in the conversion of the microseconds-precise time to Float. Float (even though in ruby internally a Double) does not have enough accuracy to fully represent all dates / times with microseconds precision, as is documented in the Time class (although they speak about “nanoseconds”, interestingly). Such conversion then only tries to find the nearest possible representation in Float. Rounding the resulting float number back to 6 digits may work but I’m not sure it’s guaranteed to always work…

Suppose that the real time stored in DB is 2020-08-07 11:30:28.593491. As you’ve noticed, this converts to Float imprecisely:

>> Time.parse('2020-08-07 11:30:28.593491').to_f
=> 1596792628.5934908

The guaranteed method would be to use a Rational number instead, i.e. to_r:

>> Time.parse('2020-08-07 11:30:28.593491').to_r
=> (1596792628593491/1000000)

To reconstruct the Time back from the rational number, you can use Time.at:

>> Time.at(Rational(1596792628593491, 1000000)).usec
=> 593491

Note that the microseconds are fully preserved here.

So, storing a created_at time precisely and using it later to search for a record involves using a Rational number variable instead of Float:

>> user_created_at = User.first.created_at.to_r
=> (1596792628593491/1000000)

>> User.where(created_at: Time.at(user_created_at)).first == User.first
=> true

An alternative approach might be to store both the integer seconds since Epoch (User.first.created_at.to_i) and the nanoseconds fraction (User.first.created_at.usec) separately in two variables. They can be the used in Time.at, too, to reconstruct the time back.

As a sidenote, this has also been discussed in a Rails issue with a similar conclusion.

over 4 years ago · Santiago Trujillo Relatório

0

This isn't a direct answer to your question rather a workaround of sorts. You could query the created_at column in some very small time delta like this.

User.where(created_at: '2020-08-07 11:30:28.593490'...'2020-08-07 11:30:28.593491')
over 4 years ago · Santiago Trujillo Relatório

0

As per @BoraMa's comment (thanks!), the MySQL created_at timestamp must have 6 digits only. Thus, the working query would look like this:

User.where(created_at: '2020-08-07 11:30:28.5934908'.round(6)).first
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda