2009-03-11 1 views
6

Ich habe eine Rails-Anwendung, wo ich Created_at als Datetime (Standard) speichern. Ich baue ein Formular für die Suche und ich finde, ich muss find_by_sql verwenden, um einige komplexe Unterabfragen zu tun. Das Formular hat einen Datumsbereich (keine Zeit), nach dem für das created_at-Feld gesucht werden kann.Wie Datumsbereich für Rails/MySQL korrekt konvertiert oder abgefragt wird DateTime-Spalte

Das Problem ich finde, ist, dass wenn ich in nur dem Datum String übergeben für Bereich abfragen ...

... status_changes.created_at between '2009-01-24' and '2009-03-12' ... 

Ich erhalte zurück Aufzeichnungen, die ein created_at Datum 2009-01-23 17 haben: 10:39 -0800, weil dies in der db gespeichert ist als 2009-01-24 01:10:39 (UTC)

Wie kann ich das beheben, so dass das Ergebnis den betreffenden Datensatz nicht zurückgibt?

Es scheint, entweder ich brauche den Datumsbereich konvertieren die find_by_sql sein UTC spezifische oder sagen zu der aktuellen Zeitzone basierend Suchen Sie stattdessen die Spalte als utc lesen ...

Jeder Abnehmer?

John

Antwort

4

Ich weiß, dass dies eine alte Frage, aber in der Antwort auf Optimiert die Abfrage über CONVERT_TZ:

Sofern Sie nicht die mySQL-Zeitzonentabelle geladen haben (was bei einer Vanilla-Installation ziemlich unwahrscheinlich ist), müssen Sie Zeitzonen als einen Offset von UTC eingeben.

CONVERT_TZ(status_changes.created_at, '+00:00', '+08:00') between '2009-01-24' and '2009-03-12') 
+0

Dank Jordan. Ich bin mir nicht sicher, ob ich das in absehbarer Zeit testen kann, aber Ihre Antwort scheint plausibel. – Streamline

1

MySQL hat eine Funktion, die eine CONVERT_TZ Datumzeit dauert und wandelt sie von einer Zeitzone in eine andere. Sie können Ihre Abfrage so erstellen, dass sie vom gespeicherten Wert (UTC) in Ihre lokale Zeitzone (PST) konvertiert.

CONVERT_TZ(status_changes.created_at,'UTC',?) between ? and ?, 'PST, '2009-01-24', '2009-03-10' 
7

Wenn Sie nicht find_by_sql verwenden, sondern eine find mit einer :conditions Klausel verwenden, die die Rails lassen Ersetzungen tun, ist es alles automatisch konvertieren.

Model.find :all, 
    :conditions => ["created_at between ? and ?", start_date, end_date] 

Im schlimmsten Fall, wenn Rails durch die Termine verwechselt wird, können Sie sie zu Zeiten konvertieren und es sollte schön spielen:

Model.find :all, 
    :conditions => ["created_at between ? and ?", 
        start_date.to_time, end_date.to_time] 
0

Ich versuchte Ians Antwort, aber es hat nicht ganz funktioniert. Rails behandelt die Zeitzone beim Speichern und Laden von Datensätzen korrekt, bei Abfrageparametern scheint dies jedoch nicht der Fall zu sein. Beachten Sie, dass sich die Anwendung, an der ich arbeite, in Rails 2.1.1 befindet, sodass sich die Dinge seitdem etwas verbessert haben könnten.

Mit einem kleinen Tweak konnte ich die Lösung von Ian jedoch funktionieren lassen: Ermitteln Sie den Zeitwert in der UTC-Zeitzone mit der getutc-Methode und übergeben Sie ihn dann als Parameter. Dies sollte auch in späteren Versionen von Rails, die die Zeitparameterzone korrekt behandeln, keinen Schaden verursachen, da die UTC-Zeit nicht durch getutc geändert wird, sondern nur die Zeitzone.

0

Da Rails die Daten in UTC in der Datenbank gespeichert werden, sollten Sie die utc Methode auf Time oder DateTime verwenden

d

Model.find :all, 
    :conditions => ["created_at between ? and ?", start_date.utc, end_date.utc] 
+0

Weitere Informationen finden Sie unter http://marklunds.com/articles/one/402 – paulodeon

12

Die moderne Active Weg dies zu tun ist:

Model.where(time_field: date1..date2) 
-1
Model.where(:from => "2012-01-01".to_date.."2012-06-30".to_date) 

für mich gearbeitet (: aus ist Datenbankfeld des Typs 'Datum')