Skip to content

Commit d0ebdbe

Browse files
authored
Add Faker::Date.day_of_week_between (#2713)
1 parent 7b30c86 commit d0ebdbe

File tree

3 files changed

+92
-0
lines changed

3 files changed

+92
-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.
@@ -136,6 +138,52 @@ def in_date_period(month: nil, year: ::Date.today.year)
136138
between(from: from, to: to).to_date
137139
end
138140

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

141189
def birthday_date(date, age)

test/faker/default/test_faker_date.rb

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,41 @@ def test_in_date_period_date
212212
assert_equal date.year, year
213213
end
214214
end
215+
216+
def test_on_day_of_week_between
217+
days = %i[tuesday saturday]
218+
from = Date.parse('2012-01-01')
219+
to = Date.parse('2012-02-01')
220+
221+
deterministically_verify -> { @tester.on_day_of_week_between(day: days, from: from, to: to) } do |date|
222+
assert date >= from, "Expected >= \"#{from}\", but got #{date}"
223+
assert date <= to, "Expected <= \"#{to}\", but got #{date}"
224+
assert date.tuesday? || date.saturday?, "Expected #{date} to be Tuesday or Saturday, but was #{Faker::Date::DAYS_OF_WEEK[date.wday].capitalize}"
225+
end
226+
end
227+
228+
def test_unknown_day_of_week
229+
error = assert_raise ArgumentError do
230+
@tester.on_day_of_week_between(day: :unknown, from: '2012-01-01', to: '2013-01-01')
231+
end
232+
233+
assert_equal 'unknown is not a valid day of the week', error.message
234+
end
235+
236+
def test_empty_day_of_week
237+
error = assert_raise ArgumentError do
238+
@tester.on_day_of_week_between(day: [], from: '2012-01-01', to: '2013-01-01')
239+
end
240+
241+
assert_equal 'Day of week cannot be empty', error.message
242+
end
243+
244+
def test_day_of_week_outside_date_range
245+
error = assert_raise ArgumentError do
246+
@tester.on_day_of_week_between(day: :friday, from: '2012-01-01', to: '2012-01-03')
247+
end
248+
249+
assert_equal 'There is no Friday between 2012-01-01 and 2012-01-03. Increase the from/to date range or choose a different day of the week.',
250+
error.message
251+
end
215252
end

0 commit comments

Comments
 (0)