2012-04-10 14 views
5

Estoy tratando de encontrar eventos en determinados días con este código:Rails 3 DateTime y hora formato beginning_of_day end_of_day incorrecta

Event.where('starttime BETWEEN ? AND ?', DateTime.now.beginning_of_day, DateTime.now.end_of_day) 

En la consola rieles si funciono DateTime.now.beginning_of_day consigo exactamente lo que espero:

Lunes, 09 de abril de 2012 00:00:00 -0700

Veo dónde está ocurriendo el problema, pero miro la consola SQL en los rieles. De alguna manera, cuando la fecha llega a la consulta SQL, se formatea automáticamente en la fecha y hora incorrectas.

SELECT "events".* FROM "events" WHERE (starttime BETWEEN '2012-04-09 07:00:00' AND '2012-04-10 06:59:59') 

Esto me está dando resultados que varían desde hoy hasta mañana, como dice el sql anterior. Puedo ver que cuando DateTime.now.beginning_of_day también DateTime.now.end_of_day están siendo formateados incorrectamente una vez que entran en la consulta sql. ¿Debo formatear esto de cierta manera? ¿Alguna idea de por qué iría a las 7:00 de hoy y a las 7:00 de mañana?

No sé si hace una diferencia, pero estoy usando PostgreSQL.

Gracias!

Respuesta

15

Ver: http://railscasts.com/episodes/106-time-zones-in-rails-2-1

creo que las veces que se está citando anteriormente son en realidad el mismo tiempo, sólo una es la hora UTC (usted es la hora del Pacífico ¿verdad?). Para solucionar este problema podría intentar configurar:

config.time_zone = "Hora del Pacífico (EE.UU. & Canadá)"

en su environment.rb

También puede probar:

DateTime.now.utc.beginning_of_day 
DateTime.now.utc.end_of_day 

entonces usted está usando UTC según el DB

+0

hey, aprecio la respuesta. No sé si te sigo por completo, pero no creo que sea una buena idea cambiar mi configuración a la hora pacífica, porque ¿qué pasa con los usuarios que no están en tiempo pacífico? Espero que entienda lo que dices. Además, usar DateTime.now.utc.beginning_of_day está causando el mismo problema cuando ejecuto las consultas que enumeré en mi publicación inicial. – botbot

+0

sí, estoy en el momento pacífico. después de investigar un poco, parece que esta es una posible solución. Voy a intentar esto. Gracias por la sugerencia. Todavía estoy preocupado por los usuarios en NY, no sé si eso sería un problema, pero hacer que la aplicación funcione en tiempo pacífico definitivamente es lo suficientemente bueno para la creación de prototipos en este momento. Gracias. – botbot

+0

@masterkrang, si necesita preocuparse por los usuarios en Nueva York y diferentes zonas horarias, registre en qué zona horaria se encuentra el usuario y configúrelo adecuadamente para esa solicitud de los usuarios, p. https://gist.github.com/809775 – rainkinz

2

Probablemente esté utilizando la hora UTC en su base de datos. Esto es algo bueno pero conduce a todo tipo de confusión. El desplazamiento -0700 se convierte a 07:00:00 ya que es cuando su día comienza en hora UTC.

+0

gracias por la respuesta. entonces, si es bueno usar utc, entonces, ¿cómo evito que el desplazamiento se convierta en un momento en el que ejecuto consultas? – botbot

+0

El motivo por el que utiliza UTC es para no tener que realizar un seguimiento de la zona horaria en la que se creó la base de datos, por lo que puede convertir fácilmente UTC de compensación cero a horas locales según sea necesario. La mayoría de las configuraciones regionales cambian los desplazamientos de la zona horaria durante todo el año debido al horario de verano. "00:00:00 -0700" es igual a "07:00:00 -0000". ¿Están sus valores de 'hora de inicio' almacenados en UTC o han eliminado inadvertidamente la información de la zona horaria antes de guardarlos? – tadman

+0

el campo en la base de datos postgresql es "marca de tiempo sin zona horaria". Me doy cuenta de que este es un problema bastante grande en todas las fechas de mi aplicación. si establezco una propiedad en un ActiveRecord, digamos Model.my_var = Time.now, luego llamo guardar, el Time.now se guardará en la base de datos como mañana en algún momento. por ejemplo, si Time.ahora = Mié 11 de abril 22:48:12 -0700 2012, cuando llamo guardar, puedo ver que el sql está guardando la fecha como "2012-04-11 05:47:47", que es el día siguiente 7 horas luego. me doy cuenta de que es porque el -700 que viene de Time.now. Solo estoy tratando de descubrir cómo resolver esto. ¿algunas ideas? – botbot

1

Puede usar el constructo PostgreSQL AT TIME ZONE con marcas de tiempo UTC:

SELECT e.* 
FROM events e 
WHERE starttime >= '2012-04-09 00:00' AT TIME ZONE 'UTC' 
AND starttime < '2012-04-10 00:00' AT TIME ZONE 'UTC' 

Recientemente lo he explicado PostgreSQL timestamp and time zone handling in a related answer.

+0

hey Erwin, aprecio la respuesta. Voy a probar esto, pero la única cosa que me hace sentir reticente a usar esto como la solución es que si quiero cambiar a mysql o volver a sqlite, sería una pena tener que cambiar todas estas cosas. hay algo realmente agradable acerca de poder llamar a Model.where ('datetime BETWEEN? AND?', Time.now.beginning_of_day, Time.now.end_of_day). tal vez estoy soñando, en este momento no está claro si su solución es la más elegante. – botbot

+0

@masterkrang: estoy todo por conveniencia. Pero la corrección es lo primero y el rendimiento a continuación. La idea de operar una base de datos independiente conduce a un bajo rendimiento, ya que difícilmente puede optimizar sus consultas. Las capas de abstracción son buenas para SQL básico, pero en su mayoría son muletas primitivas. Además, 'ENTRE ... Y ...' generalmente arroja resultados ligeramente * incorrectos *. Ambos límites de rango están incluidos. '00: 00' aparece para el día antes y después. Intento evitar esto en mi consulta, que es apenas más complejo que lo que tienes ahora. Finalmente: todo el problema con las zonas horarias * puede * ser un malentendido. –