web-dev-qa-db-ja.com

Rails:日時文字列を特定のタイムゾーンに解析する方法

DebianでRails 3.2およびRuby 1.9.3を使用しています。文字列の形式で日付、時刻、およびタイムゾーンを収集するアプリがありますHTMLフォーム経由で。次のようなものです。

start_date: "04-15-2010",
start_time: "10:00:00",
timezone: "Central Time (US & Canada)"

私がやりたいのは、これら3つの要素をUTCとしてデータベースに保存される単一の日付に解析することです。この場合、UTCタイムゾーンになったら開始時間に7時間を追加します。したがって、保存された時間は、受信した中央時間ではなくUTCとしてDBに格納されると、17:00になります。

私は日付を解析するためにこのようなことを試みました:

ActiveSupport::TimeZone[timezone].at DateTime.strptime("{ 2012-04-09 20:00:00 }", "{ %Y-%m-%d %H:%M:%S }").to_i

ただし、%Zを使用して結果の時間にタイムゾーンを組み込むことはできません。解析されないか、時刻が中部標準時ではなくUTCとして解釈されます。したがって、私の質問は、保存されている実際の日付/時刻の値を変更せずに、日付文字列を特定のタイムゾーンに強制する方法です。将来のタイムゾーン変換が正確になるように、文字列を解析して、正しいタイムゾーンを含む日付/時刻オブジェクトにその時点でを解析できるようにします。私はすべてを見てきたが、これを行う方法を見つけることができません。これは奇妙なことです。これは、HTMLフォームから入力された日付で一般的なことのように見えるためです。助けてくれてありがとう。

36
Matt Schwartz

%Zは、タイムゾーン名を指定する正しい方法です。以下を試しましたか?

date_and_time = '%m-%d-%Y %H:%M:%S %Z'
DateTime.strptime("04-15-2010 10:00:00 Central Time (US & Canada)",date_and_time)
18
0x4a6f4672

これを試して:

zone = "Central Time (US & Canada)"  

ActiveSupport::TimeZone[zone].parse("2013-04-03 17:47:00")
106
ryancheung

使用する - String#in_time_zone (レール4+)

個人的にはString#in_time_zone

>> '22.09.1986 10:30'.in_time_zone('Central Time (US & Canada)')
# => Mon, 22 Sep 1986 10:30:00 CDT -05:00

これは、指定されたタイムゾーンに文字列内の日付と時刻を解析します。

37
Artur Beljajev

私はついにこれを行うための汚い、しかし決定的な方法を見つけました。

最初に、プレーンRuby Time.strptimeを次のように使用して文字列を解析します。

time = Time.strptime('12 : 00 : PM', '%I : %M : %p')

この方法では、解析された時間を取得できますが、まだ正しいタイムゾーンではありません。それを修正するには、時間を文字列形式に変換し、標準のActiveSupport :: TimeZone#parseで解析しましょう

Time.zone.parse(time.to_s)

結果は、正しいタイムゾーンに解析された時間を持つActiveSupport :: TimeWithZoneです。

このようにする必要がある理由は、ActiveSupport :: TimeZoneもActiveSupport :: TimeWithZoneもstrptimeメソッドをサポートしないためです。したがって、タイムゾーン情報を持たないcore Ruby strptimeでTimeを解析し、ActiveSupportオブジェクトで受け入れ可能な形式に変換してから、再度解析する必要があります。

2
Phitherek_

これが私が思いついた方法です。最もきれいではありませんが、機能します。指定した形式を使用して文字列を解析し、Time.zone.parseが必要とすることがわかっている形式に変換できるようにします。

class ActiveSupport::TimeZone
  def strptime(time, format='%m/%d/%Y')
    formatted = Time.strptime(time, format).strftime('%Y-%m-%d %T')
    parse(formatted)
  end
end

次に、別の質問で言及されたようなことを、指定された形式で行うことができます:

zone = "Central Time (US & Canada)"  
ActiveSupport::TimeZone[zone].strptime('2013-04-03', '%Y-%m-%d')

または、すでにタイムゾーンが設定されている場合:

Time.zone = "Central Time (US & Canada)" 
Time.zone.strptime('01/13/2006')

ほとんどの場合、ユーザー入力は%m/%d/%Yのデフォルト形式を使用しているためです。これをニーズに合わせてカスタマイズするか、iso8601(%FT%T%z)と思われるDateTimeが使用するデフォルトの形式を使用できます。

1
ifightcrime

特定の日付形式をUTCに変換します。

ActiveSupport::TimeZone['UTC'].parse(Time.strptime('01/24/2019T16:10:16', "%m/%d/%YT%H:%M:%S").asctime)
0
DenisKo

DateTimeに日付文字列を取得させ、日付文字列の値を変更せずにUTC以外のタイムゾーンをアタッチするには、これを使用します。簡単で、うるう日に壊れません:)

xx = DateTime.strptime("9/1/15 #{object.time_zone}", "%m/%d/%Y %Z")
0
Jon