2008-12-09 29 views
30

Rails' ActiveSupport module extends the builtin ruby Time class with a number of methods.Rails ActiveSupport Time Parsing?

Đáng chú ý, có to_formatted_s phương pháp, cho phép bạn viết Time.now.to_formatted_s(:db) để có được một chuỗi ở định dạng cơ sở dữ liệu, thay vì phải viết xấu xí strftime định dạng chuỗi ở khắp mọi nơi.

Câu hỏi của tôi là, có cách nào để đi ngược lại không?

Thứ gì đó như Time.parse_formatted_s(:db) sẽ phân tích chuỗi trong định dạng Cơ sở dữ liệu, trả về đối tượng Thời gian mới. Điều này có vẻ như một cái gì đó mà đường ray nên được cung cấp, nhưng nếu có, tôi không thể tìm thấy nó.

Tôi không thể tìm thấy nó hay tôi có cần tự viết không?

Cảm ơn

Trả lời

55

Dường như ActiveSupport không cung cấp các phương pháp phân tích cú pháp bạn đang tìm kiếm (và tôi đang tìm kiếm quá), sau khi tất cả! — ít nhất là nếu chuỗi bạn đang cố phân tích là định dạng tiêu chuẩn, định dạng ISO-8601 (:db).

Nếu ngày bạn đang cố gắng phân tích đã có trong múi giờ địa phương của bạn, nó thực sự dễ dàng!

> 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 

và rằng thời gian múi giờ-aware có thể sau đó dễ dàng được chuyển đổi sang UTC

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

hoặc để múi giờ khác:

> 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 

Nếu chuỗi ngày mà bạn đang cố gắng để phân tích cú pháp là trong UTC, mặt khác, nó không giống như có bất kỳ phương pháp nào để phân tích cú pháp nó trực tiếp vào một TimeWithZone, nhưng tôi đã có thể làm việc xung quanh đó là lần đầu tiên sử dụng Da teTime.strptime ...

Nếu ngày bạn đang cố gắng để phân tích là trong UTC và bạn muốn nó ở lại như UTC, bạn có thể sử dụng:

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

Nếu ngày bạn đang cố gắng phân tích cú pháp là trong UTC và bạn muốn nó chuyển sang múi giờ mặc định của bạn, bạn có thể sử dụng:

> 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 

Dường như nó thậm chí có thể phân tích các định dạng khác, chẳng hạn như là định dạng lạ mà Time # to_s sản xuất:

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" 

Tôi khá ấn tượng.

Dưới đây là một số ví dụ khác từ [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 

Thêm liên kết tài liệu để tham khảo:

+0

Cảm ơn bạn đã đăng rất nhiều chi tiết. Tham chiếu DateTime.strptime() của bạn rất hữu ích cho trường hợp tôi cần phân tích một ngày trong cơ sở dữ liệu mà ActiveRecord :: Base.connection.select_value() trả về dưới dạng một chuỗi. – Lee

+0

Câu trả lời của kẻ giết người. Tôi đã không nhận ra Time.zone = "..." đã hoạt động. Bạn vừa cứu tôi rất nhiều thời gian. – rhh

+2

Cảm ơn bạn đã trả lời! Nếu bạn không muốn thay đổi TZ toàn cầu, bạn có thể sử dụng Time :: use_zone, vd. để phân tích cú pháp UTC, hãy sử dụng Time.use_zone ('UTC') {Time.zone.parse '2012-11-01 13:37'}. – Divide

1
>> "2009-09-24".to_date 
=> Thu, 24 Sep 2009 
>> "9/24/2009".to_date 
=> Thu, 24 Sep 2009 

Hoạt động tốt trừ khi ngày của bạn ở định dạng lạ.

+0

"một số định dạng lạ" - như một ngày được định dạng như phần còn lại của thế giới hiện nó? :) –

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

Tôi cũng đã tham gia vào vấn đề này và không có câu trả lời nào ở trên thỏa mãn với tôi. Lý tưởng nhất, người dùng có thể sử dụng ActiveSupport::TimeZone giống như Time và gọi .strptime trên đó với bất kỳ định dạng tùy ý nào và lấy lại đối tượng TimeZone chính xác. ActiveSupport::TimeZone.strptime không tồn tại vì vậy tôi tạo monkeypatch này:

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 
3

Rails 5 cuối cùng cung cấp 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 
Các vấn đề liên quan