2010-03-25 12 views
5

Tôi cần chuyển đổi đối tượng Ngày thành đối tượng TimeWithZone biểu thị ngày bắt đầu của ngày đó trong một múi giờ nhất định.chuyển đổi đối tượng Ngày thành TimeWithZone

Phương pháp sau đây hoạt động, nhưng dường như quá phức tạp vì nó đòi hỏi tôi phải chuyển đổi ngày đến một chuỗi:

?> date = Date.parse("2010-02-17") 
=> Wed, 17 Feb 2010 
>> ActiveSupport::TimeZone['Eastern Time (US & Canada)'].parse(date.to_s) 
=> Wed, 17 Feb 2010 00:00:00 EST -05:00 
>> ActiveSupport::TimeZone['UTC'].parse(date.to_s) 
=> Wed, 17 Feb 2010 00:00:00 UTC 00:00 

Có cách nào tốt hơn tôi là thiếu?

Edit: Mọi người đang cho thấy các biến thể của:

?> date.to_datetime.in_time_zone('Eastern Time (US & Canada)').beginning_of_day 
=> Tue, 16 Feb 2010 00:00:00 EST -05:00 

Như bạn có thể thấy, đây không phải là một chuyển đổi tương đương kể từ khi nó rời khỏi tôi khi bắt đầu ngày 16 tháng 2 EST, thay vì bắt đầu EST EST ngày 17 tháng 2.

+0

Dường như giải pháp của bạn có thể là cách đúng để đi. –

+0

Tôi đã chỉnh sửa phản hồi của mình để khắc phục sự cố này. –

+0

Tự cung cấp giải pháp! =) Thời gian với Múi giờ luôn lộn xộn. – John

Trả lời

0

Điều gì đó có thể phù hợp với bạn?

'2010-04-01'.to_time.in_time_zone('Eastern Time (US & Canada)').beginning_of_day 
+0

xem chỉnh sửa của tôi cho câu hỏi vì sao điều này không hoạt động – avaynshtok

0

Subtract utc_offset:

d = Date.today 
Time.zone.class.all.map(&:name).map { |tz| dt = d.to_datetime.in_time_zone(tz); dt -= dt.utc_offset } 

Sử dụng ActiveSupport :: TimeZone [tz] không mất nhiều thời gian tiết kiệm ánh sáng ban ngày vào tài khoản.

Time.zone.class.all.map(&:name).map { |tz| o = d.to_datetime.in_time_zone(tz).utc_offset - ActiveSupport::TimeZone[tz].utc_offset } 
4

Nếu bạn có Time.zone bộ trong Rails sau đó bạn có thể gọi Date#at_beginning_of_day (xem http://api.rubyonrails.org/classes/Date.html#method-i-at_beginning_of_day). Ngược lại điều này với Date#to_datetime:

Time.zone 
=> #<ActiveSupport::TimeZone:0x10cf10858 @tzinfo=#<TZInfo::TimezoneProxy: Etc/UTC>, @utc_offset=nil, @current_period=nil, @name="UTC"> 

date = Date.today 
=> Thu, 31 May 2012 

date.to_datetime 
=> Thu, 31 May 2012 00:00:00 +0000 

date.at_beginning_of_day 
=> Thu, 31 May 2012 00:00:00 UTC +00:00 

Time.zone = 'America/Chicago' 
=> "America/Chicago" 

date.to_datetime 
=> Thu, 31 May 2012 00:00:00 +0000 

date.at_beginning_of_day 
=> Thu, 31 May 2012 00:00:00 CDT -05:00 
+2

'Time.zone' ** là ** luồng an toàn, nó đặt vùng trong' Thread.current [: time_zone] '. [source] (https://github.com/rails/rails/blob/08754f12e65a9ec79633a605e986d0f1ffa4b251/activesupport/lib/active_support/core_ext/time/zones.rb#L39) –

+1

Cảm ơn bạn đã sửa, tôi đã xóa nhận xét đó, nhưng để lại điều này để mọi người không nghĩ rằng bạn đang điên;) – gtd

2

tôi khuyên chống lại bất kỳ giải pháp chuyển đổi ngày để một thời gian sử dụng to_datetime hoặc to_time vì các phương pháp đó là không biết gì về khu vực, và tacking in_time_zone vào kết quả, như một số câu trả lời gợi ý, sẽ không sửa lỗi một cách hồi tố. Ngoài ra, đừng cố gắng xây dựng toán thời gian tiết kiệm ánh sáng ban ngày của riêng bạn bằng cách sử dụng bù trừ UTC. Bạn đang bị ràng buộc để làm cho nó sai, và bạn đang làm công việc không cần thiết. .

Sử dụng TimeZone bản thân trong đó có logic này được xây dựng trong

Cho một khu vực và một ngày, bạn có thể có được một TimeWithZone cho sự khởi đầu của một ngày như thế này:

time = zone.local(date.year, date.month, date.day) 

Nếu bạn muốn có thời gian cụ thể trong ngày khác với ngày bắt đầu, bạn có thể chuyển giờ, phút và giây làm đối số thứ 4, thứ 5 và thứ 6 thành #local.

Nếu zone thực sự là múi giờ địa phương của hệ thống của bạn (Time.zone), sau đó ActiveSupport sẽ cho phép bạn rút ngắn ở trên để này:

time = date.to_time_in_current_zone 

Tất cả các xử lý trên tiết kiệm thời gian một cách chính xác ánh sáng ban ngày. Hãy xác minh rằng bằng cách nhìn vào offsets UTC hai lần, một trong đó là bên ngoài DST và một trong đó là trong vòng DST:

irb(main):009:0> zone = ActiveSupport::TimeZone['Eastern Time (US & Canada)'] 
=> (GMT-05:00) Eastern Time (US & Canada) 
irb(main):010:0> t1 = zone.local(2013, 1, 1) 
=> Tue, 01 Jan 2013 00:00:00 EST -05:00 
irb(main):011:0> t2 = zone.local(2013, 5, 1) 
=> Wed, 01 May 2013 00:00:00 EDT -04:00 
irb(main):012:0> t1.utc_offset 
=> -18000 
irb(main):013:0> t2.utc_offset 
=> -14400 
+0

Đã xóa câu trả lời của tôi và upvoted của bạn. –

5

Tôi muộn để đảng, nhưng đây vẫn là một câu hỏi lớn. ActiveSupport's in_time_zone được giới thiệu từ O.P., nhưng nó thực hiện chính xác những gì bạn muốn mà không cần phân tích chuỗi (chậm) hoặc cài đặt Thời gian.Vùng (rủi ro):

>> date = Date.parse("2010-02-17") 
=> Wed, 17 Feb 2010 
>> date.in_time_zone('Eastern Time (US & Canada)') 
=> Wed, 17 Feb 2010 00:00:00 EST -05:00 

Tất nhiên nếu bạn muốn đầu ngày thể hiện ở utc, bạn có thể làm điều này:

>> date.in_time_zone('Eastern Time (US & Canada)').utc 
=> 2010-02-17 05:00:00 UTC