Definir parte da hora de DateTime em ruby

104

Digamos que eu tenha um objeto datetime, por exemplo DateTime.now. Quero definir horas e minutos como 0 (meia-noite). Como eu posso fazer isso?

Jesse Aldridge
fonte

Respostas:

220

Dentro de um ambiente Rails:

Graças ao ActiveSupport você pode usar:

DateTime.now.midnight
DateTime.now.beginning_of_day

OU

DateTime.now.change({ hour: 0, min: 0, sec: 0 })

# More concisely
DateTime.now.change({ hour: 0 })                

Em um ambiente puramente Ruby:

now = DateTime.now
DateTime.new(now.year, now.month, now.day, 0, 0, 0, now.zone)

OU

now = DateTime.now
DateTime.parse(now.strftime("%Y-%m-%dT00:00:00%z"))
Ashoda
fonte
26
FWIW, o método de mudança faz parte do Rails, não do Ruby. As opções de tempo (hora, minuto, segundo) são redefinidas em cascata, portanto, se apenas a hora tiver passado, minuto e segundo serão definidos como 0. Se a hora e o minuto forem passados, seg será definido como 0.
Anna
1
Esteja ciente de que DateTime.now.midnight não retorna 24:00:00 como você pode esperar, ele retorna 00:00:00 - o mesmo valor de start_of_day. Veja minha resposta sobre por que isso pode ser importante em alguns cenários.
rmcsharry
1
Sua primeira solução puramente rubi elimina as informações de fuso horário, a segunda não
Tony
1
Atualizei a resposta para levar em consideração o fuso horário e substituí a segunda variação. @Tony captura muito boa, eles eram, na verdade, ambos suscetíveis à perda de informações de fuso horário em uma análise mais detalhada. DateTime.new(now.year, now.month, now.day, 0,0,0, now.zone) != now.to_date.to_datetime
ashoda
TIMEZONE: pode ser alterado pelo deslocamento da palavra-chave no hash do argumento: DateTime.now.change ({hora: 0, min: 0, sec: 0 deslocamento: '+02: 00'})
Ekkstein
34

Esqueça, entendi. É necessário criar um novo DateTime:

DateTime.new(now.year, now.month, now.day, 0, 0, 0, 0)
Jesse Aldridge
fonte
6
Boa resposta. Só queria acrescentar que esses zeros representam HORA, MINUTO, SEGUNDO e DESLOCAMENTO (fuso horário) nessa ordem.
d_ethier
3
Depois de não conseguir fazer isso funcionar, aprendi que com: DateTime.new(Time.now.year, Time.now.month, Time.now.day, 0, 0, 0)funciona.
Ekkstein
2
Não se esqueça: now = DateTime.now
Abel
1
Observe também que o último argumento precisa ser uma string do fuso horário, por exemplo ("- 0700") para MST, não um número inteiro
Donavan White
2
A menos que você esteja lidando com datas históricas, NÃO USE DateTime. Você terá problemas irritantes se morar em um país que tem horário de verão, como o Reino Unido. Veja uma explicação aqui. gist.github.com/pixeltrix/e2298822dd89d854444b
fatuhoku
5

Aviso : DateTime.now.midnighte DateTime.now.beginning_of_dayretorna o mesmo valor (que é a hora zero do dia atual - meia-noite não retorna 24:00:00 como você esperaria de seu nome).

Portanto, estou adicionando isso como mais informações para qualquer um que possa usar a resposta aceita para calcular meia-noite x dias no futuro.

Por exemplo, uma avaliação gratuita de 14 dias que deve expirar à meia-noite do 14º dia:

DateTime.now.midnight + 14.days

é a manhã do 14º dia, o que equivale a um teste de 13.x dias (x é a parte do dia restante - se agora é meio-dia, então é um teste de 13,5 dias).

Você realmente precisaria fazer isso:

DateTime.now.midnight + 15.days

para chegar à meia-noite do 14º dia.

Por isso prefiro sempre usar beginning_of_day, já que é 00:00:00. Usar meia-noite pode ser enganoso / mal interpretado.

rmcsharry
fonte
1

Se você o usa com frequência, considere instalar esta gema para melhorar a análise de data:

https://github.com/mojombo/chronic

require 'chronic'

Chronic.parse('this 0:00')
wizztjh
fonte
Não sei por que essa resposta está marcada como certa. Realmente não responde à pergunta. Eu sei como analisar uma string para uma data. Mas eu gostaria de saber como alterar uma parte específica de uma determinada instância de data. Por exemplo, o ano. Alguma ideia? Em Java, eu usaria apenas o setter por ano. Mas não funciona em Ruby :-(
Robert Reiz
1
Eu não confio mais em gemas crônicas. Está realmente desatualizado. Tive problemas ao analisar data e hora em tempo de execução em meu aplicativo, o que resultou na perda de negócios.
Vijay Meena