Zeitstempel mit Zeitzone in Schienen speichern 3.2

8

Ich versuche alle Zeitstempel in einer Rails-Anwendung mit ihrer Zeitzone zu speichern. Mir geht es gut mit ActiveRecord, das sie in utc umwandelt, aber ich habe mehrere Anwendungen, die dieselbe Datenbank treffen, von denen einige mit einer Zeitzonenanforderung implementiert werden. Also, was ich tun möchte, ist activerecord zu bekommen, um meine Zeitstempel wie üblich zu konvertieren, und sie dann in die Datenbank mit der Zeichenkette 'America / Los_Angeles' oder einer anderen geeigneten Zeitzone zu schreiben, die an den Zeitstempel angehängt wird. Ich laufe derzeit Rails 3.2.13 am jruby 1.7.8, welches den ruby ​​1.9.3 api implementiert. Meine Datenbank ist postgres 9.2.4, verbunden mit dem activerecord-jdbcpostgresql-adapter Juwel. Der Spaltentyp ist ein Zeitstempel mit Zeitzone.

Ich habe die natürlichen Active-Record-Mappings bereits mit dem activerecord-native_db_types_override gem geändert, indem ich die folgenden Zeilen zu meiner environment.rb hinzufüge:

%Vor%

Meine application.rb enthält derzeit

%Vor%

Ich vermute, ich kann ActiveSupport::TimeWithZone.to_s umschreiben und das Format ':: db' ändern, um die richtige Zeichenfolge auszugeben, aber das war noch nicht möglich. Jede Hilfe wird sehr geschätzt.

    
Raskolnikov 19.12.2013, 01:26
quelle

3 Antworten

3
Nachdem ich meinen Kopf gegen das gleiche Problem gestoßen hatte, lernte ich die traurige Wahrheit der Sache:

Postgres unterstützt nicht die Speicherung von Zeitzonen in einem seiner Datums- / Zeittypen .

Es gibt also einfach keine Möglichkeit, sowohl einen einzelnen Zeitpunkt als auch seine Zeitzone in einer Spalte zu speichern. Bevor ich eine alternative Lösung vorschlage, möchte ich das mit den Postgres-Dokumenten :

  

Alle zeitzonenbewussten Daten und Uhrzeiten werden intern in UTC gespeichert. Sie werden in der vom TimeZone-Konfigurationsparameter angegebenen Zone in die lokale Zeit konvertiert, bevor sie dem Client angezeigt werden.

Es gibt also keinen guten Weg, die Zeitzone einfach an den Zeitstempel anzuhängen. Aber das ist nicht so schlimm, das verspreche ich! Es bedeutet nur, dass Sie eine andere Spalte benötigen.

Meine (eher einfache) vorgeschlagene Lösung:

  1. Speichern Sie die Zeitzone in einer String-Spalte (grob, ich weiß).
  2. Anstatt to_s zu überschreiben, schreibe einfach einen Getter.

Angenommen, Sie benötigen dies in der Spalte explodes_at :

%Vor%

Wenn Sie die Zeitzone automatisch speichern möchten, überschreiben Sie Ihren Setter:

%Vor%

Um sicherzustellen, dass t.zone die richtige Zeitzone zurückgibt, muss Time.zone auf die richtige Zone eingestellt werden. Sie können Time.zone für jede Anwendung, jeden Benutzer oder jedes Objekt leicht variieren, indem Sie einen Around-Filter (Railscast) verwenden. . Es gibt viele Möglichkeiten, dies zu tun. Ich mag den Ansatz von Ryan Bates, also implementieren Sie ihn auf eine Weise, die für Ihre Anwendung sinnvoll ist.

Und wenn Sie sich etwas einfallen lassen wollen und diesen Getter für mehrere Spalten benötigen, können Sie alle Ihre Spalten durchlaufen und für jede Datetime eine Methode definieren:

%Vor%

Dies beinhaltet keine Setter-Methode, weil Sie nicht wirklich wollen, dass jede einzelne datetime-Spalte in self.time_zone schreiben kann. Sie müssen entscheiden, wo dies verwendet wird. Und wenn Sie wirklich möchten, können Sie dies für alle Ihre Modelle implementieren, indem Sie sie innerhalb eines Moduls definieren und in jedes Modell importieren.

%Vor%

Hier ist eine ähnliche hilfreiche Antwort: Ignorieren von Zeitzonen in Rails und PostgreSQL

Hoffe, das hilft!

    
Kyletns 02.01.2014, 23:41
quelle
2

Darf ich vorschlagen, sie in iso8601 zu speichern

Damit können Sie:

  • Möglichkeit, sie auch als UTC zu speichern wie bei einer Zeitzone Offset
  • Internationale Standards einhalten

  • Verwenden Sie in beiden Fällen das gleiche Speicherformat mit Offset und ohne.

Eine der db-Spalten kann also nur in UTC-Form mit einem Offset versehen sein (üblich).

Von der Ruby-Seite ist es so einfach wie

%Vor%

ActiveRecord sollte nahtlos mit der Konvertierung funktionieren.

Außerdem verwenden die meisten APIs dieses Format (google), daher am besten für die Kompatibilität mit verschiedenen Apps.

to_char () für postgresql sollte Ihnen das richtige Format für den Fall geben, dass ein Fehler in der Standardkonfiguration auftritt.

    
Abs 28.12.2013 16:30
quelle
1

Ein Ansatz, wie Sie vorschlagen, wäre es, ActiveSupport::TimeWithZone.to_s

zu überschreiben

Sie könnten so etwas versuchen:

%Vor%

Ich habe das nicht getestet, aber Postgres-Dokumente auf Zeitmarken , das sieht gut aus und würde eine Zeit geben wie: "2013-12-26 10:41:50 +0000"

Das Problem dabei ist, soweit ich das beurteilen kann, dass Sie immer noch Schwierigkeiten haben, die richtige Zeitzone zurückzugeben:

  

Für Zeitstempel mit Zeitzone ist der intern gespeicherte Wert immer in UTC (Universal Coordinated Time, traditionell als Greenwich Mean Time, GMT bekannt). Ein Eingabewert, für den eine explizite Zeitzone angegeben ist, wird mit dem entsprechenden Offset für diese Zeitzone in UTC konvertiert.

Genau das tut das ursprüngliche ActiveSupport::TimeWithZone.to_s bereits.

Der beste Weg, um die richtige Zeitzone zu erhalten, ist vielleicht, einen expliziten Zeitzonenwert als neue Spalte in der Datenbank festzulegen.

Dies würde bedeuten, dass Sie die native Date-Funktionalität von Postgres und Rails beibehalten könnten, während Sie auch die Zeit in der richtigen Zeitzone anzeigen könnten, falls erforderlich.

Sie könnten diese neue Spalte verwenden, um dann die richtige Zone mit Rubys Time::getlocal oder Rails ' ActiveSupport::TimeWithZone.in_time_zone ' anzuzeigen.

    
benjaminjosephw 26.12.2013 11:01
quelle