2016-04-11 12 views
2

Iは、任意時間帯成分と、それが有効なISO 8601時間である検証をユーザ入力のタイムスタンプを受信し、ユーザの設定した時間帯に応じてそれを解析できるようにする必要があります。ISO 8601タイムスタンプをユーザーのタイムゾーンで検証して解析するにはどうすればよいですか?

私は、Ruby 2.3の上のRails 4.2.6を使用しています。私は、ユーザー入力が有効なISO 8601時刻の表現であるかどうかを決定するためにArgumentError例外を救うことができるようにTime.zoneActiveSupport::TimeZone)はTime::iso8601と同等の実装を持っているだろうと期待していました。それから、私は次のようなことをすることができます:

user_time_zone = 'America/Los_Angeles' # Would actually be from user's stored settings 
params = {when: '2016-04-01T01:01:01'} # Would actually be from user input 

# Would actually use Time::use_zone in around_action filter 
Time.use_zone(user_time_zone) do 
    timestamp = Time.zone.iso8601 params[:when] 
end 

しかし、まあ、そのような方法はありません。そして私は同等のものを見つけることができません。

あいまいな日付を有効として扱うため、Time.zone.parseは使用できません(例:Time.zone.parse '04/11/16' # => Tue, 16 Nov 0004 00:00:00 LMT -07:52)。

Time.use_zone(user_time_zone) do 
    old_tz = ENV['TZ'] 
    ENV['TZ'] = Time.zone.name 
    timestamp = Time.iso8601 params[:when] # => 2016-04-01 01:01:01 -0700 
    ENV['TZ'] = old_tz 
end 

しかし、これはこの方法が正しい感じていない環境変数をいじり、醜いであり、それと確かに:

私がこれまでに出てくることができました最善の選択肢でありますRailsのようなものではありません。 Railsの方法でユーザーのタイムゾーンに応じて時刻を検証して解析するにはどうすればよいですか?

答えて

4

私はあなたは、単に2つのステップに割り当てを分割することを示唆している:最初のISO8601形式を検証し、有効であれば、それを解析:この検証を行うか、ISO 8601のタイムスタンプを解析する方法

user_time_zone = 'America/Los_Angeles' 
params = { when: '2016-04-01T01:01:01' } 

begin 
    Time.iso8601(params[:when])  # raises ArgumentError if format invalid 
rescue ArgumentError => e 
    puts "invalid time format" 
    return 
end 

Time.use_zone(user_time_zone) do 
    timestamp = Time.zone.parse(params[:when]) 
end 
+0

//github.com/mojombo/chronic実際には、あなたのオリジナルのリビジョンは正しかったです。タイムゾーンは、時間を解析するときに考慮され、ユーザーのタイムゾーン設定に従って表示されますが、これは正しいです。異なるタイムゾーンで出力する必要がある場合は、#in_time_zoneを使用できます。正規表現を使用して2つのケースを区別しようとすると、エラーが発生しやすくなります(タイムスタンプが '2016-04-01T01:01:01Z'の場合など)。 – depquid

+0

ああ、ありがとう、あなたは絶対に正しいです!私は答えをあまりに多く急いで、私のテストに十分注意を払わなかった。私は正規表現が理想的ではなく、必要でないとうれしいと同意する。答えの間違った部分を削除しました。 – BoraMa

+0

優秀、これは私が必要としたものです。唯一の他の思考は 'begin..rescue'は、無効なタイムゾーンがTime.use_zone''に渡される場合など、他の 'ArgumentError's、区別するためにTime.iso8601''へのコールを中心に、より緊密に包むべきであるということです。 – depquid

-1

私はあなたがまだあなたのユースケースのためaround_actionを使用することができると思います。それは私が使用するものであり、それは私のためにうまくいく。私ApplicationController

私が持っている:Time

class ApplicationController < ActionController::Base 
    around_action :set_time_zone 

    def set_time_zone 
    old_time_zone = Time.zone 
    Time.zone = user_time_zone 
    yield 
    ensure 
    Time.zone = old_time_zone 
    end 
end 

任意のコールは、リクエストの範囲内で、ユーザーのタイムゾーンを使用します。

+0

? – depquid

+0

お詫び申し上げます、私はあなたが*いつ*どうやって*求めていると思った。私は慢性ライブラリーをチェックアウトします。それは非常に柔軟であり、あなたがneed.https何で動作することがあります。 – JackCollins

関連する問題