6

Tengo un problema con las zonas horarias y un db postgresql (Rails 3.0.4, PostgreSQL 9.0). Estoy usando un ámbito personalizado, en el que añado algunas condiciones, hago combinaciones, etc.pp.Rails no convierte la zona horaria (PostgreSQL)

El problema es que los rieles no convierten los tiempos a mi zona horaria local. Este es el código del alcance:

scope :with_activities_within_range_in_week, lambda{ |latMin, lngMin, latMax, lngMax, date| 
    select("date_trunc('day', activities.starting_at) as date, 
     count(activities.id) as value 
    ") \ 
    .within(latMin, lngMin, latMax, lngMax) \ 
    .joins(:activities) \ 
    .merge(Activity.in_week(date)) \ 
    .group("date") \ 
    .order("date") 
    } 

El contexto de los controles método para rangos, el alcance Activity.in_week devuelve esto:

where("activities.starting_at >= ? AND activities.starting_at < ?", start, stop) 

Y en la instrucción de selección, quiero TRUNCAR la posición_inicial campo a día.

Me estoy poniendo la siguiente salida para el campo de fecha:

2011-04-07 18:48:32 
2011-04-02 14:07:20 
2011-04-02 14:06:49 

Por desgracia, no incluye la zona horaria. Cuando intento acceder a mi modelo a través de las funciones "normales" Rails, funciona:

puts Activity.first.starting_at 
-> 2011-04-15 06:47:55 +0200 

Lo que estoy haciendo mal? ¡Espero que alguien pueda ayudar!

THX, esmoquin

+0

¿Qué tipo es 'activities.starting_at' dentro de la base de datos? ¿Y qué sucede si 'seleccionas starting_at from activities' desde' psql'? –

+0

El 'activities.starting_at' es un' timestamp sin una zona horaria' (almacenado en utc). 'select starting_at from activities' devuelve' 2011-04-15 04: 47: 34', también sin una zona horaria. Pero, ¿no deberían los rieles convertir el tiempo en la zona horaria específica sobre la marcha? Con mi ejemplo de mi pregunta 'pone Activity.first.starting_at -> 2011-04-15 06:47:55 + 0200' funciona. – 23tux

+0

Encontré otra cosa interesante: cuando intento iterar sobre los resultados, y vuelco la clase de mi campo de fecha, obtengo 'String'. Pero debería ser 'ActiveSupport :: TimeWithZone'. Leí la documentación de postgresql, y 'date_trunc ('day', activities.starting_at)' debería devolver una 'timestamp'. ¿Por qué Rails no convierte esto? – 23tux

Respuesta

5

Su base de datos es el almacenamiento de sus marcas de tiempo en UTC (como debería). ActiveRecord está haciendo ajustes de zona horaria cuando sabe que tiene una marca de tiempo; Por lo tanto, cuando se dice esto:

puts Activity.first.starting_at 

AR sabe que starting_at es una marca de tiempo por lo que crea la instancia de la marca de tiempo como una instancia ActiveSupport::TimeWithZone y que la clase se aplica el ajuste de zona horaria. Pero, cuando se dice esto:

select("date_trunc('day', activities.starting_at) as date ... 

AR no se va a analizar el SQL para darse cuenta de que date_trunc volverá una marca de tiempo, AR ni siquiera sabe lo que date_trunc medios. AR solo verá una cadena que sale de la base de datos y se la entregará sin interpretación. Puede alimentar esa cadena al ActiveSupport::TimeWithZone (o a su clase de manejo de tiempo favorita) usted mismo: no hay nada de malo en contarle a AR cosas que no sabe y no puede saber por sí mismo.

Rails es inteligente pero no es mágico.

+0

thx por su respuesta. Eso fue lo que descubrí al arrojar la clase. ¿Cómo alimentaría la cadena a 'ActiveSupport :: TimeWithZone''? Iteramos a través de los resultados y convertimos la cadena? – 23tux

+0

Vas a iterar a través de los resultados de todos modos para poder lanzar las cosas de TimeWithZone ahí. No soy un gurú de alcance de AR3, así que podría haber una mejor manera. –

Cuestiones relacionadas