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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209
|
# frozen_string_literal: true
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.
#
# @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.between(from: '2014-09-23', to: '2014-09-25') #=> #<Date: 2014-09-24>
#
# @example if used with Rails (Active Support)
# Faker::Date.between(from: 2.days.ago, to: Date.today) #=> #<Date: 2014-09-24>
#
# @faker.version 1.0.0
def between(from:, to:)
from = get_date_object(from)
to = get_date_object(to)
Faker::Base.rand_in_range(from, to)
end
##
# Produce a random date between two dates.
#
# @param from [Date, String] The start of the usable date range.
# @param to [Date, String] The end of the usable date range.
# @param excepted [Date, String] A date to exclude.
# @return [Date]
#
# @example if used with or without Rails (Active Support)
# Faker::Date.between_except(from: '2014-09-23', to: '2015-09-25', excepted: '2015-01-24') #=> #<Date: 2014-10-03>
#
# @example if used with Rails (Active Support)
# Faker::Date.between_except(from: 1.year.ago, to: 1.year.from_now, excepted: Date.today) #=> #<Date: 2014-10-03>
#
# @faker.version 1.6.2
def between_except(from:, to:, excepted:)
raise ArgumentError, 'From date, to date and excepted date must not be the same' if from == to && to == excepted
excepted = get_date_object(excepted)
loop do
date = between(from: from, to: to)
break date.to_date if date != excepted
end
end
##
# Produce a random date in the future (up to N days).
#
# @param from [Integer] The start of the usable forward date range.
# @param days [Integer] The maximum number of days to go into the future.
# @return [Date]
#
# @example if used with or without Rails (Active Support)
# Faker::Date.forward(days: 23) #=> #<Date: 2014-10-03>
#
# @example if used with Rails (Active Support)
# Faker::Date.forward(from: Date.current, days: 17) #=> #<Date: 2022-06-22>
#
# @example if used with or without Rails (Active Support)
# Faker::Date.forward(from: '2022-06-03', days: 10) #=> #<Date: 2022-10-13>
#
# @faker.version 1.0.0
def forward(from: ::Date.today, days: 365)
start_date = get_date_object(from)
since = start_date + 1
to = start_date + days
between(from: since, to: to).to_date
end
##
# Produce a random date in the past (up to N days).
#
# @param days [Integer] The maximum number of days to go into the past.
# @return [Date]
#
# @example
# Faker::Date.backward(days: 14) #=> #<Date: 2019-09-12>
#
# @faker.version 1.0.0
def backward(days: 365)
from = ::Date.today - days
to = ::Date.today - 1
between(from: from, to: to).to_date
end
##
# Produce a random date in the past (up to N days).
#
# @param min_age [Integer] The minimum age that the birthday would imply.
# @param max_age [Integer] The maximum age that the birthday would imply.
# @return [Date]
#
# @example
# Faker::Date.birthday(min_age: 18, max_age: 65) #=> #<Date: 1986-03-28>
#
# @faker.version 1.4.3
def birthday(min_age: 18, max_age: 65)
t = ::Date.today
from = birthday_date(t, max_age)
to = birthday_date(t, min_age)
between(from: from, to: to).to_date
end
##
# Produces a date in the year and/or month specified.
#
# @param month [Integer] represents the month of the date
# @param year [Integer] represents the year of the date
# @return [Date]
#
# @example
# Faker::Date.in_date_period #=> #<Date: 2019-09-01>
#
# @example
# Faker::Date.in_date_period(year: 2018, month: 2) #=> #<Date: 2018-02-26>
#
# @example
# Faker::Date.in_date_period(month: 2) #=> #<Date: 2019-02-26>
#
# @faker.version 2.13.0
def in_date_period(month: nil, year: ::Date.today.year)
from = ::Date.new(year, month || 1, 1)
to = ::Date.new(year, month || 12, ::Date.civil(year, month || 12, -1).day)
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)
year = date.year - age
day =
if date.day == 29 && date.month == 2 && !::Date.leap?(year)
28
else
date.day
end
::Date.new(year, date.month, day)
end
def get_date_object(date)
date = ::Date.parse(date) if date.is_a?(::String)
date = date.to_date if date.respond_to?(:to_date)
date
end
end
end
end
|