Skip to content

Commit

Permalink
Add Faker::Date.day_of_week_between (#2713)
Browse files Browse the repository at this point in the history
  • Loading branch information
aramvisser authored Aug 5, 2023
1 parent 7b30c86 commit d0ebdbe
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 0 deletions.
7 changes: 7 additions & 0 deletions doc/default/date.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ Faker::Date.between_except(from: '2014-09-23', to: '2015-09-25', excepted: '2015
# If used with Rails (the Active Support gem), additional options are available:
Faker::Date.between_except(from: 1.year.ago, to: 1.year.from_now, excepted: Date.today) #=> #<Date: 2014-10-03>

# Random date at given day(s) of week between dates
# Keyword arguments: day, from, to
Faker::Date.on_day_of_week_between(day: :tuesday, from: '2023-01-01', to: '2023-02-01') #=> "Tue, 10 Jan 2023"
Faker::Date.on_day_of_week_between(day: [:saturday, :sunday], from: '2023-01-01', to: '2023-02-01') #=> "Sun, 22 Jan 2023"
# If used with Rails (the Active Support gem), additional options are available:
Faker::Date.on_day_of_week_between(day: [:monday, :wednesday, :friday], from: 1.year.ago, to: 1.year.from_now) #=> "Mon, 20 Feb 2023"

# Random date in the future (up to maximum of N days)
# Keyword arguments: days
Faker::Date.forward(days: 23) # => "Fri, 03 Oct 2014"
Expand Down
48 changes: 48 additions & 0 deletions lib/faker/default/date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

module Faker
class Date < Base
DAYS_OF_WEEK = %i[sunday monday tuesday wednesday thursday friday saturday].freeze

class << self
##
# Produce a random date between two dates.
Expand Down Expand Up @@ -136,6 +138,52 @@ def in_date_period(month: nil, year: ::Date.today.year)
between(from: from, to: to).to_date
end

##
# Produce a random date at given day(s) of the week between two dates.
#
# @param day [Symbol, Array<Symbol>] # The day(s) of the week. See {DAYS_OF_WEEK}.
# @param from [Date, String] The start of the usable date range.
# @param to [Date, String] The end of the usable date range.
# @return [Date]
#
# @example if used with or without Rails (Active Support)
# Faker::Date.on_day_of_week_between(day: :tuesday, from: '2023-01-01', to: '2023-02-01') #=> #<Date: 2032-01-10>
#
# @example if used with Rails (Active Support)
# Faker::Date.on_day_of_week_between(day: [:saturday, :sunday], from: 1.month.ago, to: Date.today) #=> #<Date: 2014-09-24>
#
# @faker.version next
def on_day_of_week_between(day:, from:, to:)
days = [day].flatten
raise ArgumentError, 'Day of week cannot be empty' if days.empty?

# Convert given days of the week to numbers used by `Date#wday` method
numeric_weekdays = days.map do |d|
DAYS_OF_WEEK.index(d.to_sym.downcase) || raise(ArgumentError, "#{d} is not a valid day of the week")
end

from = get_date_object(from)
to = get_date_object(to)
date = Faker::Base.rand_in_range(from, to)

# If the initial date is not on one of the wanted days of the week...
unless numeric_weekdays.include? date.wday
# ...pick a date nearby that is on one of the wanted days of the week instead
date += sample(numeric_weekdays) - date.wday

# Move date 1 week earlier or later if the adjusted date is now outside the date range
date += 7 if date < from
date -= 7 if date > to

if date > to || date < from
raise ArgumentError,
"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."
end
end

date
end

private

def birthday_date(date, age)
Expand Down
37 changes: 37 additions & 0 deletions test/faker/default/test_faker_date.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,41 @@ def test_in_date_period_date
assert_equal date.year, year
end
end

def test_on_day_of_week_between
days = %i[tuesday saturday]
from = Date.parse('2012-01-01')
to = Date.parse('2012-02-01')

deterministically_verify -> { @tester.on_day_of_week_between(day: days, from: from, to: to) } do |date|
assert date >= from, "Expected >= \"#{from}\", but got #{date}"
assert date <= to, "Expected <= \"#{to}\", but got #{date}"
assert date.tuesday? || date.saturday?, "Expected #{date} to be Tuesday or Saturday, but was #{Faker::Date::DAYS_OF_WEEK[date.wday].capitalize}"
end
end

def test_unknown_day_of_week
error = assert_raise ArgumentError do
@tester.on_day_of_week_between(day: :unknown, from: '2012-01-01', to: '2013-01-01')
end

assert_equal 'unknown is not a valid day of the week', error.message
end

def test_empty_day_of_week
error = assert_raise ArgumentError do
@tester.on_day_of_week_between(day: [], from: '2012-01-01', to: '2013-01-01')
end

assert_equal 'Day of week cannot be empty', error.message
end

def test_day_of_week_outside_date_range
error = assert_raise ArgumentError do
@tester.on_day_of_week_between(day: :friday, from: '2012-01-01', to: '2012-01-03')
end

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.',
error.message
end
end

0 comments on commit d0ebdbe

Please sign in to comment.