开发者

Best way to create random DateTime in Rails

What is the best way to generate a random DateTime in Ruby/Rails? Trying to create a nice seeds.rb file. Going to use it like so:

 Foo.create(name: Faker::Lorem.words, description: Faker::Lorem.se开发者_如何学Pythonntence, start_date: Random.date)


Here is how to create a date in the last 10 years:

rand(10.years).ago

You can also get a date in the future:

rand(10.years).from_now

Update – Rails 4.1+

Rails 4.1 has deprecated the implicit conversion from Numeric => seconds when you call .ago, which the above code depends on. See Rails PR #12389 for more information about this. To avoid a deprecation warning in Rails 4.1 you need to do an explicit conversion to seconds, like so:

rand(10.years).seconds.ago


Here are set of methods for generating a random integer, amount, time/datetime within a range.

def rand_int(from, to)
  rand_in_range(from, to).to_i
end

def rand_price(from, to)
  rand_in_range(from, to).round(2)
end

def rand_time(from, to=Time.now)
  Time.at(rand_in_range(from.to_f, to.to_f))
end

def rand_in_range(from, to)
  rand * (to - from) + from
end

Now you can make the following calls.

rand_int(60, 75)
# => 61

rand_price(10, 100)
# => 43.84

rand_time(2.days.ago)
# => Mon Mar 08 21:11:56 -0800 2010


I prefer use (1..500).to_a.rand.days.ago


You are using Faker; why not use one of the methods provided by Faker::Date?

# Random date between dates
# Keyword arguments: from, to
Faker::Date.between(from: 2.days.ago, to: Date.today) #=> "Wed, 24 Sep 2014"

# Random date between dates except for certain date
# Keyword arguments: from, to, excepted
Faker::Date.between_except(from: 1.year.ago, to: 1.year.from_now, excepted: Date.today) #=> "Wed, 24 Sep 2014"

# Random date in the future (up to maximum of N days)
# Keyword arguments: days
Faker::Date.forward(days: 23) # => "Fri, 03 Oct 2014"

# Random date in the past (up to maximum of N days)
# Keyword arguments: days
Faker::Date.backward(days: 14) #=> "Fri, 19 Sep 2014"

# Random birthday date (maximum age between 18 and 65)
# Keyword arguments: min_age, max_age
Faker::Date.birthday(min_age: 18, max_age: 65) #=> "Mar, 28 Mar 1986"

# Random date in current year
Faker::Date.in_date_period #=> #<Date: 2019-09-01>

# Random date for range of year 2018 and month 2
# Keyword arguments: year, month
Faker::Date.in_date_period(year: 2018, month: 2) #=> #<Date: 2018-02-26>

# Random date for range of current year and month 2
# Keyword arguments: month
Faker::Date.in_date_period(month: 2) #=> #<Date: 2019-02-26>

current Faker version: 2.11.0


Here is how to create a date in this month:

day = 1.times.map{ 0+Random.rand(30) }.join.to_i  
rand(day.days).ago


Another approach using DateTime's advance

def rand_date
  # return a random date within 100 days of today in both past and future directions.
  n = rand(-100..100)
  Date.today.advance(days: n)
end


This is what I use:

# get random DateTime in last 3 weeks
DateTime.now - (rand * 21)


other way:

(10..20).to_a.sample.years.ago


I haven't tried this myself but you could create a random integer between two dates using the number of seconds since epoch. For example, to get a random date for the last week.

end = Time.now
start = (end - 1.week).to_i
random_date = Time.at(rand(end.to_i - start)) + start

Of course you end up with a Time object instead of a DateTime but I'm sure you can covert from here.


As I already mentioned in another question I think the following code-snippet is more consisent regarding the data-types of the parameters and of the value to be returned. Stackoverflow: How to generate a random date in Ruby?

Anyway this uses the rand() method's internal logic what is the random Date or random Time within a span. Maybe someone has a more efficient way to set the default-parameter to (Time.now.to_date) of the method random_date, so it doesn't need this typecasting.

def random_time from = Time.at(0.0), to = Time.now
  rand(from..to)
end

# works quite similar to date :)
def random_date from = Date.new(1970), to = Time.now.to_date
  rand(from..to)
end

Edit: this code won't work before ruby v1.9.3


You can pass Time Range to rand

rand(10.weeks.ago..1.day.ago)

Output Example:

=> Fri, 10 Jan 2020 10:28:52 WIB +07:00


Without user faker (cause I'm using an old version of ruby):

Time.zone.now - rand(16..35.years) - rand(1..31).days


My 'ish' gem provides a nice way of handling this:

# plus/minus 5 min of input date
Time.now.ish
# override that time range like this
Time.now.ish(:offset => 1.year)

https://github.com/spilliton/ish

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜