Convert week number to date range with Saturday as beginning_of_week - ruby-on-rails

I need to use Saturday as the week start and calculate the beginning and the end of week from week numbers. I need week 53 to be properly accounted for as well.
Date.beginning_of_week = :saturday
works fine, but I have not found a way to generate week start and end dates only from a year and week number. Date.commercial is the only method I have been able to use thus far to convert a week number and year only to a date. I have been unable to get Date.commercial to recognize Saturdays as the week start.

I need to use Saturday as the week start and calculate the beginning and the end of week from week numbers.
Given an instance of Date representing the first Saturday, and the week number, this is quite simple, unless I'm missing something.
def beginning_of_week(first_saturday, week_num) {
return first_saturday + (7 * week_num.to_i).days
}
The days method comes from activesupport.

Related

EOMONTH returns the 1st day of the next month for months with 30 days

When I use the formula below the results of the EOMONTH function
returns the start of the next month for any month with 30 days instead of the last day of the specified month. The month and years are correct, so I'm pretty sure it's EOMONTH when used in another function.
For example,the results in B3 should be "11/31/1965" but it returns "12/1/1965".
=DATE(YEAR(B2),MONTH(B2)+6,DAY(TEXT(EOMONTH(MONTH(B2)+6,0))))
I have tried subtracting a day, but it returns the end-of-month -1 for months with 31 days (30). So I have the same problem in the other case.
I have also used IFS() to account for months with 30 days, and it miscalculates the date the same way.
=IFS( MONTH(B2)+6 = 4,DATE(YEAR(B2),MONTH(B2)+6,DAY(EOMONTH(MONTH(B2)+6,0))-2) ,
MONTH(B2)+6 =
6,DATE(YEAR(B2),MONTH(B2)+6,DAY(EOMONTH(MONTH(B2)+6,0))-2) ,
MONTH(B2)+6 =
9,DATE(YEAR(B2),MONTH(B2)+6,DAY(EOMONTH(MONTH(B2)+6,0))-2) ,
MONTH(B2)+6 =
11,DATE(YEAR(B2),MONTH(B2)+6,DAY(EOMONTH(MONTH(B2)+6,0))-2) ,
TRUE ,DATE(YEAR(B2),MONTH(B2)+6,DAY(EOMONTH(MONTH(B2)+6,0)) ) )
The EOMONTH function by itself where I just pass in the date as a string works correctly (column F).
Any Idea on what I'm doing wrong?
Thanks in advance.
Yes, as #player0 has explained, you can't just add something to a month and feed it into eomonth. Try putting
=eomonth(month(B2)+6,0)
into B3 (formatted as a date).
You get
1/31/1900
Why? month(b2)+6 gives 11 (which is just a number). Dates in google sheets are represented as days since 12/31/1899. So 11 formatted as a date gives 1/11/1900. Applying eomonth to that gives the last day of January 1900, which is the 31st. Feeding that into your formula would give 11/31/65, but that date doesn't exist, so you get 12/1/65.
If you want to go forward 6 months and then get the last day of the month, you need
=eomonth(date(year(B2),month(B2)+6,1),0)
You can also use the Edate function, which does not roll over into the first day of the next month:
=eomonth(edate(B2,6),0)
EOMONTH does not understand MONTH. instead, it converts it into date. to use EOMONTH you need to supply it with valid date
=EOMONTH(B2, 0)

How to get N days ago in Dart's DateTime?

There's the subtract() method but the documentation says it's not aware of daylight savings which makes it pretty much useless in this case, or in any other case except where the programmer doesn't know how many milliseconds there are in 24 hours.
I'm thinking of two ways:
get the day of the month, and then subtract N from it and if it's less than 1 then subtract the month and the year if appropriate and set the day for the last day of whichever month it turns out to be
OR
subtract N days from the noon of the current day and then get start of the day for the resulting day
Is there some easier/better way to do this?
You should probably try to convert both DateTimes to UTC (standardize), then call difference(). That converts it to a nice, easy Duration, which you can convert as necessary to hours, days, months, or whatever else.
DateTime one = somedatetime.toUtc();
DateTime two = someotherdatetime.toUtc();
Duration diff = one.difference(two);
//Then just convert...
return diff.inDays;

week_field gives wrong week after serialization and deserialization

I'm using the week_field helper to generate a week picker in a form. When I choose a week and submit, my controller gets the correct serialized week (e.g. '2014-W03') which I can turn into a date object. That all works, but when the date is serialized again it is always decremented by 1 (e.g. it'll be '2014-W02'). I looked at the source code for the week_field helper and it serializes as
def format_date(value)
value.try(:strftime, "%Y-W%W")
end
but this doesn't seem to be the encoding when the date is parsed. Furthermore, parsing and then serializing a date yeilded this wonky result:
irb > Date.parse('2014-W03').strftime('%Y-W%W')
=> "2014-W02"
Any ideas as to what's going on here or how I can do this in a way that makes sense? I'd hate to have an extra +1 on the week number or change the week_field format_date definition if there's a cleaner route.
This is from http://apidock.com/ruby/DateTime/strftime :
%W - Week number of the year. The week starts with Monday. (00..53)
It seems you have the good old - start with 0 or start with 1 - problem. Strftime will start counting weeks with 0.
But maybe %V is the right thing for you:
ISO 8601 week-based year and week number:
The week 1 of YYYY starts with a Monday and includes YYYY-01-04.
The days in the year before the first week are in the last week of
the previous year.
%G - The week-based year
%g - The last 2 digits of the week-based year (00..99)
%V - Week number of the week-based year (01..53)

Rails: Is there away to get the Date object that is the closest Monday to today?

Given a date, how do I find the nearest Monday in Rails?
I know I can do things like:
Date.tomorrow
Date.today
Is there something like Date.nearest :monday ?
The commercial method on the Date object will let you do this. This example will get you the next Monday.
Date.commercial(Date.today.year, 1+Date.today.cweek, 1)
If you need the next or previous Monday, whichever is closest, you can do:
Date.commercial(Date.today.year, Date.today.cwday.modulo(4)+Date.today.cweek, 1)
I can't execute this right now, so forgive me if there are syntax errors.
It's a little bit tricky, but not so hard to calculate.
Use ActiveSupport::DateAndTimeCalculations#end_of_week to calculate end of a week, this method accepts a start_day parameter that is used to indicate start day of the week (it's :monday by default). They even have implemented sunday method.
The trick is the following: if you want to calculate closest Monday, you may calculate it as a end of the week which starts on Tuesday (Tue => 1st day, Wed => 2nd day, ..., Mon => 7th day which is also end of the week).
So all you need to do is:
# it will return current date if today is Monday and nearest Monday otherwise
Date.today.end_of_week(:tuesday)
I know this is an old thread but it's always nice to keep it current for future seekers.
Let's assume today is say Friday the 19th of August. All I do to get my nearest Monday is this:
monday = Date.today.monday
Then from there you can go back a week or forward a week like this:
last_monday = monday.last_week
next_monday = monday.next_week
Assuming you want both directions: Date.today.beginning_of_week + 7*(Date.today.wday/5)
Untested, so you might need to finetune, but here you go:
def Date.nearest_monday
today = Date.today
wday = today.wday
if wday > 4 # over the half of the week
today + (7 - wday) # next monday
else
today - (1 + wday) # previous monday
end
end

How do I get a Date from a week number?

I want to find all items created in a given week, and pass in a week number param. (created_at is a normal timestamp.)
Given a week number, what is the easiest way to find a date in that particular week?
(Any date in the week will do, as I will use beginning_of_week and end_of_week in the scope.)
You can get Date objects representing the beginning and end of your week using the commercial method:
week = 41;
wkBegin = Date.commercial(2010, week, 1)
wkEnd = Date.commercial(2010, week, 7)
Now do your find:
Item.find(:all, :conditions->:create_date=>wkBegin..wkEnd.end_of_day)
Assuming you mean "a given week number in the current year", you can do the following:
2.weeks.since(Time.gm(Time.now.year))
=> Fri Jan 15 00:00:00 UTC 2010
Substitute (week_number - 1) for the 1 in the above, and you'll get a date in the desired week.

Resources