Sottrai n ore da un DateTime in Ruby
-
04-07-2019 - |
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?
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.