web-dev-qa-db-ja.com

TZInfo識別子をRails TimeZone名/キーに変換する方法

TZInfo識別子として受け取ったjs値をRails TimeZone名/キーにどのように変換しますか?

FROM:_"America/New_York"_ JavaScript TZinfo検出から返されました
TO:Rails TimeZoneで使用される"Eastern Time (US & Canada)"規則


または別の例:
_"Pacific/Honolulu"_ =>変換=> _"Hawaii"_

どちらも_ActiveSupport::TimeZone < Object_マッピングで使用できますが、Railsはキーを使用します[例:ドロップダウンの"Eastern Time (US & Canada)"]、検証、およびTime.use_zone()への保存。


私が_ActiveSupport::TimeZone.us_zones_について理解していることに基づくと、これは特にDayLightsの節約時間(Railsがうまく処理できるように聞こえます)の場合に重要であり、オフセットだけを一致させることはできません。 Rails TimeZone名でDBに保存されていない場合、検証は失敗し、ユーザーのプロファイル設定ページで_ActiveSupport::TimeZone.zones_map_のドロップダウンリストと正しく一致しません。

これの目標は、ユーザーがサインアップ時にタイムゾーンを選択する必要がないこと、またはサインアップ後に設定でタイムゾーンを変更する必要がないことです。ブラウザはそれを検出し、サインアップ時にhidden_​​fieldに渡します。まれに、自宅や職場とは別の場所で申し込みをします。後でアカウント設定を手動で上書きできます。

Jsタイムゾーン検出を取り込もうとすると、一般的なギャップのようです。これは、返された情報をjsからRailsに渡して変換し、次にjsに戻してフォームのhidden_​​fieldに保存する方法の二次的な質問になる可能性がありますか?うまくいけば、私は質問を適切に組み立て、確かにRailsで少し緑色にしたので、これに対する簡単な解決策があるかもしれません...

助けてくれてありがとう!
-E


ActiveSupportTime.zoneドキュメント
http://api.rubyonrails.org/classes/ActiveSupport/TimeZone.html#method-i-parse

_MAPPING = {"Eastern Time (US & Canada)" => "America/New_York"
_


jsパッケージ化されたgem'temporal-Rails 'を使用してユーザーのタイムゾーンを検出します。
https://github.com/jejacks0n/temporal

見られるようにユーザーTime_Zone実装:
http://railscasts.com/episodes/106-time-zones-revised

* Devise&Deviseの使用-避けられない


サインアップビュースクリプト

_    <script>
    $(function() {
        var detected_zone = Temporal.detect();
        console.log(detected_zone);  // returns object
        detected_zone = detected_zone.timezone.name;
        console.log(detected_zone);  // returns "America/New_York"
        $('#user_time_zone').val(detected_zone);  // ! need to convert this to Rails TimeZone name !
    });
    </script>
_

ユーザーモデル

_    validates_inclusion_of :time_zone, in: ActiveSupport::TimeZone.zones_map(&:name)
_

ユーザーアカウント設定フォーム

_    <%= f.label :time_zone, label: "Time Zone" %><br />
    <%= f.time_zone_select :time_zone, ActiveSupport::TimeZone.us_zones %>
_
27
TheEricMiller

Temporalには必要なロジックが含まれていますが、質問に答えるには:

Time.zone = ActiveSupport::TimeZone.new("America/New_York")

編集、私は私の答えが不完全だと思います。 「America/New_York」から「EasternTime(US&Canada)」に変更しますか?その場合、これが私が持っている最善の解決策です-誰かがより良いものを提供できるかもしれませんが。

ActiveSupport::TimeZone::MAPPING.select {|k, v| v == "America/New_York" }.keys.first

24
jejacks0n

@ajbrausが提起した問題を解決するために、誰もが本当に求めていると私が信じている魔法は、どこでも議論されているのを見つけるのが奇妙に難しいものの1つである可能性があるワンライナーです。

timezone = ActiveSupport::TimeZone[TZInfo::Timezone.get('America/Vancouver').period_for_utc(Time.now.utc).utc_offset]
 => #<ActiveSupport::TimeZone:0x00007fc2baa6d900 @name="Pacific Time (US & Canada)", @utc_offset=nil, @tzinfo=#<TZInfo::TimezoneProxy: America/Los_Angeles>> 

それ以外の場合、ActiveSupportのゾーンのDB全体を検索しようとすると、次のようになります。

ActiveSupport::TimeZone.all.find{ |tz| tz.tzinfo == ActiveSupport::TimeZone.find_tzinfo('America/Vancouver') }
 => nil

複雑さは次のように要約されます。

  • TZInfo gemは、IANAのタイムゾーン仕様に厳密に準拠しています。
  • RailsのActiveSupportは、ゾーンの表示/使用を簡素化することを決定しましたが、ゾーンの完全なDBではありません
  • ActiveSupportは、オフセットを指定すると、適切なゾーンを検索できます
  • 対象のゾーンにTZInfo :: TimezonePeriodを作成しない限り、TZInfoはオフセットを提供しません
  • Ruby 2.6は、このビジネスをクリーンアップするためにタイムゾーンのサポートを再検討しているようです。
1
agranov