Вычтите n часов из DateTime в Ruby
-
04-07-2019 - |
Вопрос
У меня есть Ruby DateTime, который заполняется из формы.Кроме того, у меня также есть n часов из формы.Я хотел бы вычесть эти n часов из предыдущего DateTime.(Чтобы получить временной диапазон).
DateTime имеет два метода «-» и «<<» для вычитания дня и месяца, но не часа.(API).Любые предложения, как я могу это сделать?
Решение
Вы могли бы сделать это.
adjusted_datetime = (datetime_from_form.to_time - n.hours).to_datetime
Другие советы
Вы можете просто вычесть меньше, чем один целый день:
two_hours_ago = DateTime.now - (2/24.0)
Это работает в течение нескольких минут и всего остального тоже:
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)>
Если арифметические неточности с плавающей запятой являются проблемой, вы можете использовать Rational
или другую безопасную арифметическую утилиту.
Метод advance удобен, если вы хотите быть более понятным в отношении такого поведения.
adjusted = time_from_form.advance(:hours => -n)
Вам просто нужно снимать доли дня.
two_hours_ago = DateTime.now - (2.0/24)
- 1,0 = один день
- 1,0/24 = 1 час
- 1,0/(24*60) = 1 минута
- 1,0/(24*60*60) = 1 секунда
n/24.0
трюк не будет работать должным образом, поскольку числа с плавающей запятой со временем округляются:
>> 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
Однако вместо этого вы можете использовать класс 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
Вы не сказали, как вам нужно использовать полученное значение, но как насчет простого деления ваших часов на 24, чтобы вы вычитали долю дня?
mydatetime = DateTime.parse(formvalue)
nhoursbefore = mydatetime - n / 24.0
РЕДАКТИРОВАТЬ : взгляните на этот вопрос , прежде чем вы решите использовать подход, который я изложил здесь. Похоже, что не рекомендуется изменять поведение базового класса в Ruby (что я могу понять). Итак, примите этот ответ с крошкой соли ...
<Ч>Ответ MattW был первым, что я думал, но мне тоже не очень понравилось.
Полагаю, вы могли бы сделать его менее уродливым, исправив DateTime
и Fixnum
сделать то, что вы хотите:
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
Затем вы можете написать свой код следующим образом:
some_date = some_date - n.hours
где n
- количество часов, которое вы хотите вычесть из some_date
DateTime
не может этого сделать, но Time
может:
t = Time.now
t = t-hours*60
Обратите внимание, что -
также хранит информацию о дате, все это немного странно.
Если вам нужно работать с <<
DateTime.commercial(date.year,date.month,date.day,date.hour-x,date.minute,date.second)
может работать, но безобразно. В документе сказано, что <=> является неизменным, поэтому я даже не уверен насчет <=> и <=>
Если мне разрешено использовать Time
вместо DateTime
(есть несколько способов перевести один в другой ):
# Just remove the number of seconds from the Time object
Time.now - (6 * 60 * 60) # 6 hours ago
Мне нравится использовать помощников в active_support. Это делает его действительно чистым и легким для чтения.
См. пример ниже:
require 'active_support'
last_accessed = 2.hours.ago
last_accessed = 2.weeks.ago
last_accessed = 1.days.ago
Возможно, можно использовать такой синтаксис для выполнения того, что вы ищете, если используется текущая дата.
Вы можете использовать это:
Time.now.ago(n*60*60)
Например, Time.now.ago(7200)
предоставит дату и время, которые были раньше, чем через 2 часа.