Bagaimana Anda mengonversi antara objek DateTime dan Waktu di Ruby?
Bagaimana Anda mengonversi antara objek DateTime dan Waktu di Ruby?
Jawaban:
Anda akan membutuhkan dua konversi yang sedikit berbeda.
Untuk mengonversi dari Time
ke DateTime
Anda dapat mengubah kelas Waktu sebagai berikut:
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
Penyesuaian serupa dengan Tanggal akan memungkinkan Anda mengonversi DateTime
ke 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
Perhatikan bahwa Anda harus memilih antara waktu setempat dan waktu GM / UTC.
Cuplikan kode di atas diambil dari Ruby Cookbook O'Reilly . Kebijakan penggunaan kembali kode mereka memungkinkan ini.
require 'time'
require 'date'
t = Time.now
d = DateTime.now
dd = DateTime.parse(t.to_s)
tt = Time.parse(d.to_s)
Sebagai pembaruan ke keadaan ekosistem Ruby Date
,, DateTime
dan Time
sekarang memiliki metode untuk mengkonversi antara berbagai kelas. Menggunakan 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
Sayangnya, DateTime.to_time, Time.to_datetime
dan Time.parse
fungsi tidak menyimpan info zona waktu. Semuanya dikonversi ke zona waktu lokal selama konversi. Date arithmetics masih berfungsi tetapi Anda tidak akan dapat menampilkan tanggal dengan zona waktu aslinya. Informasi konteks itu seringkali penting. Misalnya, jika saya ingin melihat transaksi dilakukan selama jam kerja di New York, saya mungkin lebih suka melihatnya ditampilkan dalam zona waktu semula, bukan zona waktu lokal saya di Australia (yang 12 jam lebih cepat dari New York).
Metode konversi di bawah ini menyimpan info tz itu.
Untuk Ruby 1.8, lihat jawaban Gordon Wilson . Ini dari Ruby Cookbook andal tua yang andal.
Untuk Ruby 1.9, ini sedikit lebih mudah.
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
Ini mencetak yang berikut ini
2010-01-01T10:00:00-02:00
2010-01-01 10:00:00 -0200
2010-01-01T10:00:00-02:00
Info DateTime asli lengkap termasuk zona waktu disimpan.
Time#to_datetime
tampaknya melestarikan tz untuk saya:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Memperbaiki solusi Gordon Wilson, ini adalah percobaan saya:
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
Anda akan mendapatkan waktu yang sama di UTC, kehilangan zona waktu (sayangnya)
Juga, jika Anda memiliki ruby 1.9, coba saja to_time
metode ini
Saat melakukan konversi seperti itu, seseorang harus mempertimbangkan perilaku zona waktu saat mengkonversi dari satu objek ke objek lainnya. Saya menemukan beberapa catatan dan contoh yang bagus di posting stackoverflow ini .