Question

J'ai un DateTime Ruby qui est rempli à partir d'un formulaire. De plus, j'ai n heures à partir du formulaire. Je voudrais soustraire ces n heures du DateTime précédent. (Pour obtenir une plage de temps).

DateTime a deux méthodes " - " et " < < " pour soustraire le jour et le mois, mais pas l'heure. ( API ). Avez-vous des suggestions à faire?

Était-ce utile?

La solution

Vous pouvez le faire.

adjusted_datetime = (datetime_from_form.to_time - n.hours).to_datetime

Autres conseils

Vous pouvez simplement soustraire moins d'une journée entière:

two_hours_ago = DateTime.now - (2/24.0)

Ceci fonctionne pendant des minutes et toute autre chose aussi:

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 imprécisions arithmétiques en virgule flottante posent problème, vous pouvez utiliser Rational ou un autre utilitaire arithmétique sécurisé.

La méthode d'avance est intéressante si vous souhaitez être plus explicite à propos d'un comportement comme celui-ci.

adjusted = time_from_form.advance(:hours => -n)

Il vous suffit d’enlever des fractions de jour.

two_hours_ago = DateTime.now - (2.0/24)
  • 1,0 = un jour
  • 1.0 / 24 = 1 heure
  • 1.0 / (24 * 60) = 1 minute
  • 1.0 / (24 * 60 * 60) = 1 seconde

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 toutefois 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

Vous n’avez pas précisé l’utilisation que vous devez faire de la valeur que vous obtenez, mais qu’en est-il de diviser vos heures par 24 afin de soustraire une fraction de jour?

mydatetime = DateTime.parse(formvalue)
nhoursbefore = mydatetime - n / 24.0

MODIFIER : consultez cette question avant de décider d'utiliser l'approche que j'ai décrite ici. Il semble que la modification du comportement d’une classe de base en Ruby ne soit pas recommandée (ce que je peux comprendre). Alors, prenez cette réponse avec un grain de sel ...

La réponse de MattW a été la première chose que j'ai pensé, mais je ne l’aimais pas beaucoup non plus.

Je suppose que vous pourriez le rendre moins laid en appliquant des correctifs à 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 suit:

some_date = some_date - n.hours

n est le nombre d'heures que vous souhaitez soustraire some_date

DateTime ne peut pas faire cela, mais Time peut:

t = Time.now
t = t-hours*60

Notez que - stocke également les informations relatives à la date, c'est un peu étrange.

Si vous devez travailler avec <<

DateTime.commercial(date.year,date.month,date.day,date.hour-x,date.minute,date.second)

pourrait fonctionner, mais est moche. La doc dit que <=> est immuable, je ne suis même pas sûr de <=> et de <=>

Si je suis autorisé à utiliser Time au lieu de DateTime ( Plusieurs façons de traduire l'un vers l'autre ):

# Just remove the number of seconds from the Time object
Time.now - (6 * 60 * 60) # 6 hours ago

J'aime utiliser les helpers de 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 recherchez, si la date actuelle est utilisée.

Vous pouvez utiliser ceci:

Time.now.ago(n*60*60)

Par exemple, Time.now.ago(7200) donnera la date et l'heure qui étaient antérieures à 2 heures.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top