covering edge cases of dates in Ruby - ruby-on-rails-3

I have one usecase, where I am doing manipulation based on dates. However there are some edgecases which is causing trouble in my logic and I am not able to figure out a way to cover those edge-cases.
Problem statement:
I want to get all the records which comes under the current month cycle.
Ex: Plan starts at: 5 Oct 2022, then Whenever I query data based on the date of querying, it should return the records count for the current month cycle. Let say, today is 3rd Nov which means current cycle is 5th Oct to 4th Nov. then query should return records from this period.
Based on the below logic, I am able to get the date which I am using in my query to fetch records which are created from date till now.
def get_current_month_contract_start_date(email)
contract_date = User.find_by(email: email).cycle_start_date
contract_day = contract_date.day if contract_date.present?
today = DateTime.now
if DateTime.now.day < contract_day
prev = today - 1.month
upper_bound_date = DateTime.new(prev.year, prev.month, contract_day, 0, 0, 0)
else
upper_bound_date = DateTime.new(today.year, today.month, contract_day, 0, 0, 0)
end
upper_bound_date
end
I am using below query to fetch the data from database:
User.find_by(email: email).where(:created_at.gte => get_current_month_contract_start_date(email)).count
But the problem is edge cases.
Let say contract start date is-> 31 Jan, it should end 27 Feb, next start date should be 28 Feb, but #actual is: 31-01-23 expected: 28-02-2023 when today is #28 Feb
Let say contract start date is -> 28 Feb, it should end 30 March and next start date should be 31 march. Assume, If today's date is 28 March then result is #actual: 28-03-23 expected: 28-02-23, because cycle will end on 30 March(Month end to next month end).
Same if today's date is 30th March then result is #actual: 28-03-23 expected: 28-02-23
If today date is 31th March then result is #actual: 28-03-23 expected: 31-03-23
Can someone please suggest me how to cover these edge cases as well in the current code with necessary modifications. Since I am new to ruby I am not able to figure out the exact solution.

Related

After certain week of 2022 and continue with this new year

I would like to request some advice about how to set a Where Condition, but after a certain week
What I mean is:
I have dirty data before a specific week of 2022, so I made this:
DATEPART(WK, SA.FECHAE) >= 44
AND
YEAR(SA.FECHAE) >= 2022
But, We're on 2023, so, I need to add the new information of this new year year too into the query.
The query result shows me until 12-31-2022 and need it until today after the week 44 of 2022
...
WHERE (
DATEPART(WEEK, SA.FECHAE) >= 44
AND YEAR(SA.FECHAE) = 2022
)
OR (
YEAR(SA.FECHAE) >= 2023
)
In the OPs question they ask how to add an additional date range to their WHERE clause. The addition of this OR allows a second date range (in this case anything where the year is greater than or equal to 2023) to match the predicate and be returned, without impacting the original.
Plain English definition of the amended where clause:
Week 44 of 2022, or any week of any year from 2023 forward.

SQL Selecting A Range Of Data According To Sysdate

So I have this problem where I am trying to select a range of data for this sql that will run monthly. Basically I have this field Date_OF_Entry that records dates as 01-Jan-15
Now I will be running this script twice a month at the 16th to capture all the data from the 15th back to the 1st. I will also then run the script at the 1st of the next month to capture all data from the end of the month to the 16th.
Any help is appreciated.
What I am doing now.
Where DATE_OF_ENTRY > sysdate-16
ROUND(date,'MM') Rounds down to the 15th, and up from the 16th.
So WHERE ROUND(DATE_OF_ENTRY,'MM') = ROUND(sysdate-1,'MM') will - on the 16th - round sydate and the 1-15th down to the start of the month, and, on the 1st will round everything from the 16th up.
Be carefull though as on the 1st if any new records have been added where date_of_entry = the 1st, they would get bumped down into last month's end of month group.
So, WHERE ROUND(DATE_OF_ENTRY,'MM') = ROUND(sysdate-1,'MM') AND date_of_entry < trunc(sysdate) should clear that up.

How can I determine if the current date is within/outside a range of two dates that don't include a year?

So I have an object (Activity) where I allow users to select start date and an expiry date for an activity.
The user is basically a center/centre that provides activities for the public.
They have the option of making these activities seasonal. So for example an activity could run from Feb 01 to June 22. I use the current date along with a bunch of code to determine if the activity is in season or not.
So for example I check if the current date 271014 is greater than the start date 020114 and less than the expiry date 062214. If it is then it means the date is in range.
The issue:
I've had to make changes, so now the user must select a month and day only. This is fine until they select something like Nov 01 to Feb 28.
These dates would be in the format 1101 and 2802.
Without the year this obviously gives me different results. With the year I would have been able to determine that the expiry date Feb 28 was the year after the start date and not the same year. Then when working out if the current date was within the start date and expiry date I'd get expected results. Without the year the expiry date is now actually not greater than the start date even though it should be.
What I'm currently doing
How do I solve this issue? All I really need is to allow a user to set a start date and an expiry. The activity will show up in a table view only when the current date is in range.
If only an expiry date is selected then the activity will remain active until that expiry date has been reached. Even if I set and expiry date for Feb 28 and we're in November. The same need applies to the start date too.
Would appreciate some insight here.
Thanks for your time.
Here my suggestion (in pseudo-code): Convert all dates to strings in the format "MMdd", in
your example
startDate = "1101" // November 1
expiryDate = "0228" // February 28
currentDate = "1027" // October 27
If startDate <= expiryDate then the range is within the same year and you can check
the current date with
if (startDate <= currentDate && currentDate <= expiryDate) ...
Otherwise the range starts in one year and ends in the next year, and you check with
if (currentDate >= startDate || currentDate <= expiryDate) ...

Getting the last month date's data in sql

I have the below query to get the last month date's data. Suppose if today is 23rd Dec, then it fetches 23rd Nov data. But when it's 31st Dec, then there would be no 31st Nov. In that case it should fetch 30th Nov data.
So, I want to decrease one day and check the condition again and should fetch the data. In this scenario, suppose on March 31st, first that query even should check for feb 31st, then it should check for feb 30, then 29th and so on until the valid date of that particular month.
My current query:
select *
from dataTable
where date(datecolumn)=date(add_months(DATE(sysdate-1) ,-1));
So, this only fetches last month's date data. So, can someone please suggest me how to check for the mentioned validation in the query and fetch the data?
try this:
SELECT dateadd(mm, -1, Convert(Datetime, '2013-12-31')

When was this clock bought?

The clock on the gym wall also shows the day name and the day of the month. This morning it showed Tuesday - 23.
The day obviously rotates through a cycle of 7 - and showed "Tuesday" correctly. The day of the month, though, presumably rotates through a cycle of 31 and showed "23" incorrectly - today is the 1st December (ie. not the 31st November). So this error has been slowly accruing over time.
Given the assumption that no-one has ever reset the clock, what's the most elegant, quick, optimised way of suggesting some of the possible dates for when this clock was bought brand new.
(Bonus credit for showing when the clock will again show the correct day/number combination.)
01-Oct-17 is when the clock will again show the correct day/number combination.
The day of the week (i.e. Tuesday, ... etc) will always be correct, so it is irrelevant to your problem.
Assuming non leap year, you can build a table of 12 rows (1 per month) containing the number of days in this month minus 31.
Jan 0
Feb -3
Mar 0
Apr -1
May 0
Jun -1
Jul 0
Aug 0
Sep -1
Oct 0
Nov -1
Dec 0
You can build a table of the displayed date for every 1st of the month, by adding to the day of the previous month the related number in this list. If the number is negative or equal to zero, add 31 to the figure.
i.e. from the 1st Dec 09 (date at which the clock is displaying 23), you can go to the 1st Jan 10.
You look at this table and find the figure next to Dec, it is 0.
Add 0 to 23 and you know that on the 1st Jan 10, the clock will be displaying 23.
From the 1st Jan 09, you know that the date which will be displayed on the 1st Feb 10 is 23.
From the 1st Feb 10, you can compute the value for the 01 Mar 10, it is 23 + (-3) = 20.
... etc
So, now, at every start of month where you get a value of 1 in this table, you know that the dates in this month will be correct.
If you have to include leap year, you need a second table with the values for a leap year or make an exception for February.
If you want to use this computation for previous dates, substract the figure from the table and when the number you obtain is over 31, just substract 31 to get the day number.
Using these tables and taking in account leap years.
The last past date at which the clock was correct was the 30 September 08 (it was correct between the 01-Jul-08 and the 30-Sep-08)
The next date at which it will be correct will be the: 01-Oct-17 and it will still be correct on the 30-Nov-17.
Now = 1 Dec 2009.
1st day of the month minus 23rd of past month = 8 days (assuming 31 day month).
Moving back counting non-31-days month...
Nov, Sep, June, Apr, Feb (X3), Nov = 8 days offset
So it was bought before Nov 2008?
I didn't code a single line for it, so pardon me if the answer is way off.
In Excel, you can test any date in A2 to see whether the clock will be correct on that date, with the formula =MOD(A2+19,31)+1=DAY(A2)