Comment convertir un objet DateTime et Time en Ruby?
Vous aurez besoin de deux conversions légèrement différentes.
Pour convertir de Time
à DateTime
, vous pouvez modifier la classe Time comme suit:
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
Des ajustements similaires à Date vous permettront de convertir DateTime
en 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
Notez que vous devez choisir entre l'heure locale et l'heure GM/UTC.
Les deux extraits de code ci-dessus proviennent de O'Reilly Ruby Cookbook . Leur réutilisation de code politique le permet.
require 'time'
require 'date'
t = Time.now
d = DateTime.now
dd = DateTime.parse(t.to_s)
tt = Time.parse(d.to_s)
En tant que mise à jour de l'état de l'écosystème Ruby, Date
, DateTime
et Time
, il existe maintenant des méthodes de conversion entre les différentes classes. Utilisation de 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
Malheureusement, les fonctions DateTime.to_time, Time.to_datetime
Et Time.parse
Ne conservent pas les informations de fuseau horaire. Tout est converti en fuseau horaire local lors de la conversion. L'arithmétique des dates fonctionne toujours, mais vous ne pourrez pas afficher les dates avec leurs fuseaux horaires d'origine. Cette information de contexte est souvent importante. Par exemple, si je souhaite voir des transactions effectuées pendant les heures de bureau à New York, je préfère probablement les voir affichées dans leur fuseau horaire d'origine, et non dans mon fuseau horaire local en Australie (qui compte 12 heures d'avance sur New York).
Les méthodes de conversion ci-dessous conservent cette information tz.
Pour Ruby 1.8, regardez réponse de Gordon Wilson . C'est du bon vieux fiable Ruby Cookbook.
Pour Ruby 1.9, c'est légèrement plus facile.
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
Ceci imprime ce qui suit
2010-01-01T10:00:00-02:00
2010-01-01 10:00:00 -0200
2010-01-01T10:00:00-02:00
Les informations DateTime d'origine complètes, y compris le fuseau horaire, sont conservées.
Pour améliorer la solution Gordon Wilson, voici mon essai:
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
Vous obtiendrez le même temps en UTC, en perdant le fuseau horaire (malheureusement)
En outre, si vous avez Ruby 1.9, essayez simplement le to_time
méthode