Làm thế nào để bạn chuyển đổi giữa một đối tượng DateTime và Time trong Ruby?
Làm thế nào để bạn chuyển đổi giữa một đối tượng DateTime và Time trong Ruby?
Câu trả lời:
Bạn sẽ cần hai chuyển đổi hơi khác nhau.
Để chuyển đổi từ Time
sang DateTime
bạn có thể sửa đổi lớp Thời gian như sau:
require 'date'
class Time
def to_datetime
# Convert seconds + microseconds into a fractional number of seconds
seconds = sec + Rational(usec, 10**6)
# Convert a UTC offset measured in minutes to one measured in a
# fraction of a day.
offset = Rational(utc_offset, 60 * 60 * 24)
DateTime.new(year, month, day, hour, min, seconds, offset)
end
end
Điều chỉnh tương tự với Ngày sẽ cho phép bạn chuyển đổi DateTime
sang Time
.
class Date
def to_gm_time
to_time(new_offset, :gm)
end
def to_local_time
to_time(new_offset(DateTime.now.offset-offset), :local)
end
private
def to_time(dest, method)
#Convert a fraction of a day to a number of microseconds
usec = (dest.sec_fraction * 60 * 60 * 24 * (10**6)).to_i
Time.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min,
dest.sec, usec)
end
end
Lưu ý rằng bạn phải chọn giữa giờ địa phương và giờ GM / UTC.
Cả hai đoạn mã trên được lấy từ Ruby Cookbook của O'Reilly . Chính sách tái sử dụng mã của họ cho phép điều này.
require 'time'
require 'date'
t = Time.now
d = DateTime.now
dd = DateTime.parse(t.to_s)
tt = Time.parse(d.to_s)
Là một bản cập nhật cho trạng thái của hệ sinh thái Ruby Date
, DateTime
và Time
hiện có các phương thức để chuyển đổi giữa các lớp khác nhau. Sử dụng Ruby 1.9.2+:
pry
[1] pry(main)> ts = 'Jan 1, 2000 12:01:01'
=> "Jan 1, 2000 12:01:01"
[2] pry(main)> require 'time'
=> true
[3] pry(main)> require 'date'
=> true
[4] pry(main)> ds = Date.parse(ts)
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[5] pry(main)> ds.to_date
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[6] pry(main)> ds.to_datetime
=> #<DateTime: 2000-01-01T00:00:00+00:00 (4903089/2,0,2299161)>
[7] pry(main)> ds.to_time
=> 2000-01-01 00:00:00 -0700
[8] pry(main)> ds.to_time.class
=> Time
[9] pry(main)> ds.to_datetime.class
=> DateTime
[10] pry(main)> ts = Time.parse(ts)
=> 2000-01-01 12:01:01 -0700
[11] pry(main)> ts.class
=> Time
[12] pry(main)> ts.to_date
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[13] pry(main)> ts.to_date.class
=> Date
[14] pry(main)> ts.to_datetime
=> #<DateTime: 2000-01-01T12:01:01-07:00 (211813513261/86400,-7/24,2299161)>
[15] pry(main)> ts.to_datetime.class
=> DateTime
1.9.3p327 :007 > ts = '2000-01-01 12:01:01 -0700' => "2000-01-01 12:01:01 -0700" 1.9.3p327 :009 > dt = ts.to_datetime => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :010 > dt.to_time => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :011 > dt.to_time.class => DateTime
Thật không may, các chức năng DateTime.to_time, Time.to_datetime
và Time.parse
không giữ lại thông tin múi giờ. Tất cả mọi thứ được chuyển đổi thành múi giờ địa phương trong quá trình chuyển đổi. Mỹ phẩm ngày vẫn hoạt động nhưng bạn sẽ không thể hiển thị ngày với múi giờ ban đầu của chúng. Thông tin bối cảnh đó thường rất quan trọng. Ví dụ: nếu tôi muốn xem các giao dịch được thực hiện trong giờ làm việc ở New York, tôi có thể thích thấy chúng được hiển thị trong các múi giờ ban đầu của chúng, chứ không phải múi giờ địa phương của tôi ở Úc (trước 12 giờ so với New York).
Các phương thức chuyển đổi dưới đây giữ thông tin tz đó.
Đối với Ruby 1.8, hãy xem câu trả lời của Gordon Wilson . Đó là từ Ruby Cookbook cũ đáng tin cậy.
Đối với Ruby 1.9, nó dễ dàng hơn một chút.
require 'date'
# Create a date in some foreign time zone (middle of the Atlantic)
d = DateTime.new(2010,01,01, 10,00,00, Rational(-2, 24))
puts d
# Convert DateTime to Time, keeping the original timezone
t = Time.new(d.year, d.month, d.day, d.hour, d.min, d.sec, d.zone)
puts t
# Convert Time to DateTime, keeping the original timezone
d = DateTime.new(t.year, t.month, t.day, t.hour, t.min, t.sec, Rational(t.gmt_offset / 3600, 24))
puts d
Điều này in như sau
2010-01-01T10:00:00-02:00
2010-01-01 10:00:00 -0200
2010-01-01T10:00:00-02:00
Thông tin DateTime gốc đầy đủ bao gồm cả múi giờ được lưu giữ.
Time#to_datetime
xuất hiện để bảo vệ tz cho tôi:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Cải thiện giải pháp Gordon Wilson, đây là thử của tôi:
def to_time
#Convert a fraction of a day to a number of microseconds
usec = (sec_fraction * 60 * 60 * 24 * (10**6)).to_i
t = Time.gm(year, month, day, hour, min, sec, usec)
t - offset.abs.div(SECONDS_IN_DAY)
end
Bạn sẽ nhận được cùng một thời gian trong UTC, mất múi giờ (không may)
Ngoài ra, nếu bạn có ruby 1.9, chỉ cần thử to_time
phương pháp