182

How do I count the number of days between these two dates?

start_date = Date.parse "2012-03-02 14:46:21 +0100"
end_date =  Date.parse "2012-04-02 14:46:21 +0200"
BinaryButterfly
  • 18,137
  • 13
  • 50
  • 91
andkjaer
  • 3,995
  • 10
  • 36
  • 45

12 Answers12

252

With the Date (and DateTime) classes you can do (end_date - start_date).to_i to get the number of days difference.

Andrew France
  • 4,758
  • 1
  • 25
  • 27
  • 1
    yeah but user has strings and you can't do this with strings. You need them as dates. See my answer for adding in to_date from core extensions. – Michael Durrant Mar 05 '12 at 19:59
  • 5
    @MichaelDurrant You are making an unwarranted assumption. The user does not specify if they are strings or not. In fact since they are using Rails it's most likely the dates are coming from ActiveRecord which will automatically cast them to date objects. The given text is identical to Date object representation as well, making it highly likely it's come from a native source. – Andrew France Mar 05 '12 at 20:04
  • 1
    Correct I am assuming the user tried a - b and it didn't work so they ended up posting on SO. I guess only andkjaer can tell us the real deal :) – Michael Durrant Mar 05 '12 at 20:20
  • 99
    That gives me the difference in seconds NOT in days with rails v3/4 – 2called-chaos Jan 15 '14 at 14:50
  • 8
    As far as I can tell the behaviour remains the same in all recent versions of Ruby and ActiveSupport, include 2.0 and 4.1.0 respectively. `Time` objects do return seconds though. – Andrew France Apr 23 '14 at 23:04
  • 8
    to expand on @2called-chaos answer, to get days you would need (end_date - start_date)/1.day, which would give you a float. If you wanted to have full days only you might use ((end_date - start_date)/1.day).ceil – David K. Jul 15 '16 at 15:20
  • 4
    @David Except that the comment by @2called-chaos is mistakenly referring to `Time` objects, not `Date` objects. Perhaps you could update the naming in your comment to reflect that they are not dates? – Andrew France Jul 15 '16 at 21:06
  • 1
    @AndrewFrance - adding to Andrews comment, it seems some functions convert a Date object to a Time object. If you do (Date.today.advance(weeks: 1) - Date.today).to_i it will be in days, but if you add a .beginning_of_day after both the Date.todays, it will come out in seconds because it was converted to time – MingMan Jun 04 '17 at 12:24
  • 3
    `(end_date - start_date).to_i / 1.day` – Aryeh Beitz Jul 24 '19 at 08:33
142

Assuming that end_date and start_date are both of class ActiveSupport::TimeWithZone in Rails, then you can use:

(end_date.to_date - start_date.to_date).to_i
lee
  • 2,351
  • 1
  • 16
  • 18
  • 3
    If it has to do with table fields, this answer is the way to go; instead of the most rated one right here. – Ben Apr 05 '14 at 21:52
  • 1
    Doesn't work for `(Time.zone.now.to_date - 23.hours.ago.to_date).to_i`, it gives 1 and should be 0 – Yuri Ghensev Feb 04 '17 at 16:21
  • 4
    @YuriGhensev, it depends on when you run your example code, for example right now `Time.zone.now.to_date` returns "Wed, 15 Nov 2017", while `23.hours.ago.to_date` returns "Tue, 14 Nov 2017". The difference in number of days is and should be 1 unless you ran your code in the hour before midnight. – lee Nov 15 '17 at 20:01
40

Rails has some built in helpers that might solve this for you. One thing to keep in mind is that this is part of the Actionview Helpers, so they wont be available directly from the console.

Try this

<% 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
  • 2,981
  • 17
  • 18
  • 1
    @MaayanNaveh it should not be when you need the actual number for calculations. – Fedcomp Mar 18 '19 at 09:17
  • This question is one of those cases where the the question itself is better off asked differently. If you follow the other answers here you'll run into cases where sometimes you want weeks or years shown instead of days. This really should be accepted as the "right" Rails answer. – Dylan Pierce Dec 20 '19 at 18:41
36

to get the number of days in a time range (just a count of all days)

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

to get the number of days between 2 dates

(start_date...end_date).count
(start_date...end_date).to_a.size
#=> 31
a14m
  • 7,808
  • 8
  • 50
  • 67
35

I kept getting results in seconds, so this worked for me:

(Time.now - self.created_at) / 86400
thatdankent
  • 950
  • 8
  • 15
  • 1
    @Epigene `1.day` is not `ruby` as OP requested (in tags). It's `Rails` or more specific `active support` though `created_at` is basically a `Model` method in `Rails` so.. – Roko Sep 04 '17 at 12:03
20

None of the previous answers (to this date) gives the correct difference in days between two dates.

The one that comes closest is by thatdankent. A full answer would convert to_i and then divide:

(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

In the question's specific example, one should not parse to Date if the time passed is relevant. Use Time.parse instead.

Yuri Ghensev
  • 2,507
  • 4
  • 28
  • 45
  • This may not work as expected when the times cross a DST transition moving forward. In this case, the DST transitional day length is legitimately less than 24 hours, but because of the integer arithmetic that day will not be reflected at all. – PinnyM Jun 19 '19 at 15:45
9

Very late, but it may help others:

end_date.mjd - start_date.mjd

https://apidock.com/ruby/Date/mjd

Hint: This works only for Date objects, not Time objects.

BvuRVKyUVlViVIc7
  • 11,641
  • 9
  • 59
  • 111
Aaqib
  • 367
  • 3
  • 14
6

To have the number of whole days between two dates (DateTime objects):

((end_at - start_at).to_f / 1.day).floor
Dorian
  • 22,759
  • 8
  • 120
  • 116
  • Same DST issue as the answer that Yuri gave. Arithmetic with time is never as straightforward as you'd expect :) – PinnyM Jun 19 '19 at 15:47
4

The best solution currently that I've seen work consistently well is using the following pattern:

(end_date.beginning_of_day - Time.now.utc.beginning_of_day).seconds.in_days
ibrahimab
  • 131
  • 1
  • 6
2

To get the number of days difference by two dates:

(start.to_date...end.to_date).count - 1
or 
(end.to_date - start.to_date).to_i
giapnh
  • 2,950
  • 24
  • 20
0
(end_date - start_date)/1000/60/60/24

any one have best practice please comment below

Almokhtar
  • 135
  • 2
  • 10
-9
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
  • 13,214
  • 36
  • 93
  • 155