Pregunta

Tengo un Ruby DateTime que se completa desde un formulario.Además, también tengo n horas del formulario.Me gustaría restar esas n horas del DateTime anterior.(Para obtener un rango de tiempo).

DateTime tiene dos métodos "-" y "<<" para restar día y mes, pero no hora.(API).¿Alguna sugerencia de cómo puedo hacer eso?

¿Fue útil?

Solución

Podrías hacer esto.

adjusted_datetime = (datetime_from_form.to_time - n.hours).to_datetime

Otros consejos

Puede restar menos de un día entero:

two_hours_ago = DateTime.now - (2/24.0)

Esto funciona durante minutos y cualquier otra cosa también:

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)>

Si las imprecisiones aritméticas de coma flotante son un problema, puede usar Rational o alguna otra utilidad aritmética segura.

El método de avance es bueno si quieres ser más explícito sobre comportamientos como este.

adjusted = time_from_form.advance(:hours => -n)

Solo necesitas quitar fracciones de un día.

two_hours_ago = DateTime.now - (2.0/24)
  • 1.0 = un día
  • 1.0 / 24 = 1 hora
  • 1.0 / (24 * 60) = 1 minuto
  • 1.0 / (24 * 60 * 60) = 1 segundo
El

n/24.0 truco no funcionará correctamente ya que los flotadores se redondean eventualmente:

>> 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

Sin embargo, puede usar la clase Rational en su lugar:

>> 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

No dijiste qué uso necesitas hacer del valor que obtienes, pero ¿qué hay de dividir tus horas entre 24 para restar una fracción de día?

mydatetime = DateTime.parse(formvalue)
nhoursbefore = mydatetime - n / 24.0

EDITAR:Echa un vistazo a esta pregunta antes de decidir utilizar el enfoque que he descrito aquí.Parece que puede que no sea una buena práctica modificar el comportamiento de una clase base en Ruby (lo cual puedo entender).Así que toma esta respuesta con cautela...


La respuesta de MattW Fue lo primero que pensé, pero tampoco me gustó mucho.

Supongo que podrías hacerlo menos feo parcheando DateTime y Fixnum para hacer lo que quieras:

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

Entonces puedes escribir tu código así:

some_date = some_date - n.hours

dónde n es el número de horas que deseas restar some_date

DateTime No puedo hacer esto, pero Time poder:

t = Time.now
t = t-hours*60

Tenga en cuenta que Time También almacena información de fechas, es todo un poco extraño.

Si tienes que trabajar con DateTime

DateTime.commercial(date.year,date.month,date.day,date.hour-x,date.minute,date.second)

Podría funcionar, pero es feo.El doctor dice DateTime es inmutable, así que ni siquiera estoy seguro de - y <<

Si se me permite usar Time en lugar de DateTime (Hay varias formas de traducir uno a otro ):

# Just remove the number of seconds from the Time object
Time.now - (6 * 60 * 60) # 6 hours ago

Me gusta usar los ayudantes en active_support. Lo hace realmente limpio y fácil de leer.

Vea el ejemplo a continuación:

require 'active_support'

last_accessed = 2.hours.ago
last_accessed = 2.weeks.ago
last_accessed = 1.days.ago

Puede haber una forma de usar ese tipo de sintaxis para hacer lo que está buscando, si se usa la fecha actual.

Puedes usar esto:

Time.now.ago(n*60*60)

Por ejemplo, Time.now.ago(7200) proporcionará la fecha y la hora antes de 2 horas a partir de ahora.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top