J'ai un Ruby DateTime qui est rempli à partir d'un formulaire. De plus, j'ai aussi n heures du formulaire. Je voudrais soustraire ces n heures du DateTime précédent. (Pour obtenir un intervalle de temps).
DateTime a deux méthodes "-" et "<<" pour soustraire le jour et le mois, mais pas l'heure. ( API ). Des suggestions sur la façon dont je peux faire cela?
Tu pourrais faire ça.
adjusted_datetime = (datetime_from_form.to_time - n.hours).to_datetime
Vous pouvez simplement soustraire moins d'une journée entière:
two_hours_ago = DateTime.now - (2/24.0)
Cela fonctionne pendant quelques minutes et tout le reste:
hours = 10
minutes = 5
seconds = 64
hours = DateTime.now - (hours/24.0) #<DateTime: 2015-03-11T07:27:17+02:00 ((2457093j,19637s,608393383n),+7200s,2299161j)>
minutes = DateTime.now - (minutes/1440.0) #<DateTime: 2015-03-11T17:22:17+02:00 ((2457093j,55337s,614303598n),+7200s,2299161j)>
seconds = DateTime.now - (seconds/86400.0) #<DateTime: 2015-03-11T17:26:14+02:00 ((2457093j,55574s,785701811n),+7200s,2299161j)>
Si les inexactitudes arithmétiques en virgule flottante sont un problème, vous pouvez utiliser Rational
ou un autre utilitaire arithmétique sûr.
La méthode avancée est Nice si vous voulez être plus explicite sur un comportement comme celui-ci.
adjusted = time_from_form.advance(:hours => -n)
Vous avez juste besoin d'enlever des fractions de journée.
two_hours_ago = DateTime.now - (2.0/24)
n/24.0
l'astuce ne fonctionnera pas correctement car les flottants sont finalement arrondis:
>> DateTime.parse('2009-06-04 02:00:00').step(DateTime.parse('2009-06-04 05:00:00'),1.0/24){|d| puts d}
2009-06-04T02:00:00+00:00
2009-06-04T03:00:00+00:00
2009-06-04T03:59:59+00:00
2009-06-04T04:59:59+00:00
Vous pouvez cependant utiliser la classe Rational à la place:
>> DateTime.parse('2009-06-04 02:00:00').step(DateTime.parse('2009-06-04 05:00:00'),Rational(1,24)){|d| puts d}
2009-06-04T02:00:00+00:00
2009-06-04T03:00:00+00:00
2009-06-04T04:00:00+00:00
2009-06-04T05:00:00+00:00
Si vous travaillez dans Rails, la possibilité super-intuitive suivante existe:
> Time.now - 12.hours
=> 2019-08-19 05:50:43 +0200
(Cela fonctionne également avec secondes, minutes, jours et années)
si vous utilisez uniquement Ruby, DateTime
ne peut pas le faire, mais Time
peut:
t = Time.now
t = t - (hours*60**2)
Notez que Time
stocke également les informations de date, c'est un peu étrange.
Si vous devez travailler avec DateTime
DateTime.commercial(date.year,date.month,date.day,date.hour-x,date.minute,date.second)
pourrait fonctionner, mais est moche. Le doc dit que DateTime
est immuable, donc je ne suis même pas sûr de -
et <<
[~ # ~] modifier [~ # ~] : Jetez un œil à cette question avant de décider d'utiliser l'approche J'ai décrit ici. Il semble qu'il ne soit pas recommandé de modifier le comportement d'une classe de base dans Ruby (que je peux comprendre). Alors, prenez cette réponse avec un grain de sel ...
réponse de MattW a été la première chose à laquelle j'ai pensé, mais je n'ai pas beaucoup aimé non plus.
Je suppose que vous pourriez le rendre moins laid en corrigeant DateTime
et Fixnum
pour faire ce que vous voulez:
require 'date'
# A placeholder class for holding a set number of hours.
# Used so we can know when to change the behavior
# of DateTime#-() by recognizing when hours are explicitly passed in.
class Hours
attr_reader :value
def initialize(value)
@value = value
end
end
# Patch the #-() method to handle subtracting hours
# in addition to what it normally does
class DateTime
alias old_subtract -
def -(x)
case x
when Hours; return DateTime.new(year, month, day, hour-x.value, min, sec)
else; return self.old_subtract(x)
end
end
end
# Add an #hours attribute to Fixnum that returns an Hours object.
# This is for syntactic sugar, allowing you to write "someDate - 4.hours" for example
class Fixnum
def hours
Hours.new(self)
end
end
Ensuite, vous pouvez écrire votre code comme ceci:
some_date = some_date - n.hours
où n
est le nombre d'heures dont vous souhaitez soustraire some_date
Vous n'avez pas dit quelle utilisation vous devez faire de la valeur que vous obtenez, mais qu'en est-il simplement de diviser vos heures par 24 afin de soustraire une fraction de journée?
mydatetime = DateTime.parse(formvalue)
nhoursbefore = mydatetime - n / 24.0
Si je suis autorisé à utiliser Time
au lieu de DateTime
(Il existe plusieurs façons de se traduire les unes par les autres ):
# Just remove the number of seconds from the Time object
Time.now - (6 * 60 * 60) # 6 hours ago
J'aime utiliser les assistants dans active_support. Cela le rend vraiment propre et facile à lire.
Voir l'exemple ci-dessous:
require 'active_support'
last_accessed = 2.hours.ago
last_accessed = 2.weeks.ago
last_accessed = 1.days.ago
Il pourrait y avoir un moyen d'utiliser ce type de syntaxe pour faire ce que vous cherchez, si la date actuelle est utilisée.