Finding days between 2 days in Ruby on Rails - ruby-on-rails

I am facing some problem in finding the days between 2 dates.
The scenario is as follow :
time = Time.new
enddate_timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
startdate = #logInfo.updated_at #here updated_at is the column in the db .
What is the best way to find the days ?

Post.where(["date(created_at) BETWEEN ? AND ?", Date.yesterday, Date.tomorrow]
More details: http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-where

There are several possible solutions. A possibility is to create a Range with the dates, then convert the range into an array
# set the boundaries
today = Time.current
past = 5.days.ago
Note that both boundaries are time instances. We should cast them into dates. I used time(s) because your column is a time.
range = past.to_date..today.to_date
# => Sun, 29 Dec 2013..Fri, 03 Jan 2014
Use to_a to expand the range getting all the days
range.to_a
# => [Sun, 29 Dec 2013, Mon, 30 Dec 2013, Tue, 31 Dec 2013, Wed, 01 Jan 2014, Thu, 02 Jan 2014, Fri, 03 Jan 2014]
range.count
# => 6
You can also enumerate them
range.each { |day| puts day.day }
29
30
31
1
2
3

now = Time.now
future = Time.now + 100 days
while now < future
now = now + 1.day
puts now
end
This will give you the dates, not the days count.

(startdate.beginning_of_day..enddate_timestamp.to_time.beginning_of_day).step(1.day) do |day|
puts day
end
P.S: Performance wise it's not good.

Related

Ruby(/Rails) dates - bi-weekly and quarterly DateTime ranges

I am trying to do reporting for a specific period, those periods supported being:
"today": start = DateTime.now.beginning_of_day; end = start.end_of_day
"this week": start = DateTime.now.beginning_of_week; end = start.end_of_week
"this bi-week" (first half or second half of the month, relative to the current date of DateTime.now)
it is very important to be sure that the month is evenly divided, and cweek is not used; the start of the first bi-week should be the first of the month, and the end of the second bi-week should be the last of the month. The dividing date between the two should be the total number of days in the month divided by 2, rounded up (i.e. if there are 31 days, the second bi-week would start on the 15th, and not the 14th of the month).
"this month": start = DateTime.now.beginning_of_month; end = start.end_of_month
"last month": start = (DateTime.now - 1.month).beginning_of_month; end = start.end_of_month
"this quarter": one of each of the four 3-month periods in the year, ie quarters. Ex: from 1/1/1999 to 3/31/1999 or from 10/1/2000 to 12/31/2000.
"this year" = start = DateTime.now.beginning_of_year --> end = start.end_of_year
I'm having trouble calculating the bold date ranges based on the current date (assume DateTime.now).
How can I calculate the bi-weekly and quarterly period relative to the current date, DateTime.now?
Expected output
For the date May 7th, 2018 (5/7/2018):
"this bi-week" should be the period of 5/1/2018 to 5/15/2018
"this quarter" should be the period of 4/1/2018 to 6/30/2018
For the date February 29th, 2020 (2/29/2020), a leap year:
"this bi-week" should be the period of 2/15/2018 to 2/29/2018
"this quarter" should be the period of 1/1/2018 to 3/31/2018
What about this:
This bi-week:
def bi_week_limits_for(date)
days_in_month = Time.days_in_month(date.month, date.year)
# this will round down. 30/31-day months will output 15. 28 / 29-day will output 14. Adjust as per your requirements
middle_day = days_in_month / 2
if date.day <= middle_day
[date.beginning_of_month, date.change(day: middle_day)]
else
[date.change(day: middle_day + 1), date.end_of_month]
end
end
In my console:
pry(main)> bi_week_limits_for Date.parse('29/2/2020')
=> [Sat, 15 Feb 2020, Sat, 29 Feb 2020]
pry(main)> bi_week_limits_for Date.parse('7/5/2018')
=> [Tue, 01 May 2018, Tue, 15 May 2018]
This quarter:
def bi_week_limits_for(date)
[date.beginning_of_quarter, date.end_of_quarter]
end
In my console
pry(main)> date = Date.parse('7/5/2018')
=> Mon, 07 May 2018
pry(main)> quarter_limits_for date
=> [Sun, 01 Apr 2018, Sat, 30 Jun 2018]
pry(main)> date = Date.parse '29/2/2020'
=> Sat, 29 Feb 2020
pry(main)> quarter_limits_for date
=> [Wed, 01 Jan 2020, Tue, 31 Mar 2020]
Reference: https://apidock.com/rails/DateAndTime/Calculations/beginning_of_quarter

Select object based on date range

Tech specs: ruby 2.1.5p273, Rails 4.2.3.
I have an array of Days that I want to loop through to pick the right Exits (model) that fall within a date range.
#exits has :start_date and :end_date
#days is an array of dates like:
=> [Sun, 06 Sep 2015, Sat, 12 Sep 2015, Tue, 15 Sep 2015, Fri, 18 Sep 2015, Sat, 19 Sep 2015, Sun, 20 Sep 2015, Wed, 23 Sep 2015]
I thought something like this would work:
#days.each do |day|
#exits.where(:start_date..:end_date).include?(day)
end
but I get an error:
TypeError: Cannot visit Range
What is the best way to query an object that has a date range (between two fields) by comparing it against a single date? Thanks!
You can use the following:
#days.each do |day|
exits = Exit.where('? BETWEEN start_date AND end_date', day)
# etc.
end
If you don't want to loop over them then you can do:
Event.where("start_date IN (:days) AND end_date IN (:days)", { days: #days })
or
Event.where(start_date: #days, end_date: #days)
Exit.where(day: #exit.start_date..#exits.end_date)
or
Exit.where('day >= ? AND day <= ?', #exit.start_date, #exits.end_date)
Doing SQL queries in a loop is probably a bad idea, it could be refactored to be be one call most likely. And this should happen in the controller not in the view.

How make a date range array in Ruby that starts with the current month?

Thanks to Stefan I was able to create a function that returns a number of date ranges:
def years
[2013, 2012, 2011, 2010, 2009]
end
def month_ranges
years.flat_map { |y|
12.downto(1).map { |m| Date.new(y,m,1)..Date.new(y,m,-1) }
}
end
# =>
[
Mon, 01 Dec 2013..Wed, 31 Dec 2013,
Sat, 01 Nov 2013..Sun, 30 Nov 2013,
Wed, 01 Oct 2013..Fri, 31 Oct 2013,
Mon, 01 Sep 2013..Tue, 30 Sep 2013
]
Now, is there a way to make this date array start with the current month of the current year as well? In the following years it should always start with December and end with January.
Thanks to anyone who can help.
Simple answer: check the year against the current year. If they're equal, start with current month, if not start with 12.
years = [2013, 2012, 2011, 2010, 2009]
def month_ranges
years.flat_map { |y|
if y == Date.today.year
start = Date.today.month
else
start = 12
end
start.downto(1).map { |m| Date.new(y,m,1)..Date.new(y,m,-1) }
}
end
To provide the result in the format required in the earlier question:
require 'date'
years = [2013, 2012, 2011, 2010, 2009]
years.map(&:to_s).product([*'-01'..'-12'].reverse).map(&:join).select{|d| d <= Date.today.to_s[0..-3]}
=> ["2013-09", "2013-08",..., "2009-01"]

"Ago" date/time functions in Ruby/Rails

I was wondering if there's a way in Rails to calculate time stamp like - half a minute ago, 2 minute ago, 1 day ago etc. Something like twitter real time date stamp.
I want to know if Ruby/Rails has a built-in function for such date-time conversion?
You can use:
10.minutes.ago
2.days.since
Or in your views you have the helpers:
distance_of_time_in_words(from_time, to_time)
time_ago_in_words(from_time)
Check the API for details and more options.
You can use available methods to get the time in past or future using ago, since alias for from_now and many available methods
Time.current
#=> Tue, 20 Sep 2016 15:03:30 UTC +00:00
2.minutes.ago
#=> Tue, 20 Sep 2016 15:01:30 UTC +00:00
2.minutes.since
#=> Tue, 20 Sep 2016 15:05:30 UTC +00:00
1.month.ago
#=> Sat, 20 Aug 2016 15:03:30 UTC +00:00
1.year.since
#=> Wed, 20 Sep 2017 15:03:30 UTC +00:00
Check all the available methods in Time class
distance_of_time_in_words:
from_time = Time.now
distance_of_time_in_words(from_time, from_time + 50.minutes) # => about 1 hour
distance_of_time_in_words(from_time, 50.minutes.from_now) # => about 1 hour
distance_of_time_in_words(from_time, from_time + 15.seconds) # => less than a minute
distance_of_time_in_words(from_time, from_time + 15.seconds, include_seconds: true) # => less than 20 seconds
time_ago_in_words:
time_ago_in_words(3.minutes.from_now) # => 3 minutes
time_ago_in_words(3.minutes.ago) # => 3 minutes
time_ago_in_words(Time.now - 15.hours) # => about 15 hours

Is it possible to create a list of months between two dates in Rails

I am trying to create a page to display a list of links for each month, grouped into years. The months need to be between two dates, Today, and The date of the first entry.
I am at a brick wall, I have no idea how to create this.
Any help would be massively appriciated
Regards
Adam
Just put what you want inside a range loop and use the Date::MONTHNAMES array like so
(date.year..laterdate.year).each do |y|
mo_start = (date.year == y) ? date.month : 1
mo_end = (laterdate.year == y) ? laterdate.month : 12
(mo_start..mo_end).each do |m|
puts Date::MONTHNAMES[m]
end
end
The following code will add a months_between instance method to the Date class
#!/usr/bin/ruby
require 'date'
class Date
def self.months_between(d1, d2)
months = []
start_date = Date.civil(d1.year, d1.month, 1)
end_date = Date.civil(d2.year, d2.month, 1)
raise ArgumentError unless d1 <= d2
while (start_date < end_date)
months << start_date
start_date = start_date >>1
end
months << end_date
end
end
This is VERY lightly tested, however it returns an Array of dates each date being the 1st day in each affected month.
I don't know if I've completely understood your problem, but some of the following might be useful. I've taken advantage of the extensions to Date provided in ActiveSupport:
d1 = Date.parse("20070617") # => Sun, 17 Jun 2007
d2 = Date.parse("20090529") #=> Fri, 29 May 2009
eom = d1.end_of_month #=> Sat, 30 Jun 2007
mth_ends = [eom] #=> [Sat, 30 Jun 2007]
while eom < d2
eom = eom.advance(:days => 1).end_of_month
mth_ends << eom
end
yrs = mth_ends.group_by{|me| me.year}
The final line uses another handy extension: Array#group_by, which does pretty much exactly what it promises.
d1.year.upto(d2.year) do |yr|
puts "#{yrs[yr].min}, #{yrs[yr].max}"
end
2007-06-30, 2007-12-31
2008-01-31, 2008-12-31
2009-01-31, 2009-05-31
I don't know if the start/end points are as desired, but you should be able to figure out what else you might need.
HTH
Use the date_helper gem which adds the months_between method to the Date class similar to Steve's answer.
xmas = Date.parse("2013-12-25")
hksar_establishment_day = Date.parse("2014-07-01")
Date.months_between(xmas,hksar_establishment_day)
=> [Sun, 01 Dec 2013, Wed, 01 Jan 2014, Sat, 01 Feb 2014, Sat, 01 Mar 2014, Tue, 01 Apr 2014, Thu, 01 May 2014, Sun, 01 Jun 2014, Tue, 01 Jul 2014]

Resources