Comment convertir un objet DateTime en un objet Time en Ruby ?
+1 Ce n'est peut-être pas le plus efficace en termes d'exécution, mais ça marche, c'est concis et c'est très lisible.
Comment convertir un objet DateTime en un objet Time en Ruby ?
+1 Ce n'est peut-être pas le plus efficace en termes d'exécution, mais ça marche, c'est concis et c'est très lisible.
Malheureusement, cela ne fonctionne vraiment que lorsqu'il s'agit d'heures locales. Si vous commencez par une DateTime ou une Time avec un fuseau horaire différent, la fonction d'analyse convertira le fuseau horaire local. En fait, vous perdez le fuseau horaire d'origine.
Depuis la version 1.9.1 de ruby, DateTime.parse préserve le fuseau horaire. (Je n'ai pas accès aux versions antérieures.) Time.parse ne préserve pas le fuseau horaire, car il représente le standard POSIX time_t, qui, je crois, est une différence entière de l'époque. Toute conversion en Time devrait avoir le même comportement.
Comme une mise à jour de l'état de l'écosystème Ruby, Date
, DateTime
y Time
ont maintenant des méthodes pour convertir 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
DateTime.to_time renvoie un 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
Oups. Je viens de réaliser que c'est un problème de Ruby on Rails, pas un problème de Ruby : stackoverflow.com/questions/11277454/ . Ils ont même déposé un bogue contre cette méthode dans la ligne 2.x et l'ont marqué "ne sera pas corrigé". Une décision horrible, selon moi. Le comportement de Rails brise totalement l'interface Ruby sous-jacente.
Vous aurez besoin de deux conversions légèrement différentes.
Pour convertir de Time
a DateTime
vous pouvez modifier la classe de temps 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
a 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 sont tirés de l'ouvrage O'Reilly's Livre de recettes Ruby . Leur réutilisation du code politique permet ça.
Ce n'est pas vraiment si difficile.
require 'date'
date_time = DateTime.now
# #<DateTime: blah>
date_time.to_time
# #<Time: blah>
time = Time.now
# #<Time: blah>
time.to_datetime
# #<DateTime: blah>
Après vous require "date"
vous obtenez toutes sortes de nouvelles méthodes sur Time
.
Malheureusement, le DateTime.to_time, Time.to_datetime
y Time.parse
Les fonctions ne conservent pas les informations relatives au 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 leur fuseau horaire d'origine. Ces informations contextuelles sont souvent importantes. Par exemple, si je veux voir les 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 a 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 tiré du bon vieux livre de recettes Ruby.
Pour Ruby 1.9, c'est un peu 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
Le résultat est le suivant
2010-01-01T10:00:00-02:00
2010-01-01 10:00:00 -0200
2010-01-01T10:00:00-02:00
Les informations complètes de l'heure de la date d'origine, y compris le fuseau horaire, sont conservées.
Le temps est compliqué, mais il n'y a aucune excuse pour ne pas fournir une conversion intégrée entre les différentes classes de temps intégrées. Vous pouvez lancer une RangeException si vous essayez d'obtenir un time_t UNIX pour 4713 BC (bien qu'une valeur négative BigNum serait plus agréable), mais fournissez au moins une méthode pour cela.
Time#to_datetime
semble préserver tz pour moi : Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
@Phrogz Le décalage UTC n'est pas la même chose que le fuseau horaire. L'un est constant, l'autre peut changer à différentes périodes de l'année pour l'heure d'été. DateTime n'a pas de zone, il ignore l'heure d'été. Time le respecte, mais uniquement dans la ZT "locale" (environnement du système).
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.
1 votes
Je ne sais pas si cela doit faire l'objet d'une question distincte, mais comment convertir une date en heure ?
10 votes
Les réponses acceptées et les mieux notées ne sont plus les plus précises sous les versions modernes de Ruby. Voir les réponses par @theTinMan y par @PatrickMcKenzie ci-dessous.