7
votes

Est-ce que quelqu'un sait-il comment traiter de manière appropriée les fuseaux horaires des utilisateurs dans les rails 2.3?

Nous construisons une application Rails qui doit afficher des dates (et plus important encore, les calculer) dans plusieurs fuseaux fusionnées.

Quelqu'un peut-il me diriger vers comment travailler avec les horaires d'utilisation des rails 2.3 (.5 ou .8 ) p>

L'article le plus inclusifique que j'ai vu détailler la manière dont les zones de temps d'utilisateur sont censées fonctionner sont ici: http://wiki.rubyonrails.org/howtos/time-zones ... Bien que cela ne soit pas clair lorsque cela a été écrit ou pour quelle version des rails. Spécifiquement, il stipule que: p>

"TIME.ZONE - Le fuseau horaire réellement utilisé à des fins d'affichage. Ceci peut être réglé manuellement pour remplacer config.time_zone sur une base de demande." P>

clés termes étant "affichage" et "par requête". p>

localement sur ma machine, c'est vrai. Cependant, sur la production, ni ne sont vraies. La définition du temps.Zone persiste au-delà de la fin de la demande (à toutes les demandes suivantes) et affecte également la manière dont AR enregistre à la base de données (traitant essentiellement n'importe quelle date, comme s'il était déjà en UCC, même si ce n'est pas), ce qui sauve des valeurs complètement inappropriées. . P>

Nous gérons Ruby Enterprise Edition sur la production avec passager. Si tel est mon problème, devons-nous passer à Jruby ou autre chose? P>

Pour illustrer le problème, je pose actuellement les actions suivantes dans mon applicationController: P>

Processing ApplicationController#test (for 98.202.196.203 at 2010-12-24 22:15:50) [GET]
TIME.ZONE#<ActiveSupport::TimeZone:0x2c57a68 @tzinfo=#<TZInfo::DataTimezone: Etc/UTC>, @name="UTC", @utc_offset=0>
nil
Fri Dec 24 22:15:50 UTC 2010
Fri Dec 24 22:00:00 UTC 2010
Fri Dec 24 22:00:00 UTC 2010
Fri, 24 Dec 2010 22:00:00 UTC +00:00
Fri Dec 24 22:00:00 UTC 2010
Fri, 24 Dec 2010 22:00:00 UTC +00:00
Completed in 21ms (View: 0, DB: 4) | 200 OK [http://www.dealsthatmatter.com/test]


Processing ApplicationController#test2 (for 98.202.196.203 at 2010-12-24 22:15:53) [GET]
TIME.ZONE#<ActiveSupport::TimeZone:0x2c580a8 @tzinfo=#<TZInfo::DataTimezone: America/Denver>, @name="Mountain Time (US & Canada)", @utc_offset=-25200>
nil
Completed in 143ms (View: 1, DB: 3) | 200 OK [http://www.dealsthatmatter.com/test2]


Processing ApplicationController#test (for 98.202.196.203 at 2010-12-24 22:15:59) [GET]
TIME.ZONE#<ActiveSupport::TimeZone:0x2c580a8 @tzinfo=#<TZInfo::DataTimezone: America/Denver>, @name="Mountain Time (US & Canada)", @utc_offset=-25200>
nil
Fri Dec 24 22:15:59 UTC 2010
Fri Dec 24 22:00:00 UTC 2010
Fri Dec 24 22:00:00 UTC 2010
Fri, 24 Dec 2010 15:00:00 MST -07:00
Fri Dec 24 22:00:00 UTC 2010
Fri, 24 Dec 2010 15:00:00 MST -07:00
Completed in 20ms (View: 0, DB: 4) | 200 OK [http://www.dealsthatmatter.com/test]

Processing ApplicationController#test3 (for 98.202.196.203 at 2010-12-24 22:16:03) [GET]
TIME.ZONE#<ActiveSupport::TimeZone:0x2c57a68 @tzinfo=#<TZInfo::DataTimezone: Etc/UTC>, @name="UTC", @utc_offset=0>
nil
Completed in 17ms (View: 0, DB: 2) | 200 OK [http://www.dealsthatmatter.com/test3]

Processing ApplicationController#test (for 98.202.196.203 at 2010-12-24 22:16:04) [GET]
TIME.ZONE#<ActiveSupport::TimeZone:0x2c57a68 @tzinfo=#<TZInfo::DataTimezone: Etc/UTC>, @name="UTC", @utc_offset=0>
nil
Fri Dec 24 22:16:05 UTC 2010
Fri Dec 24 22:00:00 UTC 2010
Fri Dec 24 22:00:00 UTC 2010
Fri, 24 Dec 2010 22:00:00 UTC +00:00
Fri Dec 24 22:00:00 UTC 2010
Fri, 24 Dec 2010 22:00:00 UTC +00:00
Completed in 151ms (View: 0, DB: 4) | 200 OK [http://www.dealsthatmatter.com/test]


0 commentaires

3 Réponses :


0
votes

J'ai eu ce problème lorsque je construisais un système de billetterie de support. Ma solution était la suivante.

Définissez le fuseau horaire de DateTime SQL et Activerecord sur UTC.

Définissez le format de votre temps souhaité dans la configuration de votre application.

Faites une classe CSS pour la façon dont vous souhaitez que le CSS de votre date de regarder. Faire le nom unique. PAR EXEMPLE. Utcdate

Écrire JavaScript pour rechercher la page pour les classes de date nommées DOM (UTCDate ci-dessus). Étant donné que JavaScript est exécuté par l'utilisateur final, il remplacera la valeur avec ce que la machine locale est réglée sur. Dans le cas où vous avez une erreur d'analyse, quittez l'heure en UTC. Regardez ici pour JavaScript pertinent

L'avantage de cette solution est votre application ne dispose pas d'un sélecteur de fuseau horaire stupide comme tant de forums. Il diminue également la charge de la charge du serveur et la taille de la base de code (puisque vous n'avez pas à stocker ou gérer aucune information sur les zones de temps de client) pour gérer une tâche importante mais difficile.


0 commentaires

9
votes

Après une recherche exhaustive, il est maintenant complètement clair que le temps.Zone est cassé dans la plupart des versions des rails (y compris 2.3 et 3). Cette fonctionnalité utilise un hachage de fil central pour stocker la valeur définie (qui est censé être du fil de sécurité, et n'est pas) et finit par modifier le comportement pour toutes les demandes suivantes. De plus, contrairement à la documentation, le réglage du temps.ZONE modifie le comportement ActiveRecord et enregistre les temps de date dans la nouvelle zone, au lieu de celui spécifié dans la configuration (qui est généralement UTC).

jusqu'à ce que les rails obtiennent cela, nous avons choisi de travailler avec Timezones manuellement, qui peuvent être accessibles via la méthode par défaut non documentée: P>

module ActiveSupport #:nodoc:
  module CoreExtensions #:nodoc:
    module Time #:nodoc:
      module ZoneCalculations
        def self.included(base) #:nodoc:
          base.class_eval do
            alias_method_chain :change, :zone
          end
        end

        def change_zone(new_zone)
          new_zone = ::Time.__send__(:get_zone, new_zone)
          return self if new_zone.name == zone
          new_zone.local(year,month,day,hour,min,sec,usec)
        end

        def change_with_zone(options)
          result = change_without_zone(options)
          options[:zone] ? result.change_zone(options[:zone]) : result
        end

      end
    end
  end
  class TimeWithZone
    def change_zone(new_zone)
      time.change_zone(new_zone)
    end
    def change(options)
      time.change(options)
    end
  end

end

class Time
  include ActiveSupport::CoreExtensions::Time::ZoneCalculations
end


1 commentaires

Convenu - Timezones étant cassé dans des rails 2.3. * M'a mordu sur le cul plus d'une fois



8
votes

Vous avez raison dans ce rails ne réinitialise pas automatiquement le fuseau horaire par demande. L'auteur Wiki donne un exemple dans lequel le fuseau horaire est défini dans un filtre avant, il ne subit donc jamais le problème des zones de temps "fuites" entre les demandes (car le fuseau horaire est configuré correctement avant la demande). L'exemple utilisé dans la documentation RDOC pour Timezone.zone = code> est similaire. Je pense donc que c'est un problème de documentation.

Changer le fuseau horaire ne demande pas local, il est en fil local. Les rails stockent le fuseau horaire sélectionné dans le thread de courant (voir fil.current. [: Time_zone] code>), pas dans la demande actuelle. Comme le même thread gère plusieurs demandes, les modifications apportées au temps.Zone sont persistantes entre les demandes. P>

Je pense que la bonne façon d'utiliser des fuseaux horaires dans votre scénario consiste à utiliser temps.utilisateur code >: P>

def my_action
  Time.zone # 'UTC'
  Time.use_zone('Mountain Time (US & Canada)') do
    Time.zone # 'Mountain Time (US & Canada)'
  end
  Time.zone # 'UTC'
end


1 commentaires

C'est la bonne réponse. Et si vous souhaitez envelopper une action complète des rails dans un fuseau horaire, utilisez un roturel autour de un fichier avant_filter.