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?

War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top