Convert readable time string to datetime - ruby-on-rails

I have an alarm clock app, I want when the user enter's "5:00 PM", the system store it as datetime.
How do I convert '5:00 pm' to a datetime.
If it is already past 5:00 pm and the user enters '5:00 pm', the system should assume the user means tomorrow's '5:00 pm' and return the appropriate datetime.

Thanks to a previous answer, I figure out.
time_string = '5:00 pm' # mock of user input
date_time = DateTime.parse time_string
date_time += 1.day if Time.now > date_time
return date_time

Related

Datetime format Rails

I am having problem understanding datetime format in rails. I have stored a date which is called 'starts_at' and type is datetime using postman.
{
"reservation": {
"starts_at": "2020-1-7 7:00 pm",
"expires_at": "2020-1-7 9:00 pm"
}
}
I want to enter another date and want to validate the date I enter every time be in an interval of 120 minutes after.
So I tried plucking out 'starts_at' from my model 'reservations' and tried to loop through each 'starts_at' date and comparing their difference with my new entered dates' 'starts_at'.
# I have defined scope to pluck the 'starts_at' in reservation.rb
# scope :starts_at, -> { pluck(:starts_at) }
def create
Reservation.starts_at.each do |starts_at|
time_diffs = time_diff_in_minutes(date_time_conversion(starts_at) - params[:starts_at].to_datetime)
if time_diffs < 120
return
end
#reservation = Reservation.new(processed_params)
reservation.save
end
end
private
def date_time_conversion(starts_at)
starts_at.to_datetime
end
def time_diff_in_minutes(time_calc)
(time_calc * 24 * 60).to_s.to_i.abs
end
I have one value in database which has starts_at datetime = "2020-1-7 7:00 pm".
When I run debugger and checked the plucked value it has a format something like
Tue, 07 Jan 2020 18:00:00 +06 +06:00
And the format of the date I entered was something like
Tue, 07 Jan 2020 19:00:00 +0000
I want to understand what does +06 +6:00 means and how does postgresql database store datetime object and return format. Your help shall be highly appreciated. Thank you!

Parsing date using strftime

I have a problem parsing dates taken in from scraping a website using Nokogiri. I scrape the datetime using
#date = h4.at('time[itemprop="startDate"]')[:datetime]
This gives me 2015-04-28 19:30:00 UTC, which is inserted into my date column, of type "datetime".
Using strptime I am trying to parse the date into a "dd/mm" format, and enter it into my Rails table:
Date.strptime(#date, "%Y-%m-%d %H:%M:%S %Z").strftime("%m/%d/%Y")
#event=Event.new
#event.date= #date
Any help would be very much appreciated.
Here's some code that might help:
require 'date'
require 'time'
date = Date.strptime('2015-04-28 19:30:00 UTC', "%Y-%m-%d %H:%M:%S %Z")
# => #<Date: 2015-04-28 ((2457141j,0s,0n),+0s,2299161j)>
date.strftime('%m/%d/%y')
# => "04/28/15"
Parsing into a Date object stores only the year, month and day information.
datetime = DateTime.strptime('2015-04-28 19:30:00 UTC', "%Y-%m-%d %H:%M:%S %Z")
# => #<DateTime: 2015-04-28T19:30:00+00:00 ((2457141j,70200s,0n),+0s,2299161j)>
datetime.strftime('%m/%d/%y')
# => "04/28/15"
time = Time.strptime('2015-04-28 19:30:00 UTC', "%Y-%m-%d %H:%M:%S %Z")
# => 2015-04-28 19:30:00 UTC
time.strftime('%m/%d/%y')
# => "04/28/15"
Parsing into a DateTime, or Time object captures all the information.
The error you're seeing is often caused by a date string in a format you don't expect. That often happens when you expect a value in 'mm/dd/yy' order, but actually receive one in 'dd/mm/yy' order. This happens because the US uses 'mm/dd/yy' and most of the rest of the world uses 'dd/mm/yy':
date = Date.strptime('2015-28-04', '%Y-%m-%d')
# ~> -:7:in `strptime': invalid date (ArgumentError)
or
date = Date.strptime('28-04-2015', '%m-%d-%Y')
# ~> -:7:in `strptime': invalid date (ArgumentError)
You can work around that by using some rescue statements to try several different formats.
You don't want to use parse because it'll assume 'dd/mm/yyyy' and will blow up with US dates, and is slower because it tries multiple formats before giving up. So, using fixed formats you expect is the way to go but you need to search for your various formats of date/datetime strings you'll expect to find and write format strings to match. And, since you're scraping pages, it's possible to find a LOT of bad/malformed values so program defensively.
You don't need strftime and you can parse the date with parse. Just convert the string to a Date object and assign that to your ActiveRecord attribute:
#event = Event.new
#event.date = Date.parse('2015-04-28 19:30:00 UTC')

Ruby on Rails parsing time from datetime, not as string

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

How do I specify a time given a date object?

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.

Rails - How to change created_at time?

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

Resources