Skip to content

Commit 486fcde

Browse files
committed
Add Faker::Date.day_of_week_between
1 parent 0f47ff0 commit 486fcde

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

doc/default/date.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ Faker::Date.between_except(from: '2014-09-23', to: '2015-09-25', excepted: '2015
1313
# If used with Rails (the Active Support gem), additional options are available:
1414
Faker::Date.between_except(from: 1.year.ago, to: 1.year.from_now, excepted: Date.today) #=> #<Date: 2014-10-03>
1515

16+
# Random date at given day(s) of week between dates
17+
# Keyword arguments: day, from, to
18+
Faker::Date.on_day_of_week_between(day: :tuesday, from: '2023-01-01', to: '2023-02-01') #=> "Tue, 10 Jan 2023"
19+
Faker::Date.on_day_of_week_between(day: [:saturday, :sunday], from: '2023-01-01', to: '2023-02-01') #=> "Sun, 22 Jan 2023"
20+
# If used with Rails (the Active Support gem), additional options are available:
21+
Faker::Date.on_day_of_week_between(day: [:monday, :wednesday, :friday], from: 1.year.ago, to: 1.year.from_now) #=> "Mon, 20 Feb 2023"
22+
1623
# Random date in the future (up to maximum of N days)
1724
# Keyword arguments: days
1825
Faker::Date.forward(days: 23) # => "Fri, 03 Oct 2014"

lib/faker/default/date.rb

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
module Faker
44
class Date < Base
5+
DAYS_OF_WEEK = %i[sunday monday tuesday wednesday thursday friday saturday].freeze
6+
57
class << self
68
##
79
# Produce a random date between two dates.
@@ -128,6 +130,52 @@ def in_date_period(month: nil, year: ::Date.today.year)
128130
between(from: from, to: to).to_date
129131
end
130132

133+
##
134+
# Produce a random date at given day(s) of the week between two dates.
135+
#
136+
# @param day [Symbol, Array<Symbol>] # The day(s) of the week. See {DAYS_OF_WEEK}.
137+
# @param from [Date, String] The start of the usable date range.
138+
# @param to [Date, String] The end of the usable date range.
139+
# @return [Date]
140+
#
141+
# @example if used with or without Rails (Active Support)
142+
# Faker::Date.on_day_of_week_between(day: :tuesday, from: '2023-01-01', to: '2023-02-01') #=> #<Date: 2032-01-10>
143+
#
144+
# @example if used with Rails (Active Support)
145+
# Faker::Date.on_day_of_week_between(day: [:saturday, :sunday], from: 1.month.ago, to: Date.today) #=> #<Date: 2014-09-24>
146+
#
147+
# @faker.version next
148+
def on_day_of_week_between(day:, from:, to:)
149+
days = [day].flatten
150+
raise ArgumentError, 'Day of week cannot be empty' if days.empty?
151+
152+
# Convert given days of the week to numbers used by `Date#wday` method
153+
numeric_weekdays = days.map do |d|
154+
DAYS_OF_WEEK.index(d.to_sym.downcase) || raise(ArgumentError, "#{d} is not a valid day of the week")
155+
end
156+
157+
from = get_date_object(from)
158+
to = get_date_object(to)
159+
date = Faker::Base.rand_in_range(from, to)
160+
161+
# If the date is not on one of the wanted days of the week...
162+
unless numeric_weekdays.include? date.wday
163+
# ...pick a date nearby that is on one of the wanted days of the week instead
164+
date += sample(numeric_weekdays) - date.wday
165+
166+
# Move date 1 week earlier or later if the adjusted date is now outside the date range
167+
date += 7 if date < from
168+
date -= 7 if date > to
169+
170+
if date > to || date < from
171+
raise ArgumentError,
172+
"There is no #{DAYS_OF_WEEK[date.wday].capitalize} between #{from} and #{to}"
173+
end
174+
end
175+
176+
date
177+
end
178+
131179
private
132180

133181
def birthday_date(date, age)

test/faker/default/test_faker_date.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,4 +191,42 @@ def test_in_date_period_date
191191
assert_equal date.year, year
192192
end
193193
end
194+
195+
def test_on_day_of_week_between
196+
days = %i[tuesday saturday]
197+
from = Date.parse('2012-01-01')
198+
to = Date.parse('2012-02-01')
199+
200+
100.times do
201+
random_date = @tester.on_day_of_week_between(day: days, from: from, to: to)
202+
203+
assert random_date >= from, "Expected >= \"#{from}\", but got #{random_date}"
204+
assert random_date <= to, "Expected <= \"#{to}\", but got #{random_date}"
205+
assert random_date.tuesday? || random_date.saturday?, "Expected #{random_date} to be Tuesday or Saturday, but was #{Faker::Date::DAYS_OF_WEEK[random_date.wday].capitalize}"
206+
end
207+
end
208+
209+
def test_unknown_day_of_week
210+
error = assert_raise ArgumentError do
211+
@tester.on_day_of_week_between(day: :unknown, from: '2012-01-01', to: '2013-01-01')
212+
end
213+
214+
assert_equal 'unknown is not a valid day of the week', error.message
215+
end
216+
217+
def test_empty_day_of_week
218+
error = assert_raise ArgumentError do
219+
@tester.on_day_of_week_between(day: [], from: '2012-01-01', to: '2013-01-01')
220+
end
221+
222+
assert_equal 'Day of week cannot be empty', error.message
223+
end
224+
225+
def test_day_of_week_outside_date_range
226+
error = assert_raise ArgumentError do
227+
@tester.on_day_of_week_between(day: :friday, from: '2012-01-01', to: '2012-01-03')
228+
end
229+
230+
assert_equal 'There is no Friday between 2012-01-01 and 2012-01-03', error.message
231+
end
194232
end

0 commit comments

Comments
 (0)