Policz liczbę dni między dwiema datami

149

Jak policzyć liczbę dni między tymi dwiema datami?

start_date = Date.parse "2012-03-02 14:46:21 +0100"
end_date =  Date.parse "2012-04-02 14:46:21 +0200"
andkjaer
źródło

Odpowiedzi:

207

Za pomocą klas Date (i DateTime) możesz (end_date - start_date).to_iuzyskać różnicę w liczbie dni.

Andrew France
źródło
5
@MichaelDurrant Robisz nieuzasadnione założenie. Użytkownik nie określa, czy są to łańcuchy, czy nie. W rzeczywistości, ponieważ używają Railsów, najprawdopodobniej daty pochodzą z ActiveRecord, który automatycznie rzutuje je na obiekty daty. Podany tekst jest również identyczny z reprezentacją obiektu Date, co sprawia, że ​​jest wysoce prawdopodobne, że pochodzi z natywnego źródła.
Andrew France
84
To daje mi różnicę w sekundach, a nie w dniach z szynami v3 / 4
wezwany-chaos
6
O ile wiem, zachowanie pozostaje takie samo we wszystkich ostatnich wersjach Ruby i ActiveSupport, uwzględnij odpowiednio 2.0 i 4.1.0. Timeobiekty zwracają jednak sekundy.
Andrew France
5
aby rozwinąć odpowiedź @ 2called-chaos, aby uzyskać dni, których potrzebujesz (data_końcowa - data_początkowa) /1.day, co da ci liczbę zmiennoprzecinkową. Jeśli chcesz mieć tylko pełne dni, możesz użyć ((data_końcowa
David K.
2
@David Tyle że komentarz @ 2called-chaos błędnie odnosi się do Timeobiektów, a nie Dateobiektów. Może mógłbyś zaktualizować nazewnictwo w swoim komentarzu, aby odzwierciedlić, że nie są to daty?
Andrew France
109

Zakładając, że end_datei start_dateoba są klasą ActiveSupport::TimeWithZonew Railsach, możesz użyć:

(end_date.to_date - start_date.to_date).to_i
zawietrzny
źródło
2
Jeśli ma to związek z polami tabeli, ta odpowiedź jest do zrobienia; zamiast najwyżej ocenianego tutaj.
Ben,
Nie działa (Time.zone.now.to_date - 23.hours.ago.to_date).to_i, daje 1 i powinno być 0
Yuri Ghensev
3
@YuriGhensev, zależy to od tego, kiedy uruchomisz przykładowy kod, na przykład teraz Time.zone.now.to_datezwraca „Wed, 15 Nov 2017”, a 23.hours.ago.to_datezwraca „Tue, 14 Nov 2017”. Różnica w liczbie dni wynosi i powinna wynosić 1, chyba że uruchomiłeś kod na godzinę przed północą.
lee
35

Railsy mają wbudowanych pomocników, które mogą rozwiązać ten problem. Należy pamiętać, że jest to część pomocników Actionview, więc nie będą one dostępne bezpośrednio z konsoli.

Spróbuj tego

<% start_time =  "2012-03-02 14:46:21 +0100" %>
<% end_time   =  "2012-04-02 14:46:21 +0200" %>
<%= distance_of_time_in_words(start_time, end_time)  %>

 "about 1 month"
Justin Herrick
źródło
@MaayanNaveh nie powinno być, gdy potrzebujesz rzeczywistej liczby do obliczeń.
Fedcomp
To pytanie jest jednym z tych przypadków, w których samo pytanie lepiej jest zadać inaczej. Jeśli zastosujesz się do innych odpowiedzi tutaj, napotkasz przypadki, w których czasami chcesz, aby zamiast dni były wyświetlane tygodnie lub lata. To naprawdę powinno zostać zaakceptowane jako „właściwa” odpowiedź Railsów.
Dylan Pierce
34

Otrzymywałem wyniki w ciągu kilku sekund, więc to zadziałało:

(Time.now - self.created_at) / 86400
todankent
źródło
1
@Epigene 1.daynie jest rubyzgodne z żądaniem OP (w tagach). Jest to Railslub bardziej szczegółowe, active supportchociaż created_atjest w zasadzie Modelmetodą w Railstak ..
Roko
26

aby uzyskać liczbę dni w zakresie czasowym (tylko liczba wszystkich dni)

(start_date..end_date).count
(start_date..end_date).to_a.size
#=> 32

aby uzyskać liczbę dni między dwiema datami

(start_date...end_date).count
(start_date...end_date).to_a.size
#=> 31
a14m
źródło
Dzięki za to @ a14m! Dał mi sposób na robienie inkluzywnych i ekskluzywnych ujęć randkowych :)
Kris Boyd
18

Żadna z poprzednich odpowiedzi (do tej pory) nie podaje prawidłowej różnicy w dniach między dwiema datami.

Ten, który jest najbliżej, jest godny . Pełna odpowiedź przekształciłaby, to_ia następnie podzieliłaby:

(Time.now.to_i - 23.hours.ago.to_i) / 86400
>> 0

(Time.now.to_i - 25.hours.ago.to_i) / 86400
>> 1

(Time.now.to_i - 1.day.ago.to_i) / 86400
>> 1

W konkretnym przykładzie pytania nie należy analizować, Dateczy upływający czas jest istotny. Użyj Time.parsezamiast tego.

Yuri Ghensev
źródło
Może to nie działać zgodnie z oczekiwaniami, gdy czasy przekraczają przejście na czas letni do przodu. W tym przypadku długość dnia przejściowego DST jest zgodnie z prawem krótsza niż 24 godziny, ale z powodu arytmetyki całkowitej ten dzień w ogóle nie zostanie odzwierciedlony.
PinnyM
4

Aby mieć liczbę pełnych dni między dwiema datami ( DateTimeobiektami):

((end_at - start_at).to_f / 1.day).floor
dorycki
źródło
Ten sam problem z czasem letnim, co w odpowiedzi, której udzielił Jurij. Arytmetyka z czasem nigdy nie jest tak prosta, jak można by się tego spodziewać :)
PinnyM
0

Aby uzyskać różnicę w liczbie dni w dwóch datach:

(start.to_date...end.to_date).count - 1
or 
(end.to_date - start.to_date).to_i
giapnh
źródło
-8
def business_days_between(date1, date2)
  business_days = 0
  date = date2
  while date > date1
   business_days = business_days + 1 unless date.saturday? or date.sunday?
   date = date - 1.day
  end
  business_days
end
Teja
źródło
3
znacznie łatwiej odjąć obiekty daty.
OpenCoderX
OP nigdy nie pytał o dostosowanie do dni roboczych. I tak jest to naprawdę zawiłe.
Nathan