How can i get the current weekday beginning in ruby? - ruby-on-rails

For example today is 28/07/2011
How do i get the weeks first day the monday which is 25/07/2011 in ruby

>> Date.today.beginning_of_week.strftime('%d/%m/%Y')
#=> 25/07/2011
See the Time and Date classes under Rails for more info, and strftime for information on the formatting options.

Without Rails/ActiveSupport:
phrogz$ irb
> require 'date'
> now = Date.today
#=> #<Date: 2011-07-28 (4911541/2,0,2299161)>
> sunday = now - now.wday
#=> #<Date: 2011-07-24 (4911533/2,0,2299161)>
> monday = now - (now.wday - 1) % 7
#=> #<Date: 2011-07-25 (4911535/2,0,2299161)>
> monday.iso8601
#=> "2011-07-25"
> monday.strftime('%d/%m/%Y')
#=> "25/07/2011"
For more, see the Date class in the Standard Library.
Wrapped up as a method:
require 'date'
# For weekdays to start on Monday use 1 for the offset; for Tuesday use 2, etc.
def week_start( date, offset_from_sunday=0 )
date - (date.wday - offset_from_sunday)%7
end
sun = Date.parse '2011-07-24'
week_start(sun,0).strftime('%a, %b-%d') #=> "Sun, Jul-24"
week_start(sun,1).strftime('%a, %b-%d') #=> "Mon, Jul-18"

Related

Efficient way to get closest pay day to a given date

I'm trying to figure out the most efficient way to find the closest payday from a given date.
Let's say we know payday are every 14 days and that January 6, 2022 was one of them. What is the most efficient way to find the next payday for a given date (the date is the beginning of a week actually) from a known payday?
Here is a current working ugly implementation
def payday_first_date
# TODO: Very reliable, but very inefficient
#payday_first_date ||= begin
date = known_pay_day
date -= 14.days until date < given_date
date += 14.days until date > given_date
date
end
end
def known_pay_day
# Thursday January 6, 2022 was a payday
#known_pay_day ||= Date.new(2022, 2, 17)
end
The given_date could be in the future and also in the past. It can be a date from another year aswell.
Thanks in advance!
First define the known pay date and two helper methods.
require 'date'
def date_str_to_date_obj(date_str)
DateTime.strptime(date_str, "%B %d, %Y").to_date
end
known_date = date_str_to_date_obj("January 6, 2022")
#=> #<Date: 2022-01-06 ((2459586j,0s,0n),+0s,2299161j)>
For presentation only:
def date_obj_to_date_str(date_obj)
date_obj.strftime("%B %d, %Y, %A")
end
date_obj_to_date_str(known_date)
#=> "January 06, 2022, Thursday"
The main method follows.
def closest_pay_day(known_date, target_date)
nbr_pay_dates = (target_date - known_date)/14.0
last_pay_date = known_date + nbr_pay_dates.floor * 14
next_pay_date = last_pay_date + 14
(next_pay_date - target_date < target_date - last_pay_date) ?
next_pay_date : last_pay_date
end
Suppose the target date is after the known pay date.
target_date_str = "March 26, 2022"
Then
target_date = date_str_to_date_obj(target_date_str)
#=> #<Date: 2022-03-26 ((2459665j,0s,0n),+0s,2299161j)>
date_obj_to_date_str(target_date)
#=> "March 26, 2022, Saturday"
The closest pay period to the target date is therefore
closest = closest_pay_day(known_date, target_date)
#=> #<Date: 2022-03-31 ((2459670j,0s,0n),+0s,2299161j)>
date_obj_to_date_str(closest)
#=> "March 31, 2022, Thursday"
which is
(target_date- closest).to_i
#=> -5
days before the target date, meaning 5 days after the target date.
Now suppose the target date is before the known pay date.
target_date_str = "October 19, 2021"
Then
target_date = date_str_to_date_obj(target_date_str)
#=> #<Date: 2021-10-19 ((2459507j,0s,0n),+0s,2299161j)>
date_obj_to_date_str(target_date)
#=> "October 19, 2021, Tuesday"
date_obj_to_date_str(closest_pay_day(known_date, target_date))
#=> "October 14, 2021, Thursday"

How to get all 'specific days' within a date range

How can I get let's say All the dates for Saturday and Sunday from X year to Y year and store them as array? Pseudo code would be
(year_today..next_year).get_all_dates_for_saturday_and_sunday
Or perhaps there are gems that cater to this already?
Try this:
(Date.today..Date.today.next_year).select { |date|
date.sunday? or date.saturday?
}
#=> [Sat, 03 Sep 2016,Sun, 04 Sep 2016,Sat, 10 Sep 2016,Sun, 11 Sep 2016...
(Date.today..(Date.today + 1.year)).select do |date|
date.saturday? || date.sunday?
end # => [Sat, 03 Sep 2016, Sun, 04 Sep 2016, Sat, 10 Sep 2016, ...
This will then give you an array of 104 elements containing every date which is a saturday or a sunday between today and today in a year.
The following approach emphasizes efficiency over brevity, by avoiding the need to determine if every day in a range is a given day (or one of two given days) of the week.
Code
require 'date'
def dates_by_years_and_wday(start_year, end_year, wday)
(first_date_by_year_and_wday(start_year, wday)...
first_date_by_year_and_wday(end_year+1, wday)).step(7).to_a
end
def first_date_by_year_and_wday(year, wday)
d = Date.new(year)
d + (wday >= d.wday ? wday - d.wday : 7 + wday - d.wday)
end
Notice that the range is defined with three dots, meaning the first date in end_year is excluded.
Example
SATURDAY = 6
SUNDAY = 0
start_year, end_year = 2015, 2017
dates_by_years_and_wday(start_year, end_year, SATURDAY)
#=> [#<Date: 2015-01-03 ((2457026j,0s,0n),+0s,2299161j)>,
# #<Date: 2015-01-10 ((2457033j,0s,0n),+0s,2299161j)>,
# ...
# #<Date: 2017-12-30 ((2458118j,0s,0n),+0s,2299161j)>]
dates_by_years_and_wday(start_year, end_year, SATURDAY).size
#=> 157
dates_by_years_and_wday(start_year, end_year, SUNDAY)
#=> [#<Date: 2015-01-04 ((2457027j,0s,0n),+0s,2299161j)>,
# #<Date: 2015-01-11 ((2457034j,0s,0n),+0s,2299161j)>,
# ...
# #<Date: 2017-12-31 ((2458119j,0s,0n),+0s,2299161j)>]
dates_by_years_and_wday(start_year, end_year, SUNDAY).size
#=> 157

Number of hours between two dates - Ruby

Say I want the difference between tomorrow and now (in hours).
What I've tried:
t = (DateTime.tomorrow - DateTime.now)
(t / 3600).to_i
=> 0
Why does it give 0?
What am I doing wrong?
This is because DateTime.tomorrow does not have any time value. Here:
DateTime.tomorrow
# => Wed, 22 Apr 2015
If you go through official document for DateTime you can see there is no method tomorrow. Its basically Date#tomorrow.
You can use .to_time to get default localtime 00:00:00
DateTime.tomorrow.to_time
# => 2015-04-22 00:00:00 +0530
(DateTime.tomorrow.to_time - DateTime.now) / 1.hours
# => 9.008116581638655
To get exact hour difference between dates:
(DateTime.tomorrow.to_time - Date.today.to_time) / 1.hours
# => 24.0
Try this
t = (DateTime.tomorrow.to_time - Date.today.to_time)
t = (t / 3600).to_i
It returns rational number. You can take days number if you'll use round method:
>> (DateTime.tomorrow - DateTime.now).round
1
Or if you want to take value in hours from now, use Time class:
>> (Date.tomorrow.to_time - Time.now) / 1.hour
11.119436663611111
if you have two dates like
start_time = Time.new(2015,1, 22, 35, 0)
end_time = Time.new(2015,2, 22, 55, 0)
Try Time Difference gem for Ruby at https://rubygems.org/gems/time_difference
def timediff(start, end)
TimeDifference.between(start, end).in_hours
end
and call it like:
timediff(start_time, end_time)
It will work.
Cheers!
There's DateTime#seconds_until_end_of_day:
seconds = DateTime.now.seconds_until_end_of_day
#=> 41133
seconds / 3600
#=> 11
distance_of_time_in_words(seconds)
=> "about 11 hours"

Get the day of the last Friday of each month

I am new with ruby and I want to get the day of the last Friday of each month.
For example, the last Friday of March is 29, the Last Friday of April 26.
So, how can I get a solution?
I'm using the rails framework.
The method .cweek returns the week of the year, but does not return the week of the current month.
#!/usr/bin/env ruby
require 'date'
(1..12).each do |month|
d = Date.new(2013, month, -1)
d -= (d.wday - 5) % 7
puts d
end
Source (second/third Google result..)
I would go with Lee's answer, I'm only posting this one because (I thought) it's pretty cool.
Using gem Chronic (https://github.com/mojombo/chronic):
#Last Friday of this coming December
require 'chronic'
last_friday = Chronic.parse("First Friday of next January") - 1.week
Retrieving the last friday of a month can be made in a single line:
def last_fridays_for_every_month_of_year(year)
(1..12).map do |month|
Date.new(year, month, -1).downto(0).find(&:friday?)
end
end
You may use it like this:
last_fridays_for_every_month_of_year 2013
#=> [#<Date: 2013-01-25 ((2456318j,0s,0n),+0s,2299161j)>,
#<Date: 2013-02-22 ((2456346j,0s,0n),+0s,2299161j)>,
#<Date: 2013-03-29 ((2456381j,0s,0n),+0s,2299161j)>,
#<Date: 2013-04-26 ((2456409j,0s,0n),+0s,2299161j)>,
#<Date: 2013-05-31 ((2456444j,0s,0n),+0s,2299161j)>,
#<Date: 2013-06-28 ((2456472j,0s,0n),+0s,2299161j)>,
#<Date: 2013-07-26 ((2456500j,0s,0n),+0s,2299161j)>,
#<Date: 2013-08-30 ((2456535j,0s,0n),+0s,2299161j)>,
#<Date: 2013-09-27 ((2456563j,0s,0n),+0s,2299161j)>,
#<Date: 2013-10-25 ((2456591j,0s,0n),+0s,2299161j)>,
#<Date: 2013-11-29 ((2456626j,0s,0n),+0s,2299161j)>,
#<Date: 2013-12-27 ((2456654j,0s,0n),+0s,2299161j)>]
require "active_support/core_ext"
end_of_month = Date.today.end_of_month
if end_of_month - end_of_month.beginning_of_week >= 4
end_of_month+5.days
else
end_of_month-2.days
end
# => Fri, 29 Mar 2013

Convert Ruby Date to Integer

How can I convert a Ruby Date to an integer?
t = Time.now
# => 2010-12-20 11:20:31 -0700
# Seconds since epoch
t.to_i
#=> 1292869231
require 'date'
d = Date.today
#=> #<Date: 2010-12-20 (4911101/2,0,2299161)>
epoch = Date.new(1970,1,1)
#=> #<Date: 1970-01-01 (4881175/2,0,2299161)>
d - epoch
#=> (14963/1)
# Days since epoch
(d - epoch).to_i
#=> 14963
# Seconds since epoch
d.to_time.to_i
#=> 1292828400
Date cannot directly become an integer. Ex:
$ Date.today
=> #<Date: 2017-12-29 ((2458117j,0s,0n),+0s,2299161j)>
$ Date.today.to_i
=> NoMethodError: undefined method 'to_i' for #<Date: 2017-12-29 ((2458117j,0s,0n),+0s,2299161j)>
Your options are either to turn the Date into a time then an Int which will give you the seconds since epoch:
$ Date.today.to_time.to_i
=> 1514523600
Or come up with some other number you want like days since epoch:
$ Date.today.to_time.to_i / (60 * 60 * 24) ### Number of seconds in a day
=> 17529 ### Number of days since epoch
Time.now.to_i
returns seconds since epoch format
Solution for Ruby 1.8 when you have an arbitrary DateTime object:
1.8.7-p374 :001 > require 'date'
=> true
1.8.7-p374 :002 > DateTime.new(2012, 1, 15).strftime('%s')
=> "1326585600"
I had to do it recently and took some time to figure it out but that is how I came across a solution and it may give you some ideas:
require 'date'
today = Date.today
year = today.year
month = today.mon
day = day.mday
year = year.to_s
month = month.to_s
day = day.to_s
if month.length <2
month = "0" + month
end
if day.length <2
day = "0" + day
end
today = year + month + day
today = today.to_i
puts today
At the date of this post, It will put 20191205.
In case the month or day is less than 2 digits it will add a 0 on the left.
I did like this because I had to compare the current date whit some data that came from a DB in this format and as an integer. I hope it helps you.

Resources