Domanda

Ho un Ruby DateTime che viene riempito da un modulo. Inoltre ho n ore dal modulo pure. Vorrei sottrarre quelle n ore dal precedente DateTime. (Per ottenere un intervallo di tempo).

DateTime ha due metodi " - " e " < < " per sottrarre giorno e mese, ma non ora. ( API ). Qualche suggerimento su come posso farlo?

È stato utile?

Soluzione

Potresti farlo.

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

Altri suggerimenti

Puoi sottrarre solo meno di un giorno intero:

two_hours_ago = DateTime.now - (2/24.0)

Funziona per minuti e quant'altro:

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

Se le inesattezze aritmetiche in virgola mobile sono un problema, è possibile utilizzare Rational o qualche altra utilità aritmetica sicura.

Il metodo avanzato è utile se vuoi essere più esplicito su comportamenti come questo.

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

Devi solo toglierti le frazioni di un giorno.

two_hours_ago = DateTime.now - (2.0/24)
  • 1.0 = un giorno
  • 1.0 / 24 = 1 ora
  • 1.0 / (24 * 60) = 1 minuto
  • 1.0 / (24 * 60 * 60) = 1 secondo

n/24.0 Il trucco non funzionerà correttamente poiché i float vengono infine arrotondati:

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

Tuttavia, è possibile utilizzare invece la classe Rational:

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

Non hai detto a che cosa serve per fare del valore che ottieni, ma che ne dici di dividere le tue ore per 24 in modo da sottrarre una frazione del giorno?

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

MODIFICA : dai un'occhiata a questa domanda prima di decidere di utilizzare l'approccio che ho delineato qui. Sembra che potrebbe non essere la migliore pratica modificare il comportamento di una classe di base in Ruby (che posso capire). Quindi, prendi questa risposta con un granello di sale ...


La risposta di MattW è stata la prima cosa che ho pensato, ma anche a me non è piaciuto molto.

Suppongo che potresti renderlo meno brutto patching DateTime e Fixnum per fare quello che vuoi:

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

Quindi puoi scrivere il tuo codice in questo modo:

some_date = some_date - n.hours

dove n è il numero di ore che si desidera sottrarre da some_date

DateTime non può farlo, ma Time può:

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

Nota che - memorizza anche le informazioni sulla data, è tutto un po 'strano.

Se devi lavorare con <<

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

potrebbe funzionare, ma è brutto. Il documento dice che <=> è immutabile, quindi non sono nemmeno sicuro di <=> e <=>

Se mi è permesso usare Time invece di DateTime (Ci sono diversi modi per tradurli l'un l'altro ):

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

Mi piace usare gli helper in active_support. Lo rende davvero pulito e di facile lettura.

Vedi l'esempio seguente:

require 'active_support'

last_accessed = 2.hours.ago
last_accessed = 2.weeks.ago
last_accessed = 1.days.ago

Potrebbe esserci un modo per utilizzare quel tipo di sintassi per fare ciò che stai cercando, se viene utilizzata la data corrente.

Puoi usare questo:

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

Ad esempio Time.now.ago(7200) fornirà la data e l'ora che erano prima di 2 ore da adesso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top