web-dev-qa-db-ja.com

タイムゾーンでのStrptime

_DateTime.strptime_で解析する文字列があります。文字列内の日付のタイムゾーンはCETですが、Rubyは、もちろん2時間のオフセットを持つUTCDateTimeオブジェクトを作成します。

現在、私はDateTime.strptime().change(:offset => "+0020")の問題を回避していますが、これが意図したとおりの方法ではないと確信しています。

誰かがこれを行う正しい方法について私に教えてもらえますか?

20
Nicolas

私はそれを次のように使用します:

Ruby-1.9.2-head :001 > require 'date'
 => true 
Ruby-1.9.2-head :002 > fmt = "%m-%d-%Y %H:%M:%S %Z"
 => "%m-%d-%Y %H:%M:%S %Z" 
Ruby-1.9.2-head :003 > DateTime.strptime "10-26-2011 10:16:29 CET", fmt
 => #<DateTime: 2011-10-26T10:16:29+01:00 (212186380589/86400,1/24,2299161)> 
Ruby-1.9.2-head :004 > DateTime.strptime "10-26-2011 10:16:29 UTC", fmt
 => #<DateTime: 2011-10-26T10:16:29+00:00 (212186384189/86400,0/1,2299161)> 
Ruby-1.9.2-head :005 > DateTime.strptime "10-26-2011 10:16:29 PST", fmt
 => #<DateTime: 2011-10-26T10:16:29-08:00 (212186412989/86400,-1/3,2299161)> 

それはどういう意味ですか?

11
WarHog

これはRails 5:

Time.zone.strptime("2017-05-20 18:20:10", "%Y-%m-%d %H:%M:%S")

指定されたタイムゾーンの時間を返します。

4
avergin

少なくともRails 4.2(おそらく以前、テストされていません)の時点では、Time#strptimeの代わりにDateTime.strptimeを使用している限り、現在のタイムゾーンが自動的に適用されます。

> DateTime.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> Wed, 28 Dec 2016 17:00:00 +0000

> Time.strptime('12/28/2016 5:00 PM', '%m/%d/%Y %H:%M %p')
=> 2016-12-28 17:00:00 -0800
4
Jared

私はこの文字列を「strptiming」していました:

_19/05/2014 8:13:26 a.m.
_

私の場合、ローカルタイムスタンプはAuckland NZで、文字列にタイムゾーンスタンプがありません。

_Time.strptime_はサーバーのタイムゾーンをベースとして使用していることがわかります。

私の状況と一般的なグッドプラクティスでは、サーバーはUTCタイムゾーンで実行されるため、文字列を解析するたびに、+ 0000(UTC)までの時間オブジェクトが作成されます。

_2014-05-19 08:13:26 +0000
_

次に、in_time_zone(Time.zone)に変換すると次のようになります。

_Mon, 19 May 2014 20:13:26 NZST +12:00
_

ご覧のとおり、実際の時間より12時間(UTCオフセット)遅れています。

上記のように_+' Auckland', '...%Z'_トリックを変更せずに使用しようとしました。次に、上記の_+ '+1200', '...%Z'_トリックを使用しました。これは正しく機能しました。

しかし、私は夏の時間を心配していました、そしてそれから解析は1時間で終わるでしょう、それでこれは私が仕上げたものです:

_Time.strptime(call_data[:datetime].gsub(/\./, "").gsub(/am/, "AM").gsub(/pm/, "PM") + (Time.zone.now.time_zone.utc_offset/3600).to_s.ljust(4,'0').rjust(6,' +'), '%d/%m/%Y %I:%M:%S %p %Z').in_time_zone(Time.zone)
_

結果:

_Mon, 19 May 2014 08:13:26 NZST +12:00
_

それは特にエレガントではありませんが、機能します。

1
Gordon

Pre Rails 5の場合、以下が機能します。

t0 = Time.strptime("2018-05-01", "%Y-%m-%d") # Or whatever
t1 = Time.zone.now.change(year: t0.year, month: t0.month, day: t0.day, hour: t0.hour, min: t0.min, sec: t0.sec, usec: t0.usec)
0
troelskn

to_time_in_current_zoneを使用して日付をタイムゾーンに変換できます。例えば:

Date.strptime('04/07/1988', '%m/%d/%Y').to_time_in_current_zone
0
Mikhail K.

私は、フォームから日付文字列を解析し、サーバーの時間とは関係なく保存しようとして、この同じ問題と戦ってきました。私が従ったプロセスはそのようなものです。 RoRとRubyタイムゾーンがUTCに設定されていることを確認します。サーバーがUTC時間にある場合も、簡単になります。

US/EasternのようなActiveSupport:TimeZone形式を使用してユーザーロケールを保存しています。タイムゾーンまたはオフセットをネイティブに含まない日付文字列を説明できる日付解釈関数があります。

# date_str looks something like this `12/31/2014 6:22 PM`
# tz is a string containing an ActiveSupport::TimeZone name like `US/Eastern`
def interpret_date(date_str, tz)
  Time.use_zone tz do
    parsed_dt = DateTime.strptime(date_str, '%m/%d/%Y %H:%M %p')
    offset = parsed_dt.in_time_zone(tz).utc_offset
    parsed_dt.advance(seconds: -(offset)).in_time_zone(tz)
  end
end

もちろん、これは完璧な解決策のようには感じられませんが、機能します。正しいタイムゾーンを確保するための手順は次のとおりです。

  1. フォーマットに従って日付文字列を解析します
  2. そのタイムゾーンの時間に基づいて現在のUTCオフセットを抽出します(現地時間が東部時間のdstではないのに、解析している日付がdstにある場合は、これを行う必要があります。これにより、dstが解析されたローカルになります。時間)
  3. 時間をターゲットロケールに変換し、正しいオフセットを追加して時間をシフトできるようにします
0
PaulSCoder