Traverse through a certain month in Date with just a given integer - ruby-on-rails

Would it be possible to go to a certain month of the year with just a given integer. For example
date = Date.today
=> Wed, 30 Dec 2015
What if I want to go back to a certain month based on that date and I am just given a number let's say 7 which is July in the Date::MONTHNAMES so would it be possible to do something like
date = Date.today
=> Wed, 30 Dec 2015
date.go_to_month_of(7) # which will bring me back to July 30, 2015

Okay I found it. It's:
date = Date.today
date.change(:month => x)
Hope this helps you!

Related

How to parse week and year with strptime

Usually I don't have issues parsing strings to Time in Rails, however I cannot understand why it's behaving like this:
irb(main):073:0> DateTime.strptime("20/2020", "%V/%Y")
=> Wed, 01 Jan 2020 00:00:00 +0000
I want the 20th week of 2020, not the 1st Jan...
I think that you need to use the commercial method.
require 'date'
week = 20
start_week = Date.commercial(2020, week)
# => Mon, 11 May 2020
puts "#{start_week}"
# => 2020-05-11
In case you need a Range, you can do:
Date.commercial(2020, week).all_week
# => Mon, 11 May 2020..Sun, 17 May 2020
For more information see the documentation.
require 'date'
If week 1 begins on Sunday:
Date.strptime("20/2020", "%U/%Y")
#=> #<Date: 2020-05-17 ((2458987j,0s,0n),+0s,2299161j)>
and on Monday:
d = Date.strptime("20/2020", "%W/%Y")
#=> #<Date: 2020-05-18 ((2458988j,0s,0n),+0s,2299161j)>
and also from the doc Date#strftime (which contains the formatting directives for Date::strptime), "The days in the year before the first week are in week 0".
There is generally a difference between %Y and %G for the year depending on your assumed definition for a week number.
For ISO 8601 weeks (which are commonly used in e.g. Europe), you have to use the week-based year here (%G) rather than the day-=based year (%Y). This is important around the edges of the years. For example, 2021-01-01 is in week 53 of 2020. On this date
%G is 2020, but
%Y is already 2021
If you want to parse an ISO 8601 week, you can thus use the following code to ensur you use the right week and year:
require 'date'
DateTime.strptime("20/2020", "%V/%G")
# => #<DateTime: 2020-05-11T00:00:00+00:00 ((2458981j,0s,0n),+0s,2299161j)>

Query all records from a week in a month

I am creating a Rails 5 app.
In this app I got Survey model. I am able to run queries (using scopes) to get all surveys from a specific month and all from a specific quarter but I want to get all from a specific week in a month too, how can I do that?
These are my quarter and month scopes
scope :period_quarter, -> (year, quarter) { where(created_at: Date.new(year.to_i, 3 * quarter.to_i - 2).all_quarter) }
scope :period_month, -> (year, month) { where(created_at: Date.new(year.to_i, month.to_i).all_month) }
How can I add a scope to get all surveys from a specific week in a month. I will provide year, month and week (1-5).
Consider the same approach you've been using, only with all_week and perhaps beginning_of_week as needed to get the correct start date.
To get a date in a specific week, you could use something like this:
def week(year, month, week_num)
Date.new(year, month, 7 * week_num - 6)
end
week(2018, 8, 1).beginning_of_week # => Mon, 30 Jul 2018
week(2018, 8, 1).end_of_week # => Sun, 05 Aug 2018
week(2018, 8, 1).all_week # => Mon, 30 Jul 2018..Sun, 05 Aug 2018
To use this in a query, you could use it like this:
where(created_at: week(2018, 8, 1).all_week)
This will count the first week in a month as the week where the 1. is. However, if you want it to use the first full week in a month, you can remove the -6.

Why does adding and subtracting 2 months to a date not give back the same date?

I'm a bit confused about this outcome, taking today's date minus 2 months, and then taking that date again and adding two months, does not give me today's date when assign the dates to a variable.
Time.zone
"Eastern Time (US & Canada)"
> today = Date.today.in_time_zone
=> Thu, 31 Aug 2017 00:00:00 EDT -04:00
> a = today - 2.months # This is persisted to the db
=> Fri, 30 Jun 2017 00:00:00 EDT -04:00
> b = a + 2.months
=> Wed, 30 Aug 2017 00:00:00 EDT -04:00
If I however, just use the same object, it moves back and forth properly:
> today = Date.today.in_time_zone
=> Thu, 31 Aug 2017 00:00:00 EDT -04:00
> today - 2.months
=> Fri, 30 Jun 2017 00:00:00 EDT -04:00
> today + 2.months
=> Tue, 31 Oct 2017 00:00:00 EDT -04:00
The problem is obviously when "a" gets saved to a database, and then retrieved later on, and calculated plus 2 months..., it should match today's date.
TL;DR
A month is not a fixed duration. Adding or taking a month does not give the same "time shift" depending on which day you are.
The usual algorithm
to add or take months is the following :
try to land on the same day number (4th, 30th, 31st) as you started, just by changing the month
if you would land on an impossible date (like 31th September, 30th February, 29th February for some years) then just go the maximum allowed day number of this month
This implies that adding some months then taking out the same number of months will not necessarily give you back the same date.
Examples :
31st of some month + 1 month --> One would want to get to the 31th of next month
But if there is no 31st of next month (like for 31th of August, no 31st of September), then what to do ?
Usual interpretation would say that you want to go to the end of the month, this is 30th September (for rent or other monthly subscription, for instance)
But usually, 30th of some month - 1 month --> One would want to get to the 30th of the previous month.
That would lead to .... 30th of August. Not 31th of August.
Hence: some date + 1 month - 1 month does not necessarily give the original date !
Another example :
Start at the 30th of August.
Take a month -> 30th of July
Add a month -> You want to get to 30th of August (same number, next month) or to the end of August ?
The default algorithm will try to give the same day number -> 30th of August (which is more logical now)
Also with days...
Note that the same problem happens with days,but much less often ! When some days don't have the same number of hours, for daylight saving days, when adding and taking same number of days you might not get back to the original date and time as you started from.

How to get time x days ago from a specific date in Rails?

I am looking for a rails solution to calculate the time ago from a particulat time. For example , 2 days ago 15th May 2016 22:00 UTC should return 13th May 2016 22::00 UTC .
My requirement is something like this
2.days.ago.from(yesterday)
Which will be a more specific version of
2.days.from_now
Try this:
> DateTime.now-2.days
=> Wed, 18 May 2016 21:40:31 -0700
how about this:
# 2 days before a specific date
specific_date.days_ago(2)
Example:
specific_date = DateTime.now
two_days_ago_from_specific_date = specific_date.days_ago(2)
My personal favorite syntax for this with rails would be
x.days.ago
For example, if you wanted 10 days ago you would call
10.days.ago
=> Sat, 12 Feb 2022 01:36:58 UTC +00:00
Easy to read and defaults to UTC.
example:
Time.now.ago(10.year)
Time.now.ago(1.minutes)
Time.now.ago(10.day)

Rails, day of year to date

I have day of the year. For example 15th day of 2014, or 210th day of 2014. I need to get the Date on the particular day. Is there any library function in Rails/Ruby that I can use, or any other elegant way?
Something like:
15th day of 2014 = 15-Jan-2014
210th day of 2014 = 29-Jul-2014
You can use Date.ordinal for that:
require 'date'
Date.ordinal(2014, 210)
# => #<Date: 2014-07-29 ((2456868j,0s,0n),+0s,2299161j)>
Date.new(2014, 1, 1) + 210
=> Wed, 30 Jul 2014
Edit - you'd need to subtract 1 day. I prefer #wonderb0lt's suggestion.

Resources