Définir la partie horaire de DateTime en rubis

104

Disons que j'ai un objet datetime, par exemple DateTime.now. Je veux régler les heures et les minutes sur 0 (minuit). Comment puis je faire ça?

Jesse Aldridge
la source

Réponses:

220

Dans un environnement Rails:

Grâce à ActiveSupport, vous pouvez utiliser:

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

Dans un environnement purement 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
la source
26
FWIW, la méthode de changement fait partie des rails et non du rubis. Les options de temps (heure, minute, sec) se réinitialisent en cascade, donc si seule l'heure est passée, les minutes et les secondes sont réglées sur 0. Si l'heure et les minutes sont dépassées, sec est réglé sur 0.
Anna
1
Sachez que DateTime.now.midnight ne renvoie pas 24:00:00 comme vous pouvez vous y attendre, il renvoie 00:00:00 - la même valeur que begin_of_day. Voir ma réponse pour savoir pourquoi cela pourrait être important dans certains scénarios.
rmcsharry
1
Votre première solution purement rubis supprime les informations de fuseau horaire, votre seconde ne le fait pas
Tony
1
J'ai mis à jour la réponse pour prendre en compte le fuseau horaire et remplacé la deuxième variante. @Tony très bonne prise, ils étaient en fait tous les deux sensibles à la perte d'informations sur le fuseau horaire à y regarder de plus près. DateTime.new(now.year, now.month, now.day, 0,0,0, now.zone) != now.to_date.to_datetime
ashoda
TIMEZONE: peut être modifié par le décalage du mot clé dans le hachage d'argument: DateTime.now.change ({hour: 0, min: 0, sec: 0 offset: '+02: 00'})
Ekkstein
34

Nevermind, compris. Besoin de créer un nouveau DateTime:

DateTime.new(now.year, now.month, now.day, 0, 0, 0, 0)
Jesse Aldridge
la source
6
Bonne réponse. Je voulais juste ajouter que ces zéros représentent HOUR, MINUTE, SECOND et OFFSET (fuseau horaire) dans cet ordre.
d_ethier
3
Après avoir échoué à faire fonctionner cela, j'ai appris cela avec: DateTime.new(Time.now.year, Time.now.month, Time.now.day, 0, 0, 0)cela fonctionne.
Ekkstein
2
N'oubliez pas: now = DateTime.now
Abel
1
Notez également que le dernier argument doit être une chaîne du fuseau horaire, par exemple ("- 0700") pour MST, pas un entier
Donavan White
2
Sauf si vous avez affaire à des dates historiques, NE PAS UTILISER DateTime. Vous aurez des problèmes ennuyeux si vous vivez dans un pays qui a l'heure d'été comme le Royaume-Uni. Voir une explication ici. gist.github.com/pixeltrix/e2298822dd89d854444b
fatuhoku
5

Attention : DateTime.now.midnightet DateTime.now.beginning_of_dayrenvoyez la même valeur (qui est l'heure zéro du jour en cours - minuit ne renvoie pas 24:00:00 comme vous l'attendriez de son nom).

J'ajoute donc ceci comme information supplémentaire pour quiconque pourrait utiliser la réponse acceptée pour calculer minuit x jours dans le futur.

Par exemple, un essai gratuit de 14 jours qui devrait expirer à minuit le 14e jour:

DateTime.now.midnight + 14.days

est le matin du 14e jour, ce qui équivaut à un essai de 13.x jours (x est la partie de la journée restante - si maintenant c'est midi, alors c'est un essai de 13,5 jours).

Vous auriez en fait besoin de faire ceci:

DateTime.now.midnight + 15.days

pour obtenir minuit le 14e jour.

Pour cette raison, je préfère toujours utiliser beginning_of_day, car c'est 00:00:00. Utiliser minuit peut être trompeur / mal compris.

rmcsharry
la source
1

Si vous l'utilisez souvent, pensez à installer cette gemme pour améliorer l'analyse des dates:

https://github.com/mojombo/chronic

require 'chronic'

Chronic.parse('this 0:00')
wizztjh
la source
Je ne sais pas pourquoi cette réponse est indiquée comme correcte. Cela ne répond pas vraiment à la question. Je sais comment analyser une chaîne à une date. Mais j'aimerais savoir comment modifier une partie particulière d'une instance de date donnée. Par exemple l'année. Des idées? En Java, j'utiliserais simplement le setter pendant un an. Mais cela ne fonctionne pas dans Ruby :-(
Robert Reiz
1
Je ne fais plus confiance aux gemmes chroniques. C'est vraiment dépassé. J'ai rencontré un problème lors de l'analyse de la date et de l'heure au moment de l'exécution dans mon application, ce qui a entraîné une perte d'activité.
Vijay Meena