2010-12-03 26 views
11

que tenía el siguiente aparato:rieles Fechas Hora y Accesorios

link_1: 
    user: tom 
    image: boy1 
    created_at: <%= 5.day.ago %> 

Probé la petición siguiente:

Links.where("Date(created_at) = ?", 5.day.ago.to_date) 

Respuesta:

[] 

grrrr .. ..typing ... typing ... scratching ... finalmente he intentado:

link_1: 
    user: tom 
    image: boy1 
    created_at: <%= 5.day.ago.to_date %> 

y

Links.where("Date(created_at) = ?", 5.day.ago.to_date) 

finalmente responde

[#<Link id: 298486374, user_id: 1038054164, image_id: 482586125, created_at: "2010-11-28 00:00:00", updated_at: "2010-12-03 21:32:19">] 

lo que estaba esperando, pero ¿por qué tengo que poner to_date? No está claro para mí, porque cuando se crea un objeto sin especificar la fecha de creación, puedo seleccionarlos con la cláusula siguiente, donde sin ningún problema:

Links.where("Date(created_at) = ?", Date.today) 

Alguna idea?

+0

Permítanme ser más claro, mi pregunta es: ¿Por qué está funcionando mi consulta cuando puse .to_date en el accesorio y no cuando no lo puse. – standup75

Respuesta

1

Me gustaría especular que es debido a la diferencia de tiempo entre cuando se creó el dispositivo y cuando se llamó a la consulta. Hace

5 días + 0,00025 ms> hace 5 días

No estoy seguro de lo que la precisión es para datetimes, pero es la única posibilidad que se me ocurre. Cuando lo convirtió a una fecha, eliminó la información de tiempo extra y los hizo iguales.

+0

Esto no es un problema de zona horaria ya que el último ejemplo Links.where ("Date (created_at) =?", Date.today) está funcionando bien – standup75

+0

No estoy diciendo que sea un problema de zona horaria. Hay un pequeño retraso entre el momento en que se insertó la fecha y la hora (diremos 12/05/2010 12: 00: 00.0000) vs cuando se estaba comparando (12/05/2010 12: 00: 00,0005). Esa es la diferencia de tiempo de la que estaba hablando. –

0

La diferencia entre sus dos casos es que cuando llama al to_date, pierde el valor del tiempo, por lo que el resultado final es una marca de tiempo created_at establecida a la medianoche de ese día. También evita la traducción de huso horario desde TimeWithZone. Francamente, no tenemos suficiente información para conjeturar lo que está sucediendo más allá de esto. Para ver exactamente qué está sucediendo, la mejor opción es consultar las consultas en su log/test.log. Si no ve consultas, puede activarlas configurando log_level en :debug en config/environments/test.rb. Siéntase libre de copiar y pegar las consultas SQL aquí.

@Ibz también plantea un buen punto: usar .to_s(:db) es una buena idea, porque el archivo de dispositivo ERB se evalúa como una cadena y luego se lee como YAML, lo que puede causar problemas con la conversión de valores a cadenas. El uso de .to_s(:db) solucionará este problema, pero para evitar esto en el futuro (y obtener un montón de funciones adicionales), recomendaría usar factory_girl en lugar de accesorios.

Este tipo de problemas son comunes cuando se trata de fechas de prueba, especialmente si intenta consultar por igualdad de dos fechas o marcas de tiempo. Para abordar estos problemas, recomiendo elegir fechas/horas fijas arbitrarias en el pasado en lugar de hacer 5.days.ago, o si necesita usar fechas/horas dinámicas, use el Timecop gem para controlar/congelar el tiempo dentro de sus pruebas.

+0

Mi pregunta fue más "por qué está funcionando" que "por qué no está funcionando" – standup75

+0

@ standup75: respuesta editada. – wuputah

19

En los accesorios que debe tener:

created_at: <%= 5.day.ago.to_s(:db) %> 

Su consulta será una:

Links.where("created_at = ?", ... 

Vamos ActiveRecord el cuidado de los detalles acerca de cómo mover datos desde y hacia la base de datos. Estamos usando un ORM por una razón.

Reference.

+0

to_s (: db) es el camino a seguir aquí, me he encontrado con esto. –

+0

5.day.ago == 5.day.ago.to_date => false es claro para mí, pero este no es el problema aquí, mi punto es que está funcionando cuando puse .to_date – standup75

+0

En tu dispositivo estás lanzando 5.day.ago (del tipo 'ActiveSupport :: TimeWithZone') a' Date'. Lo que se guarda en la base de datos, luego se convierte en 'Fecha' dentro de su consulta con' Fecha (created_at) = ... '. 'Date' no le importa la hora o la zona horaria de la aplicación Rails. Encienda la consola 'carriles' y compare los resultados que ha introducido' 5.day.ago', '5.day.ago.to_date',' 5.day.ago.to_s (: db) 'para tener algo empírico para ver a. Verá diferentes _valores_. – lbz

1

created_at es un campo DateTime y 5.days.ago devuelve efectivamente un objeto DateTime. Este objeto tendrá el mismo tiempo configurado como en el momento en que se lo llama, por ej. Sáb, 23 de agosto de 2014 10:30: , y esto es lo que se pone en la base de datos.

En su caso anómalo, cuando llama al 5.days.ago nuevamente más tarde (incluso en la misma ejecución), la nueva hora probablemente difiera, por ej. Sáb, 23 de agosto de 2014 10:30: . Por lo tanto, puede ver que no son iguales y no obtendrá coincidencias.

Cuando anexa .to_date, obtiene un objeto Date, que no tiene componente de tiempo. Cuando esto persista en la base de datos o se use en su consulta, siempre se considerará que tiene una hora de 00:00:00 (medianoche). Por lo tanto, la fecha y la hora coincidirán (siempre que no intente ejecutar los dispositivos y la consulta exactamente pasada la medianoche)

Cuestiones relacionadas