I'm looking for an elegant way to make a range of datetimes, e.g.:
def DateRange(start_time, end_time, period) ... end >> results = DateRange(DateTime.new(2013,10,10,12), DateTime.new(2013,10,10,14), :hourly) >> puts results 2013-10-10:12:00:00 2013-10-10:13:00:00 2013-10-10:14:00:00
The step should be configurable, e.g. hourly, daily, monthly.
I'd like times
to be inclusive, i.e. include end_time
.
Additional requirements are:
:advance
, to handle things like variable number of days in months.Is there an elegant solution?
Ranges as Sequences Sequences have a start point, an end point, and a way to produce successive values in the sequence. Ruby creates these sequences using the ''..'' and ''...'' range operators. The two-dot form creates an inclusive range, while the three-dot form creates a range that excludes the specified high value.
Yes, the method does look like an array class. However, you need to add a pair of parenthesis to let Ruby know you are using the Array method and not the class. The resulting value is the range of values in an array format.
Using @CaptainPete's base, I modified it to use the ActiveSupport::DateTime#advance
call. The difference comes into effect when the time intervals are non-uniform, such as `:month" and ":year"
require 'active_support/all' class RailsDateRange < Range # step is similar to DateTime#advance argument def every(step, &block) c_time = self.begin.to_datetime finish_time = self.end.to_datetime foo_compare = self.exclude_end? ? :< : :<= arr = [] while c_time.send( foo_compare, finish_time) do arr << c_time c_time = c_time.advance(step) end return arr end end # Convenience method def RailsDateRange(range) RailsDateRange.new(range.begin, range.end, range.exclude_end?) end
My method also returns an Array
. For comparison's sake, I altered @CaptainPete's answer to also return an array:
RailsDateRange((4.years.ago)..Time.now).every(years: 1) => [Tue, 13 Oct 2009 11:30:07 -0400, Wed, 13 Oct 2010 11:30:07 -0400, Thu, 13 Oct 2011 11:30:07 -0400, Sat, 13 Oct 2012 11:30:07 -0400, Sun, 13 Oct 2013 11:30:07 -0400] DateRange((4.years.ago)..Time.now).every(1.year) => [2009-10-13 11:30:07 -0400, 2010-10-13 17:30:07 -0400, 2011-10-13 23:30:07 -0400, 2012-10-13 05:30:07 -0400, 2013-10-13 11:30:07 -0400]
RailsDateRange((5.months.ago)..Time.now).every(months: 1) => [Mon, 13 May 2013 11:31:55 -0400, Thu, 13 Jun 2013 11:31:55 -0400, Sat, 13 Jul 2013 11:31:55 -0400, Tue, 13 Aug 2013 11:31:55 -0400, Fri, 13 Sep 2013 11:31:55 -0400, Sun, 13 Oct 2013 11:31:55 -0400] DateRange((5.months.ago)..Time.now).every(1.month) => [2013-05-13 11:31:55 -0400, 2013-06-12 11:31:55 -0400, 2013-07-12 11:31:55 -0400, 2013-08-11 11:31:55 -0400, 2013-09-10 11:31:55 -0400, 2013-10-10 11:31:55 -0400]
RailsDateRange((4.years.ago)..Time.now).every(years: 1) => [Tue, 13 Oct 2009 11:30:07 -0400, Wed, 13 Oct 2010 11:30:07 -0400, Thu, 13 Oct 2011 11:30:07 -0400, Sat, 13 Oct 2012 11:30:07 -0400, Sun, 13 Oct 2013 11:30:07 -0400] DateRange((4.years.ago)..Time.now).every(1.year) => [2009-10-13 11:30:07 -0400, 2010-10-13 17:30:07 -0400, 2011-10-13 23:30:07 -0400, 2012-10-13 05:30:07 -0400, 2013-10-13 11:30:07 -0400]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With