ZebThan ZebThan - 1 month ago 13
Ruby Question

Dividing a time period into multiple periods

Let's say I have a time period in two variables (from start_date to end_date). Is there an easy way to split it into a smaller periods? Important thing is, I want results to be rounded up. If it's not clear what I mean, here's an example:

I have period from 15.01.2016 to 10.06.2016. I want to split in into months, so I will have six periods.
01.01.2016 - 31.01.2016

01.02.2016 - 31.02.2016

01.03.2016 - 31.03.2016

01.04.2016 - 31.04.2016

01.05.2016 - 31.05.2016

01.06.2016 - 31.06.2016

I want to include the time between 01.01.2016 and 15.01.2016 regardless of the fact, that it is not in the original period.

I've been looking for some ideas, but at this time it seems, that the only way is using the start date, and iterating (using DateAndTime::Calculations to determine the borders of intervals), until hitting the end date.

Answer
from = Date.parse('15.01.2016')
to   = Date.parse('10.06.2016')
(from..to).group_by(&:month).map do |group|
  group.last.first.beginning_of_month..group.last.last.end_of_month
end
# => [Fri, 01 Jan 2016..Sun, 31 Jan 2016,
#  Mon, 01 Feb 2016..Mon, 29 Feb 2016,
#  Tue, 01 Mar 2016..Thu, 31 Mar 2016,
#  Fri, 01 Apr 2016..Sat, 30 Apr 2016,
#  Sun, 01 May 2016..Tue, 31 May 2016,
#  Wed, 01 Jun 2016..Thu, 30 Jun 2016]

Or, map dates to strings, if you need string representation:

(from..to).group_by(&:month).map do |group|
  "#{group.last.first.beginning_of_month} - #{group.last.last.end_of_month}"
end

# => ["2016-01-01 - 2016-01-31",
#     "2016-02-01 - 2016-02-29",
#     "2016-03-01 - 2016-03-31",
#     "2016-04-01 - 2016-04-30",
#     "2016-05-01 - 2016-05-31",
#     "2016-06-01 - 2016-06-30"]

To get precisely what you want, you can format the string representation of the dates:

(from..to).group_by(&:month).map do |group|
  "#{group.last.first.beginning_of_month.strftime('%d-%m-%Y')} - #{group.last.last.end_of_month.strftime('%d-%m-%Y')}"
end
#=> ["01-01-2016 - 31-01-2016",
#    "01-02-2016 - 29-02-2016",
#    "01-03-2016 - 31-03-2016",
#    "01-04-2016 - 30-04-2016",
#    "01-05-2016 - 31-05-2016",
#    "01-06-2016 - 30-06-2016"]