Saya tidak yakin apakah ini harus menjadi pertanyaan yang terpisah, tetapi bagaimana Anda mengonversi antara Tanggal dan Waktu?
Andrew Grimm
8
Jawaban yang diterima dan diberi nilai tertinggi tidak lagi paling akurat di bawah Ruby versi modern. Lihat jawaban oleh @theTinMan dan oleh @PatrickMcKenzie di bawah ini.
Phrogz
Jawaban:
50
Anda akan membutuhkan dua konversi yang sedikit berbeda.
Untuk mengonversi dari Time ke DateTimeAnda dapat mengubah kelas Waktu sebagai berikut:
require 'date'classTimedef 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)endend
Penyesuaian serupa dengan Tanggal akan memungkinkan Anda mengonversi DateTime ke Time .
classDatedef to_gm_time
to_time(new_offset,:gm)enddef 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)endend
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.
Ini akan berhenti pada 1.9 di mana DateTime # sec_fraction mengembalikan jumlah milidetik dalam satu detik. Untuk 1.9, Anda ingin menggunakan: usec = dest.sec_fraction * 10 ** 6
dkubb
185
require 'time'
require 'date'
t =Time.now
d =DateTime.now
dd =DateTime.parse(t.to_s)
tt =Time.parse(d.to_s)
+1 Ini mungkin bukan yang paling efisien dalam eksekusi, tetapi berfungsi, ringkas, dan sangat mudah dibaca.
Walt Jones
6
Sayangnya ini hanya benar-benar berfungsi ketika berhadapan dengan waktu setempat. Jika Anda mulai dengan DateTime atau Waktu dengan zona waktu yang berbeda, fungsi parse akan dikonversi menjadi zona waktu lokal. Anda pada dasarnya kehilangan zona waktu asli.
Bernard
6
Mulai dari ruby 1.9.1, DateTime.parse memang mempertahankan zona waktu. (Saya tidak memiliki akses ke versi sebelumnya.) Time.parse tidak mempertahankan zona waktu, karena itu mewakili time_t POSIX-standard, yang saya percaya adalah perbedaan bilangan bulat dari zaman. Setiap konversi ke Waktu harus memiliki perilaku yang sama.
anshul
1
Kamu benar. DateTime.parse bekerja di 1.9.1 tetapi tidak Time.parse. Bagaimanapun, ini lebih rentan kesalahan (konsisten) dan lebih cepat menggunakan DateTime.new (...) dan Time.new (..). Lihat jawaban saya untuk kode sampel.
Bernard
1
Hai @anshul. Saya tidak menyiratkan bahwa saya menyatakan :-). Info zona waktu tidak disimpan saat menggunakan Time.parse (). Mudah untuk diuji. Dalam kode Anda di atas, cukup ganti d = DateTime.now dengan d = DateTime.new (2010,01,01, 10,00,00, Rasional (-2, 24)). Sekarang akan menunjukkan tanggal d dikonversi ke zona waktu lokal Anda. Anda masih dapat melakukan aritmatika tanggal dan semua kecuali info asli hilang. Info ini adalah konteks untuk tanggal dan seringkali penting. Lihat di sini: stackoverflow.com/questions/279769/…
Bernard
63
Sebagai pembaruan ke keadaan ekosistem Ruby Date,, DateTimedan Timesekarang memiliki metode untuk mengkonversi antara berbagai kelas. Menggunakan Ruby 1.9.2+:
Ups. Baru menyadari bahwa ini adalah masalah Ruby on Rails bukan masalah Ruby: stackoverflow.com/questions/11277454/… . Mereka bahkan memiliki bug yang diajukan terhadap metode ini di baris 2.x dan menandainya "tidak akan memperbaiki". IMHO keputusan yang mengerikan. Perilaku Rails benar-benar merusak antarmuka Ruby yang mendasarinya.
Jesse Clark
12
Sayangnya, DateTime.to_time, Time.to_datetimedan Time.parsefungsi 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
Waktu memang rumit, tetapi tidak ada alasan untuk tidak menyediakan konversi bawaan antara berbagai kelas waktu bawaan. Anda bisa melempar RangeException jika Anda mencoba untuk mendapatkan time_t UNIX untuk 4713 SM (meskipun nilai negatif BigNum akan lebih baik), tetapi setidaknya memberikan metode untuk itu.
Mark Reed
1
Time#to_datetimetampaknya melestarikan tz untuk saya:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Phrogz
@Phrogz UTC offset tidak sama dengan zona waktu. Satu konstan, yang lain dapat berubah pada waktu yang berbeda tahun untuk menghemat waktu siang hari. DateTime tidak memiliki zona, ia mengabaikan DST. Waktu menghormatinya, tetapi hanya di TZ "lokal" (lingkungan sistem).
Andrew Vit
1
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_timemetode 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 .
Jawaban:
Anda akan membutuhkan dua konversi yang sedikit berbeda.
Untuk mengonversi dari
Time
keDateTime
Anda dapat mengubah kelas Waktu sebagai berikut:Penyesuaian serupa dengan Tanggal akan memungkinkan Anda mengonversi
DateTime
keTime
.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.
sumber
sumber
Sebagai pembaruan ke keadaan ekosistem Ruby
Date
,,DateTime
danTime
sekarang memiliki metode untuk mengkonversi antara berbagai kelas. Menggunakan Ruby 1.9.2+:sumber
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
danTime.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.
Ini mencetak yang berikut ini
Info DateTime asli lengkap termasuk zona waktu disimpan.
sumber
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:
Anda akan mendapatkan waktu yang sama di UTC, kehilangan zona waktu (sayangnya)
Juga, jika Anda memiliki ruby 1.9, coba saja
to_time
metode inisumber
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 .
sumber