ZebThan ZebThan - 1 month ago 11
Ruby Question

How to divide a time period into multiple periods

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, rounding the values up.

Here's an example:

I have period from
15.01.2016
to
10.06.2016
. I want to split it 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"]