web-dev-qa-db-ja.com

Rails ActiveSupport Time Parsing?

RailsのActiveSupportモジュールは組み込みを拡張しますRuby Timeクラスに多数のメソッドがあります。

特に、_to_formatted_s_メソッドがあります。このメソッドを使用すると、どこにでも醜いstrftime形式文字列を記述する必要がなく、Time.now.to_formatted_s(:db)を記述してデータベース形式の文字列を取得できます。

私の質問は、後退する方法はありますか?

Time.parse_formatted_s(:db)のようなもので、データベース形式の文字列を解析し、新しいTimeオブジェクトを返します。これはRailsが提供する必要があるもののようですが、提供されている場合は見つかりません。

私はそれを見つけることができませんか、それとも自分で書く必要がありますか?

ありがとう

30
Orion Edwards

結局、ActiveSupportはあなたが探している(そして私も探していた)解析メソッドを提供しているようです。 —少なくとも、解析しようとしている文字列が標準のISO-8601形式(:db形式)日付。

解析しようとしている日付がすでにローカルタイムゾーンにある場合、それは非常に簡単です。

 > Time.zone.parse('2009-09-24 08:28:43')
=> Thu, 24 Sep 2009 08:28:43 PDT -07:00

 > Time.zone.parse('2009-09-24 08:28:43').class
=> ActiveSupport::TimeWithZone

そして、そのタイムゾーン対応の時刻を簡単にUTCに変換できます

 > Time.zone.parse('2009-09-24 08:28:43').utc
=> 2009-09-24 15:28:43 UTC

または他のタイムゾーン:

 > ActiveSupport::TimeZone.us_zones.map(&:name)
=> ["Hawaii", "Alaska", "Pacific Time (US & Canada)", "Arizona", "Mountain Time (US & Canada)", "Central Time (US & Canada)", "Eastern Time (US & Canada)", "Indiana (East)"]

 > Time.zone.parse('2009-09-24 08:28:43').utc.in_time_zone('Eastern Time (US & Canada)')
=> Thu, 24 Sep 2009 11:28:43 EDT -04:00

一方、解析しようとしている日付文字列がUTCである場合、それを解析する方法はないようです直接 TimeWithZoneに変更しましたが、最初にDateTime.strptimeを使用することで回避できました...

解析しようとしている日付がUTCであり、それをUTCのままにしたい場合は、以下を使用できます。

 > DateTime.strptime('2009-09-24 08:28:43', '%Y-%m-%d %H:%M:%S').to_time
=> 2009-09-24 08:28:43 UTC

解析しようとしている日付がUTCであり、それをデフォルトのタイムゾーンに変換したい場合は、以下を使用できます。

 > DateTime.strptime('2009-09-24 08:28:43', '%Y-%m-%d %H:%M:%S').to_time.in_time_zone
=> Thu, 24 Sep 2009 01:28:43 PDT -07:00

Time#to_sが生成する奇妙な形式など、他の形式も解析できるようです。

irb -> Time.zone.parse('Wed, 23 Sep 2009 02:18:08').to_s(:db)
    => "2009-09-23 09:18:08"

irb -> Time.zone.parse('Wed, 23 Sep 2009 02:18:08 EDT').to_s(:db)
    => "2009-09-23 06:18:08"

とても感動しました。

[ http://api.rubyonrails.org/classes/ActiveSupport/TimeWithZone.html] [1] のいくつかの例を次に示します。

  Time.zone = 'Eastern Time (US & Canada)'        # => 'Eastern Time (US & Canada)'
  Time.zone.local(2007, 2, 10, 15, 30, 45)        # => Sat, 10 Feb 2007 15:30:45 EST -05:00
  Time.zone.parse('2007-02-10 15:30:45')          # => Sat, 10 Feb 2007 15:30:45 EST -05:00
  Time.zone.at(1170361845)                        # => Sat, 10 Feb 2007 15:30:45 EST -05:00
  Time.zone.now                                   # => Sun, 18 May 2008 13:07:55 EDT -04:00
  Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone  # => Sat, 10 Feb 2007 15:30:45 EST -05:00

参照用のその他のドキュメントリンク:

56
Tyler Rick
ActiveSupport::TimeZone.new('UTC').parse('2009-09-23 09:18:08')
=> Wed, 23 Sep 2009 09:18:08 UTC +00:00
5
Leventix

Rails 5はついにstrptimeを提供します!

value = '1999-12-31 14:00:00'
format = '%Y-%m-%d %H:%M:%S'
Time.zone.strptime(value, format)
# => Fri, 31 Dec 1999 14:00:00 HST -10:00

ActiveSupport::TimeZone.all.sample.strptime(value, format)
# => Fri, 31 Dec 1999 14:00:00 GST +04:00
3
vemv

私もこれに遭遇し、上記の答えはどれも満足のいくものではありませんでした。理想的には、Timeと同じようにActiveSupport::TimeZoneを使用し、任意の形式で.strptimeを呼び出して、正しいTimeZoneオブジェクトを取得できます。 ActiveSupport::TimeZone.strptimeは存在しないため、このモンキーパッチを作成しました。

 class ActiveSupport::TimeZone
    def strptime(str, fmt, now = self.now)
      date_parts = Date._strptime(str, fmt)
      return if date_parts.blank?
      time = Time.strptime(str, fmt, now) rescue DateTime.strptime(str, fmt, now)
      if date_parts[:offset].nil?
        ActiveSupport::TimeWithZone.new(nil, self, time)
      else
        time.in_time_zone(self)
      end
    end
  end
2
Ben Mabey
>> "2009-09-24".to_date
=> Thu, 24 Sep 2009
>> "9/24/2009".to_date
=> Thu, 24 Sep 2009

日付が奇妙な形式でない限り、うまく機能します。

1
eremite