Enumdate is a small enumerator library to expand recurring dates.
You can get the latest version from:
These are simple examples to create enumerables:
# June 2021
# Su Mo Tu We Th Fr Sa
# 1 2 3 4 5
# 6 7 8 9 10 11 12
# 13 14 15 16 17 18 19
# 20 21 22 23 24 25 26
# 27 28 29 30
#
start = Date.new(2021, 6, 1) # first Tuesday June
# June 1st every year:
Enumdate.yearly_by_monthday(start).lazy.map(&:to_s).take(3).force
# => ["2021-06-01", "2022-06-01", "2023-06-01"]
# First Tuesday June every year:
Enumdate.yearly_by_day(start).lazy.map(&:to_s).take(3).force
# => ["2021-06-01", "2022-06-07", "2023-06-06"]
# 1st monthday every month:
Enumdate.monthly_by_monthday(start).lazy.map(&:to_s).take(3).force
# => ["2021-06-01", "2021-07-01", "2021-08-01"]
# First Tuesday every month:
Enumdate.monthly_by_day(start).lazy.map(&:to_s).take(3).force
# => ["2021-06-01", "2021-07-06", "2021-08-03"]
# every Tuesday:
Enumdate.weekly(start).lazy.map(&:to_s).take(3).force
# => ["2021-06-01", "2021-06-08", "2021-06-15"]
# Everyday:
Enumdate.daily(start).lazy.map(&:to_s).take(3).force
# => ["2021-06-01", "2021-06-02", "2021-06-03"]
These constructor methods can take more complex parameters
such as month:
, mday:
, wday:
, nth:
, wkst:
, interval:
.
See the gem document for details.
This code makes infinite loop (every two years forever):
start = Date.new(2021, 6, 1)
Enumdate.yearly_by_monthday(start, interval: 2).each do |date|
puts date
end
Results:
2021-06-01 2023-06-01 2025-06-01 :
To clip the duration, you can use forward_to
and until
:
start = Date.new(2021, 6, 1)
Enumdate.yearly_by_monthday(start, interval: 2)
.forward_to(Date.new(2022, 1, 1))
.until(Date.new(2025, 12, 31))
.each do |date|
puts date
end
Results:
2023-06-01 2025-06-01
Note that the meaning of forward_to
is different from that of
changing the start
parameter.
start = Date.new(2022, 1, 1) # changed as if set forward_to
Enumdate.yearly_by_monthday(start, interval: 2)
.until(Date.new(2025, 12, 31))
.each do |date|
puts date
end
Results:
2022-01-01 2024-01-01
forward_to
and until
clip concrete occurrences without changing
the recurring pattern.
Sometimes, you may need to compose more complex recurring patterns. In this case, you can merge multiple enumerables:
first = Date.new(2021, 8, 4) # Wednesday
# Every Monday and Wednesday:
(Enumdate::EnumMerger.new << Enumdate.weekly(first) << Enumdate.weekly(first, wday: 1))
.lazy.map(&:to_s).take(4).force
# => ["2021-08-04", "2021-08-09", "2021-08-11", "2021-08-16"]
Add this line to your application’s Gemfile:
gem "enumdate"
And then execute:
$ bundle install
Or install it yourself as:
$ gem install enumdate
Bug reports and pull requests are welcome on GitHub at https://github.com/yoshinari-nomura/enumdate.
The gem is available as open source under the terms of the MIT License.