Pergunta

Eu tenho um rubi DateTime que é preenchido de um formulário. Além disso eu ter n horas a partir da forma como bem. Eu gostaria de subtrair esses n horas do DateTime anterior. (Para obter um intervalo de tempo).

DateTime tem dois métodos "-" e "<<" para subtrair dia e mês, mas não hora. ( API ). Todas as sugestões como posso fazer isso?

Foi útil?

Solução

Você poderia fazer isso.

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

Outras dicas

Você pode apenas subtrair menos de um dia inteiro:

two_hours_ago = DateTime.now - (2/24.0)

Isso funciona para minutos e qualquer outra coisa também:

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

Se ponto flutuante imprecisões aritméticas são um problema, você pode usar Rational ou algum outro utilitário aritmética seguro.

O método de avanço é bom se você quer ser mais explícito sobre o comportamento assim.

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

Você só precisa tirar frações de um dia.

two_hours_ago = DateTime.now - (2.0/24)
  • 1,0 = um dia
  • 1,0 / 24 = 1 hora
  • 1.0 / (24 * 60) = um minuto
  • 1.0 / (24 * 60 * 60) = um segundo

truque n/24.0 não funcionará corretamente como carros alegóricos são, eventualmente arredondada:

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

Você pode, entretanto, usar a classe Rational vez:

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

Você não disse que usar o que você precisa fazer com o valor que você começa, mas que sobre apenas dividindo suas horas de 24 modo que você está subtraindo uma fração de um dia?

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

Editar : Dê uma olhada em esta questão antes de decidir usar a abordagem que descrevi aqui. Parece que pode não ser a melhor prática para modificar o comportamento de uma classe base em Ruby (que eu posso entender). Portanto, tome esta resposta com um grão de sal ...


de MattW resposta foi a primeira coisa que eu pensado, mas eu também não gostava muito.

Eu suponho que você poderia torná-lo menos feio remendando DateTime e Fixnum para fazer o que quiser:

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

Em seguida, você pode escrever seu código como este:

some_date = some_date - n.hours

onde n é o número de horas que você quer subtrair a partir some_date

DateTime não pode fazer isso, mas Time pode:

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

Note que a informação Time também armazena data, é tudo um pouco estranho.

Se você tem que trabalhar com DateTime

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

pode funcionar, mas é feio. O doc diz DateTime é imutável, então eu nem tenho certeza sobre - e <<

Se eu estou autorizado a utilização Time vez de DateTime (Há várias maneiras de traduzir um para outro ):

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

Eu gosto de usar os ajudantes em active_support. Isso torna muito limpo e fácil de ler.

Veja o exemplo abaixo:

require 'active_support'

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

Pode haver uma maneira de usar esse tipo de sintaxe para fazer o que você está procurando, se a data atual é usada.

Você pode usar este:

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

Por exemplo Time.now.ago(7200) dará a data e hora em que foi antes de 2 horas a partir de agora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top