rails parse hours ruby postgresql datetime activerecord rails-postgresql

parse - strptime ruby



ResoluciĆ³n en milisegundos de DateTime en Ruby (4)

ActiveRecord debe preservar la precisión total de la base de datos, simplemente no la está mirando correctamente. Use strftime y el formato %N para ver los segundos fraccionarios. Por ejemplo, psql dice esto:

=> select created_at from models where id = 1; created_at ---------------------------- 2012-02-07 07:36:20.949641 (1 row)

y ActiveRecord dice esto:

> Model.find(1).created_at.strftime(''%Y-%m-%d %H:%M:%S.%N'') => "2012-02-07 07:36:20.949641000"

Entonces, todo está allí, solo necesitas saber cómo verlo.

También tenga en cuenta que ActiveRecord probablemente le ActiveSupport::TimeWithZone objetos ActiveSupport::TimeWithZone lugar de objetos DateTime , pero DateTime conserva todo:

> ''2012-12-31T01:01:01.232323+3''.to_datetime.strftime(''%Y-%m-%d %H:%M:%S.%N'') => "2012-12-31 01:01:01.232323000"

Eche un vistazo a connection_adapters/column.rb en la fuente ActiveRecord y verifique qué hace el método string_to_time . Su cadena iría por la ruta de fallback_string_to_time y eso conservará los segundos fraccionarios tan cerca como pueda ver. Algo extraño podría estar sucediendo en otra parte, no me sorprendería si se tuvieran en cuenta las cosas extrañas que he visto en la fuente de Rails, especialmente el lado de la base de datos. Intentaría convertir las cadenas en objetos a mano para que ActiveRecord los mantenga alejados de ellos.

Tengo una cadena como 2012-01-01T01:02:03.456 que estoy almacenando en una base de datos de Postgres TIMESTAMP usando ActiveRecord.

Desafortunadamente, Ruby parece cortar los milisegundos:

ruby-1.9.3-rc1 :078 > ''2012-12-31T01:01:01.232323+3''.to_datetime => Mon, 31 Dec 2012 01:01:01 +0300

Postgrs admite una resolución de microsegundos. ¿Cómo puedo hacer que mi marca de tiempo se guarde en consecuencia? Necesito al menos una resolución de milisegundos.

(PD: Sí, podría piratear una columna de enteros de milisegundos en postgres, que de alguna forma frustra el propósito de ActiveRecord).

ACTUALIZAR:
Las respuestas muy útiles mostraron que DateTime de Ruby no está cortando milisegundos; usar #to_f muestra. Pero, haciendo:

m.happened_at = ''2012-01-01T00:00:00.32323''.to_datetime m.save! m.reload m.happened_at.to_f

Hace caer los milisegundos.

Ahora, lo interesante es que created_at muestra milisegundos, tanto en Rails como en Postgres. Pero otros campos de marcas de tiempo (como lo happened_at superior) no. (Quizás Rails usa una función NOW() para created_at en lugar de pasar en DateTime).

Lo que lleva a mi última pregunta:
¿Cómo puedo obtener ActiveRecord para preservar la resolución de milisegundos en los campos de marca de tiempo?


Cambiar m.happened_at = ''2012-01-01T00:00:00.32323''.to_datetime en el código anterior a m.happened_at = ''2012-01-01T00:00:00.32323'' resuelve el problema, aunque no tengo idea de por qué.


Terminé aquí cuando sufría el uso del RVM proporcionado Ruby 2.0.0-p247 binario en OS X (Mavericks) que estaba causando el redondeo a valores enteros de segundos al recuperar los tiempos de Postgres. La reconstrucción de Ruby ( rvm reinstall 2.0.0 --disable-binary ) resolvió el problema para mí.

Ver https://github.com/wayneeseguin/rvm/issues/2189 que encontré a través de https://github.com/rails/rails/issues/12422 .

Reconozco que esta no es LA RESPUESTA a este problema, pero espero que esta nota pueda ayudar a alguien a lidiar con ella.


to_datetime no destruye la resolución de los datos en milisegundos, simplemente está oculta porque DateTime#to_s no la muestra.

[1] pry(main)> ''2012-12-31T01:01:01.232323+3''.to_datetime => Mon, 31 Dec 2012 01:01:01 +0300 [2] pry(main)> ''2012-12-31T01:01:01.232323+3''.to_datetime.to_f => 1356904861.232323

Dicho esto, sospecho que ActiveRecord está ocultando por error esa información cuando persisten los datos; recuerde que es independiente de la base de datos, por lo que se necesitan enfoques que garanticen que funcionen en todos sus objetivos de base de datos. Mientras que Postgres supuso información de microsegundos en sellos de tiempo, MySQL no lo hace, entonces sospecho que AR selecciona el mínimo común denominador. No podría estar seguro sin meterme en las entrañas de AR. Es posible que necesite un monopatch específico de Postgres para habilitar este comportamiento.