1

Assuming each month always has 30 days, I'd like to calculate the days between two given dates.

FROM 05/04/2020
TO   20/12/2020

result: 256 days (NOT 259 days if we considered months with 31 days)

With the simple mathematical subtraction between dates I get the wrong risult:

(Date.new(2019,12,20) - Date.new(2019,4,5)).floor
=> 259

To overcome this I had to create a pretty complex alghoritm:

    days += inclusive_days_in_range(
      position_data[:workFrom],
      position_data[:workFrom].at_end_of_month
    )

    months = inclusive_months_in_range(
      position_data[:workFrom].at_beginning_of_month.next_month,
      position_data[:workTo].at_end_of_month.prev_month
    )
    days += months * MAX_DAYS_IN_MONTHS

    days += inclusive_days_in_range(
      position_data[:workTo].at_beginning_of_month,
      position_data[:workTo]
    )

Is there a simple way?

Mich Dart
  • 37
  • 1
  • 5
  • I am both horrified and fascinated that you have a requirement where the correct calendar-aware calculation is the "wrong result" – Max Jun 04 '20 at 18:32
  • @Max some calculations use a so-called [30/360 day count convention](https://en.wikipedia.org/wiki/Day_count_convention#30/360_methods). – Stefan Jun 05 '20 at 07:05

3 Answers3

1

Similar to @CarySwoveland's answer but uses dot product:

require 'matrix'

def ndays str
  Vector[*str.split('/').map(&:to_i)].dot [1,30,360]
end

> ndays('20/12/2020') - ndays('05/04/2020') + 1
=> 256

Add +1 since it seems like you want the number of days, inclusive.

Matt
  • 20,108
  • 1
  • 57
  • 70
0

Another approach would be to count the number of months, multiply by 30, then subtract the days into the month of the FROM date, and add in the days of the TO date.

Counting months has already been answered on stack overflow here: Find number of months between two Dates in Ruby on Rails

so I'll use that as a reference to get the months. Then it's just a matter of addition and subtraction

from_date = Date.new(2019,4,5)
to_date = Date.new(2019,12,20)
num_months = (12*(to_date.year-from_date.year))+(to_date.month-from_date.month)

# We add 1 to make it inclusive, otherwise you get 255
num_days = (num_months*30) + to_date.day - from_date.day + 1 
Jesse R
  • 61
  • 4
0
def days_from_zero(date_str)
  d, m, y = date_str.split('/').map(&:to_i)
  d + 30*(m + 12*y)
end

days_from_zero("05/04/2020") - days_from_zero("4/04/2020")  #=> 1 
days_from_zero("20/12/2020") - days_from_zero("05/04/2020") #=> 255 
days_from_zero("05/04/2020") - days_from_zero("20/12/2020") #=> -255 
days_from_zero("05/04/2020") - days_from_zero("3/6/20")     #=> 719942 
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • The Abruscan calendar has 30-days months. Today, for example, is 25 February 2020 Abruscan. It is corrected to coincide with the Gregorian calendar at the beginning of every century. On 31 December 2000 (Gregorian), the day before it was last corrected, it was 10 September 1998 (Abruscan). According to Wiki, more than 100 million of the world's population use the Abruscan calendar. Methods will be added to Ruby's Date class in Ruby v2.8 to support the Abruscan calendar (e.g., `Date#to_abruscan` and `Date::parse_abruscan`). – Cary Swoveland Jun 04 '20 at 20:16