Gibt es eine einfache Möglichkeit, eine Zeit auf die nächsten 15 Minuten abzurunden?
Das ist es, was ich derzeit tue. Gibt es einen einfacheren Weg, dies zu tun?
t = Time.new
rounded_t = Time.local(t.year, t.month, t.day, t.hour, t.min/15*15)
Gibt es eine einfache Möglichkeit, eine Zeit auf die nächsten 15 Minuten abzurunden?
Das ist es, was ich derzeit tue. Gibt es einen einfacheren Weg, dies zu tun?
t = Time.new
rounded_t = Time.local(t.year, t.month, t.day, t.hour, t.min/15*15)
Es gibt hier eine ganze Reihe von Lösungen, und ich begann, mich über ihre Effizienz zu wundern (obwohl Effizienz bei diesem Problem wahrscheinlich nicht der wichtigste Aspekt ist). Ich habe einige von hier übernommen und ein paar eigene hinzugefügt. (N.B.: Obwohl der Auftraggeber darum bat, auf die nächsten 15 Minuten abzurunden, habe ich meine Vergleiche und Stichproben mit nur 1 Minute / 60 Sekunden durchgeführt, um einfachere Stichproben zu erhalten).
Benchmark.bmbm do |x|
x.report("to_f, /, floor, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_f / 60).floor * 60) } }
x.report("to_i, /, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_i / 60) * 60) } }
x.report("to_i, %, - and Time.at") { 1_000_000.times { t = Time.now.to_i; Time.at(t - (t % 60)) } }
x.report("to_i, %, seconds and -") { 1_000_000.times { t = Time.now; t - (t.to_i % 60).seconds } }
x.report("to_i, % and -") { 1_000_000.times { t = Time.now; t - (t.to_i % 60) } }
end
Rehearsal -----------------------------------------------------------------
to_f, /, floor, * and Time.at 4.380000 0.010000 4.390000 ( 4.393235)
to_i, /, * and Time.at 3.270000 0.010000 3.280000 ( 3.277615)
to_i, %, - and Time.at 3.220000 0.020000 3.240000 ( 3.233176)
to_i, %, seconds and - 10.860000 0.020000 10.880000 ( 10.893103)
to_i, % and - 4.450000 0.010000 4.460000 ( 4.460001)
------------------------------------------------------- total: 26.250000sec
user system total real
to_f, /, floor, * and Time.at 4.400000 0.020000 4.420000 ( 4.419075)
to_i, /, * and Time.at 3.220000 0.000000 3.220000 ( 3.226546)
to_i, %, - and Time.at 3.270000 0.020000 3.290000 ( 3.275769)
to_i, %, seconds and - 10.910000 0.010000 10.920000 ( 10.924287)
to_i, % and - 4.500000 0.010000 4.510000 ( 4.513809)
Was ist davon zu halten? Nun, die Dinge können auf Ihrer Hardware schneller oder langsamer funktionieren, also nehmen Sie meinen Computer nicht beim Wort. Wie Sie sehen, macht es auch keinen großen Unterschied, welche Methode Sie verwenden, was die Rechenleistung angeht, es sei denn, wir führen diese Operationen im Umfang von Millionen von Operationen durch (beachten Sie jedoch, dass beispielsweise die meisten Cloud-Computing-Lösungen nur sehr wenig Rechenleistung bieten, so dass die Millionen in solchen Umgebungen vielleicht Hunderte oder Zehntausende sind).
In diesem Sinne eindeutig der langsamste von ihnen t = Time.now; t - (t.to_i % 60).seconds
kann gerechtfertigt sein, weil die .seconds dort so cool sind.
Da sie aber eigentlich gar nicht benötigt wird und die Operation mehr als doppelt so teuer macht wie ohne sie, muss ich sagen, dass meine Wahl auf die t = Time.now; t - (t.to_i % 60)
. Meiner Meinung nach ist sie schnell genug und millionenfach besser lesbar als alle anderen hier vorgestellten Lösungen. Deshalb denke ich, dass es die beste Lösung für Ihre gelegentlichen Bodenbelagsbedürfnisse ist, obwohl es deutlich langsamer ist als die drei anderen.
Die meistgewählte Lösung auf dieser Seite Time.at((Time.now.to_f / 60).floor * 60)
ist die langsamste aller Lösungen auf dieser Seite (vor dieser Antwort) und deutlich langsamer als die ersten beiden Lösungen. Die Verwendung von Fließkommazahlen, nur um die Dezimalstellen wegzudrücken, erscheint ebenfalls sehr unlogisch. Für das Runden wäre das in Ordnung, aber das Abrunden klingt für mich wie "Aufrunden". Wenn überhaupt, könnte das Gegenstück dazu das Aufrunden oder "Aufstocken" sein, was in etwa so aussehen würde t = Time.now; t - (60 - t.to_i % 60) % 60
ou Time.at((Time.now.to_f / 60).ceil * 60)
. Das doppelte Modulo, das die to_i-Lösung hier benötigt, sieht etwas unschön aus, so dass ich hier die ceil-Methode bevorzugen würde, auch wenn sie deutlich schneller ist. (Benchmarks sind ganz am Ende dieses Beitrags angefügt)
Die beiden besten Ergebnisse im Test waren zwei to_i-Varianten, die leicht unterschiedliche Kombinationen von Operationen verwenden und dann Integer zurück in Time-Objekte konvertieren, wobei die Unterschiede so unbedeutend sind, dass man nicht wirklich einen Gewinner ausmachen kann. Wenn Sie es eilig haben, sollten Sie diese Varianten verwenden:
Time.at((Time.now.to_i / 60) * 60)
t = Time.now.to_i; Time.at(t - (t % 60))
Benchmark.bmbm do |x|
x.report("to_f, /, ceil, * and Time.at") { 1_000_000.times { Time.at((Time.now.to_f / 60).ceil * 60) } }
x.report("to_i, %, -, %, + and Time.at") { 1_000_000.times { t = Time.now; t + (60 - t.to_i % 60) % 60 } }
end
Rehearsal ----------------------------------------------------------------
to_f, /, ceil, * and Time.at 4.410000 0.040000 4.450000 ( 4.446320)
to_i, %, -, %, + and Time.at 3.910000 0.020000 3.930000 ( 3.939048)
------------------------------------------------------- total: 8.380000sec
user system total real
to_f, /, ceil, * and Time.at 4.420000 0.030000 4.450000 ( 4.454173)
to_i, %, -, %, + and Time.at 3.860000 0.010000 3.870000 ( 3.884866)
# this is an extension of Ryan McGeary's solution, specifically for Rails.
# Note the use of utc, which is necessary to keep Rails time zone stuff happy.
# put this in config/initializers/time_extensions
require 'rubygems'
require 'active_support'
module TimeExtensions
%w[ round floor ceil ].each do |_method|
define_method _method do |*args|
seconds = args.first || 60
Time.at((self.to_f / seconds).send(_method) * seconds).utc
end
end
end
Time.send :include, TimeExtensions
Chucks Antwort ist zwar elegant, bringt Sie aber in Schwierigkeiten, wenn Sie versuchen, auf diese Weise abgeleitete Werte zu vergleichen; die Usecs werden nicht auf Null gesetzt.
Mit der Antwort von Shalmanese ist das erledigt, oder Chucks Antwort kann wie folgt abgeändert werden:
t = Time.new
truncated_t = Time.at(t.to_i - t.sec - t.min % 15 * 60)
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.