Ruby: Is Date greater than a particular date - ruby

I am trying to do a date comparison like so:
if date > "Sept 22"
#do stuff
else
#do other stuff
end
I just can't think of how to do this in Ruby (well at least looking at a particular date).

Normal comparison operators work with dates too:
require 'date'
date = Date.new(2012,3,3)
if date > Date.new(2011,4,4)
# do whatever
end

Related

Refactor a convoluted date method

My users choose some dates from a datepicker, which is saving the dates in this format:
"06/05/2019"
I'd like the date to display back in this format: "Wednesday, June 5"
I'm struggling a bit with Ruby's date methods. This method that I put together is working, but I'm sure if somebody could help me trim this to one line, then I would understand Ruby's date methods better.
def friendly_date(input)
orig_due_date = Date.strptime(input, "%m/%d/%Y")
orig_due_date.strftime("%A, %B %e")
end
Thank you in advance for any insight.
I can't see any improvement except avoiding the local variable
def friendly_date(input)
Date.strptime(input, "%m/%d/%Y").strftime("%A, %B %e")
end
You could write...
def friendly_date(input)
Date.strptime(input, "%m/%d/%Y").strftime("%A, %B %e")
end
...but this would not be an improvement. It's doing two operations, parse and format, so it's easier to understand as two lines. Naming the variable just date is an improvement because inside this function its just a date.
def friendly_date(input)
date = Date.strptime(input, "%m/%d/%Y")
date.strftime("%A, %B %e")
end
A better way to simplify your code is to have one function parsing what the datepicker gives you into a Date, and other to format any Date.
def date_from_datepicker(from_datepicker)
Date.strptime(input, "%m/%d/%Y")
end
def friendly_date(date)
date.strftime("%A, %B %e")
end
Now you have a generic function to transform the datepicker format into a Date. And a generic function to transform any Date or Time into your preferred format.
Now you'd immediately normalize the output from your datepicker into a Date and only transform it into your friendly format as necessary. This will make working with all dates easier by having the be Date objects for as long as possible.
input_date = date_from_datepicker(params['date'])
...work with it like any other Date...
puts friendly_date(input_date)
# And it works on any Date.
puts friendly_date(some_other_date)

Ruby: comparing dates of two Time objects

What is the best way to compare the dates of two Time objects in Ruby?
I have two objects such as:
time_1 = Time.new(2012,12,10,10,10)
time_2 = Time.new(2012,12,11,10,10)
In this example, the date comparison should return false.
Otherwise, same date, but different times, should return true:
time_1 = Time.new(2012,12,10,10,10)
time_2 = Time.new(2012,12,10,11,10)
I have tried to use .to_date that works for DateTime objects, but it is not supported by Time.
Just require the 'date' part of stdlib, then compare the dates:
require "date"
time1.to_date == time2.to_date
Job done.
I have verified that this works for me:
time_1.strftime("%F") == time_2.strftime("%F")
The %F format returns the date portion only.
Maybe just testing this way:
time_1.year == time_2.year && time_1.yday == time_2.yday
It'll be less resource consuming than string comparison.
monkey patch the class Time with this method and it i'll be nice to read
class Time
def date_compare(time)
year == time.year && yday == time_2.yday
end
end
time_1.date_compare time_2
to_date works just fine in ruby 2.0 and ruby 1.9.3 and ruby 1.9.2 http://ruby-doc.org/stdlib-1.9.2/libdoc/date/rdoc/Time.html
>> time_1.to_date
=> #<Date: 2012-12-10 ((2456272j,0s,0n),+0s,2299161j)>
but it's not in the stdlib of ruby 1.8.7 http://ruby-doc.org/stdlib-1.8.7/libdoc/time/rdoc/Time.html - but then, your way of creating a time object doesn't work in that version either:
> time_1 = Time.new(2012,12,10,10,10)
ArgumentError: wrong number of arguments (5 for 0)

Ruby, Recursion Method

I have a method that is basically a loop and it calls itself at the end each time. What is the best way for the method to not call itself when the date reaches a certain point? Each iteration through adds 1 day and basically processes stats for that day. It looks like the below:
def loop(start_day)
date = start_day
#do a bunch of stuff
date = date +1.day
if date > Time.now
puts "loop should be over"
end
loop(date)
end
Each iteration through adds 1 day
That's not true for the code you've posted. In your code you add 1 day to the start date once and then you keep processing the same date over and over again because you recurse on the old date (start_date), not the incremented date (date).
What is the best way for the method to not call itself when the date reaches a certain point?
Just put the recursive call inside an if or, in this case, inside of the else of the if that you already have.
Since you set date to start_date immediately, it seems there's no point in having both. Here's the more canonical form of doing recursion:
def loop(date)
return if date > Time.now
#do a bunch of stuff
loop(date + 1.day)
end
Update: If it's not obvious to you that recursion isn't necessary here, in real life, it would make more sense to do something like this:
def process_from(date)
while date <= Time.now
# Process date
date += 1.day
end
end
What about this?
def loop(start_day)
return "loop should be over" if start_day >= Time.now
#...
loop(modified_date)
end
or...
def loop(start_day)
date = start_day.dup
time = Time.now
date += 1.day while date <= time
'loop should be over'
end
It seems like you want to iterate over all days from starting date to today. Then maybe this is even more simple:
def map_date(date)
(date.to_date..Date.today).map do |d|
d.strftime("Today is %A")
end
end
You must have base case (stop case) for recursive function;
example:
def loop(date)
if date == certain_point
return [something_for_stop]
end
loop(date - 1)
end

Ruby: how to get at meridian in Time objects?

If I've got a time object:
t = Time.now
and I want to know if that time is AM or PM, right now the only way I can figure to do this is:
t.strftime("%p") == "PM"
Now, that %p is getting interpolated from something, right? Is there another way to get to it?
I ask because I'm doing some time formatting where I want to display a time range like:
"9:00 AM - 5:00 PM"
"4:00 - 5:30 PM"
"10:15 - 11:45 AM"
Right now I have to do this checking the string value of strftime, but I'd prefer to write something like:
if start_time.am? && end_time.pm? || start_time.pm? && end_time.am?
...instead of the much more verbose strftime string comparisons I'm doing now.
Based on http://www.ruby-doc.org/core-1.9.3/Time.html, I do not believe there is any other way. You could monkey-patch Time to save you some tedious strftime, however:
class Time
def meridian
self.strftime('%p')
end
def am?
self.meridian == 'AM'
end
def pm?
self.meridian == 'PM'
end
end
There isn't anything as nice as time.am? but you can use time.hour < 12 instead.
class Time
def am?
self.hour.in? (0..12)
end
def pm?
self.hour.in? (13..24)
end
end

Step in a Date Interval

I trying to do a each on a Date interval with Rails 3.2.. something like this:
(1.months.ago.to_date..5.months.from_now.to_date).step(1.month).each do |date|
puts date.strftime('%m/%Y')
end
But, the step(1.month) does not work.. seems like it get the first month (ex: today is august, it will return jully) and does not iterate the other months..
Is there a way to do that?
Thanks
You are using Date as your iteration base, and 1.month translates (behind the scenes) into seconds I believe.
When you add to the Date object, it's in days, thus:
Date.today + 1 would be tomorrow
Thus, in your example, you are trying to step 2592000 days.
What you probably want is something more like:
(1.months.ago.to_date..5.months.from_now.to_date).step(30).each { |date| puts date.strftime('%m/%Y') }
If you are looking for the iterator to be smart enough to know how many days are in each month when you are "stepping" that's not going to happen. You will need to roll that on your own.
You can intelligently iterate through months by using the >> operator, so:
date = Date.today
while date < 5.months.from_now.to_date do
puts date.strftime('%m/%Y')
date = date>>1
end
how about this:
current_date, end_date = Date.today, 5.monthes.from_now.to_date
while current_date <= end_date
puts current_date
current_date = current_date.next_month
end

Resources