Subtrahieren n Stunden von einem DateTime- in Ruby
-
04-07-2019 - |
Frage
Ich habe einen Ruby-Datetime, die aus einer Form gefüllt werden. Ich habe zusätzlich n Stunden von der Form als auch. Ich mag diese n Stunden von der vorherige Datetime subtrahieren. (Um einen Zeitbereich zu erhalten).
Datetime hat zwei Methoden „-“ und „<<“ subtrahieren Tag und Monat, aber nicht Stunde. ( API ). Irgendwelche Vorschläge, wie kann ich das tun?
Lösung
Sie können dies tun.
adjusted_datetime = (datetime_from_form.to_time - n.hours).to_datetime
Andere Tipps
Sie können nur subtrahieren weniger als einen ganzen Tag:
two_hours_ago = DateTime.now - (2/24.0)
Dies funktioniert für Minuten und alles andere auch:
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)>
Wenn Gleitpunktarithmetik Ungenauigkeiten ein Problem sind, können Sie Rational
oder ein anderes sicheres Arithmetik-Dienstprogramm verwenden können.
Der Fortschritt Methode ist schön, wenn man noch deutlicher über das Verhalten so sein soll.
adjusted = time_from_form.advance(:hours => -n)
Sie müssen nur Bruchteile eines Tages ausziehen.
two_hours_ago = DateTime.now - (2.0/24)
- 1,0 = 1 Tag
- 1,0 / 24 = 1 Stunde
- 1,0 / (24 * 60) = 1 Minute
- 1,0 / (24 * 60 * 60) = 1 Sekunde
n/24.0
Trick nicht richtig funktionieren wird als Schwimmer ist schließlich abgerundet:
>> 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
Sie können jedoch verwenden Rational Klasse statt:
>> 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
Sie nicht sagen, was verwenden Sie für den Wert erhalten Sie machen müssen, aber was ist nur um 24 Stunden Ihre Dividieren, so dass Sie einen Bruchteil eines Tages abgezogen?
mydatetime = DateTime.parse(formvalue)
nhoursbefore = mydatetime - n / 24.0
Bearbeiten : Werfen Sie einen Blick auf diese Frage , bevor Sie sich entscheiden, den Ansatz zu verwenden, die ich hier skizziert habe. Es scheint, es nicht am beste Praxis sein kann, das Verhalten einer Basisklasse in Ruby (was ich verstehen kann) zu ändern. Also, nehmen Sie diese Antwort mit einem Körnchen Salz ...
mattw Antwort war das erste, was ich dachte, aber ich habe es nicht sehr viel auch mögen.
Ich nehme an, Sie es durch das Patchen DateTime
und Fixnum
weniger hässlich machen könnte zu tun, was Sie wollen:
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
Dann können Sie Ihren Code wie folgt schreiben:
some_date = some_date - n.hours
wo n
ist die Anzahl der Stunden, die Sie von some_date
subtrahieren wollen
DateTime
kann dies nicht tun, aber Time
kann:
t = Time.now
t = t-hours*60
Beachten Sie, dass Time
speichert auch aktuelle Informationen, es ist alles ein wenig seltsam.
Wenn Sie mit DateTime
arbeiten
DateTime.commercial(date.year,date.month,date.day,date.hour-x,date.minute,date.second)
funktionieren könnte, ist aber hässlich. Der Doc sagt DateTime
ist unveränderlich, so ich bin nicht einmal sicher über -
und <<
Wenn ich darf Time
statt DateTime
verwenden (Es gibt mehr Möglichkeiten, eine auf einem andere zu übersetzen):
# Just remove the number of seconds from the Time object
Time.now - (6 * 60 * 60) # 6 hours ago
Ich mag die Helfer in active_support verwenden. Es macht es wirklich sauber und leicht zu lesen.
Sehen Sie das folgende Beispiel:
require 'active_support'
last_accessed = 2.hours.ago
last_accessed = 2.weeks.ago
last_accessed = 1.days.ago
Es könnte ein Weg sein, diese Art von Syntax zu verwenden, zu tun, was Sie suchen, wenn das aktuelle Datum verwendet wird.
Sie können diese verwenden:
Time.now.ago(n*60*60)
Zum Beispiel Time.now.ago(7200)
gibt das Datum und die Zeit, die von jetzt vor 2 Stunden war.