In my controller I have:
#konkurrencer = Rating.new(params[:kon])
#konkurrencer.save
#konkurrencer.konkurrencer.rating_score += params[:kon][:ratings].to_i
#konkurrencer.konkurrencer.ratings += 1
#konkurrencer.created_at = Time.now.strftime("%Y-%m-%d 00:00:00")
#konkurrencer.save
When I create a new item it the created_at column is:
2012-02-27 16:35:18
I would expect it to be:
2012-02-27 00:00:00
Your problem is that strftime only formats the time, it doesn't actually change the time.
So when you do Time.now, that returns the time. Strftime only changes the way that its represented.
If you wanted to change the created_at date to "2012-02-27 00:00:00", just pass that in to #koncurrencer.created_at
#koncurrencer.created_at = "2012-02-27 00:00:00"
That should do it.
In response to your question:
What you were doing should work just fine then. In fact you can just say:
#koncurrencer.created_at = Time.now
#koncurrencer.save
and that should work just fine.
If you wanted to always have the time be at the beginning of the day you could use Date.today instead of Time.now since that always returns the time component of the Date as "00:00:00"
Here is what you want:
#koncurrencer.created_at = Date.today
#koncurrencer.save
That should be more clear.
If you want to set the time always to "00:00:00", you can go by this:
t = Time.now
=> 2012-02-27 17:46:38 +0100
t2 = Time.parse("00:00:00", t)
=> 2012-02-27 00:00:00 +0100
Related
The goal is to compare timestamp to a range of times.
The range of times were defined in the rails schema as t.time for postgresql database. However the data returned upon querying the console attributes a date to the record's field...
start_time: "2000-01-01 08:00:00"
end_time: "2000-01-01 17:59:59"
Now if I want to validate whether a record created_at: "2017-03-18 03:44:04" is in the time range, I am also comparing the date, which is throwing the query into empty-array-land.
What rails or ruby tools can be used in this case in a database-agnostic manner?
def within_time_range?(start_time, end_time, time_check)
t = time_check[11..-1]
t >= start_time[11..-1] && t <= end_time[11..-1]
end
start_time = "2000-01-01 08:00:00"
end_time = "2000-01-01 17:59:59"
within_time_range?(start_time, end_time, "2017-03-18 03:44:04")
#=> false
within_time_range?(start_time, end_time, "2017-03-18 09:05:01")
#=> true
within_time_range?(start_time, end_time, "2017-03-18 19:05:01")
#=> false
Note
start_time[11..-1]
#=> "08:00:00"
I've used String#<= and String#>=, which are obtained from String#<=> and the inclusion of the module Comparable into the String class.
You could force every time object to be parsed at the same date (e.g. 1st of january 2000) :
require 'time'
def parse_time_not_date(string)
time = Time.parse(string)
Time.local(2000, 1, 1, time.hour, time.min, time.sec, time.usec)
end
start_time = parse_time_not_date("2000-01-01 08:00:00")
end_time = parse_time_not_date("2000-01-01 17:59:59")
my_time = parse_time_not_date("2017-03-18 03:44:04")
puts (start_time..end_time).cover?(my_time)
# false
puts (start_time..end_time).cover?(parse_time_not_date("2017-03-18 14:59"))
# true
I am going to chime in, as the discussion from the first answer was pertinent. Cary's answer works for that case. The question was ambivalent in terms of possible solutions: ruby or rails. And hence some potential gum ups. What follows is another way.
With rails, there is an issue in considering time zones. Calling an object of data type time actually stays in UTC. With date_time you are getting a string with + or - hours(or fraction thereof - yay Newfoundland!)
So, processing with rails, the proper way to handle UTC data is to assign it the rails application time zone with in_time_zone, chain to string and then extracting. Thus, comparisons ended up as:
p = Time.parse(#interruptions[0].pause.to_s[11,8])
p >= Time.parse(d_s.start_time.in_time_zone.to_s[11,8]) && p <= Time.parse(d_s.end_time.in_time_zone.to_s[11,8])
Note: could not get [11..-1] working in this context
I'm trying to extract the time component from a DateTime object (which is represented as "at" in my example). How do I do this, I am absolutely stumped? (I don't want to parse it to a string with strftime as i did here):
#session_date.at.strftime("%H:%M")
I would really like to return the hours and minutes as a Time object.
Is there a specific reason you want a Time object?
Just so we're clear, the Time class in Ruby isn't just "DateTime without the date." As "What's the difference between DateTime and Time in Ruby?" explains, "Time is a wrapper around POSIX-standard time_t, or seconds since January 1, 1970." Like DateTime, a Time object still has year, month, and day, so you don't really gain anything by using Time instead. There's not really a way to represent just hour and minute using either Time or DateTime.
The best you could do with Time, I think, would be this:
date_time = DateTime.now
seconds = date_time.hour * 60 * 60 + date_time.minute * 60
time = Time.at(seconds)
# => 1970-01-01 09:58
...but then you still have to call time.hour and time.min to get at the hour and minute.
If you're just looking for a lightweight data structure to represent an hour and minute pair, though, you might as well just roll your own:
HourAndMinute = Struct.new(:hour, :minute) do
def self.from_datetime(date_time)
new(date_time.hour, date_time.minute)
end
end
hm = HourAndMinute.from_datetime(DateTime.now)
# => #<struct HourAndMinute hour=15, minute=58>
hm.to_h
# => { :hour => 15, :minute => 58 }
hm.to_a
# => [ 15, 58 ]
Edit re:
I have a variable that stores an appointment -- this variable is a DateTime object. I have two table fields that store the start and end times of a location. I need to check if the time scheduled for that appointment lies between the start and end times.
Ah, it seems you had a bit of a XY problem. This makes a lot more sense now.
Absent any more information, I'm going to assume your "fields that store the start and end times of a location" are MySQL TIME columns called start_time and end_time. Given MySQL TIME columns, Rails casts the values to Time objects with the date component set to 1/1/2000. So if your database has the values start_time = '09:00' and end_time = '17:00', Rails will give you Time objects like this:
start_time = Time.new(2000, 1, 1, 9, 0) # => 2000-01-01 09:00:00 ...
end_time = Time.new(2000, 1, 1, 17, 0) # => 2000-01-01 17:00:00 ...
Now you say your appointment time is a DateTime, so let's call it appointment_datetime and suppose it's at 10:30am tomorrow:
appointment_datetime = DateTime.new(2014, 11, 18, 10, 30) # => 2014-11-18 10:30:00 ...
So now to rephrase your question: How do we tell if the time part of appointment_datetime is between the time part of start_time and end_time. The answer is, we need to either change the date part of start_time and end_time to match the date part of appointment_datetime, or the other way around. Since it's easier to change one thing than two, let's do it the other way around and change appointment_datetime to match start_time and end_time (and, since those two are Time objects, we'll create a Time object):
appointment_time = DateTime.new(2000, 1, 1, appointment_datetime.hour, appointment_datetime.minute)
# => 2000-01-01 10:30:00 ...
Now we can compare them directly:
if appointment_time >= start_time && appointment_time <= end_time
puts "Appointment time is good!"
end
# Or, more succinctly:
if (start_time..end_time).cover?(appointment_time)
puts "Appointment time is good!"
end
You would, of course, want to wrap all of this up in a method, perhaps in your Location model (which, again, I'm assuming has start_time and end_time attributes):
class Location < ActiveRecord::Base
# ...
def appointment_time_good?(appointment_datetime)
appointment_time = DateTime.new(2000, 1, 1,
appointment_datetime.hour, appointment_datetime.minute)
(start_time..end_time).cover?(appointment_time)
end
end
location = Location.find(12) # => #<Location id: 12, ...>
location.appointment_time_good?(appointment_time) # => true
I hope that's helpful!
P.S. Another way to implement this would be to ditch the date/time objects entirely and do a straight numeric comparison:
def appointment_time_good?(appointment_datetime)
appointment_hour_min = [ appointment_datetime.hour, appointment_datetime.minute ]
appointment_hour_min >= [ start_time.hour, start_time.min ]
&& appointment_hour_min <= [ end_time.hour, end_time.min ]
end
If you have a DateTime object:
date_time = DateTime.now
date_time.hour
# => 16
date_time.minute
# => 1
If you are looking for the Time since now in words (which is common in Rails apps), then this may be a good read: http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-time_ago_in_words
I am trying to create an object which has both a date field and a time field. I'd like the time field to be generated based on the date in the date field. For example:
SampleObject.new(
date = Date.today #Sat, 28 Dec 2013
time = Date.today.at(5:00pm EST) #Sat, 28 Dec 2013 2013-12-28 17:00:00 -0500 Not valid ruby syntax)
)
How can I make time = line work as intended?
I'd do something like:
DateTime.parse Date.today.to_s + ' 5pm'
#<DateTime: 2013-12-28T17:00:00+00:00 ((2456655j,61200s,0n),+0s,2299161j)>
I am interpreting this question as "a way to set the time of the day on a given date to a given time".
One way you could do it is as follows:
def set_date_and_time(date = Date.today, time = Time.now)
this_day = [date.year, date.month, date.day]
this_time = [time.hour, time.min, time.sec]
Time.new(*this_day, *this_time)
end
Hope this helps.
I have a Location that can have Events. I want to have an upcoming_events method but want it to round down such that if someone looks at 10pm at night, it will show todays events. I have this:
def upcoming_events
d=Time.new
d.strftime("%m-%d-%Y")
l=Event.where('location_id=? and start_datetime>?',self.id, d)
end
I gets converted down correctly but in d.strftime but the query is:
SELECT `events`.* FROM `events` WHERE (location_id=301 and start_datetime>'2012-06-20 02:49:23')
Any idea how to just get it to do '2012-06-20'?
Calling strftime does essentially nothing here, since it doesn't change the d object in any way.
Anyway, Rails provides the method beginning_of_day on DateTime (as well as Date & Time) that does exactly what you want:
d = Time.now #=> 2012-06-19 23:05:54 -0400
d.beginning_of_day #=> 2012-06-19 00:00:00 -0400
So just change your code to:
Event.where('location_id=? and start_datetime>?', self.id, d.beginning_of_day)
I think you actually meant "%Y-%m-%d" vice "%m-%d-%Y" since you wanted '2012-06-20'. As such, try the following:
def upcoming_events
d=Time.new
l=Event.where('location_id=? and start_datetime>?', self.id, d.strftime("%Y-%m-%d"))
end
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.sentence, 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