Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Faker::Date.day_of_week_between #2713

Merged
merged 1 commit into from
Aug 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
aramvisser marked this conversation as resolved.
Show resolved Hide resolved

class << self
##
# Produce a random date between two dates.
Expand Down Expand Up @@ -128,6 +130,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 @@ -191,4 +191,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|
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

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.',
aramvisser marked this conversation as resolved.
Show resolved Hide resolved
error.message
end
end