When was this clock bought? - optimization

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)

Related

covering edge cases of dates in Ruby

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.

Daily Partitioning and archiving

I'm trying to partition a table by month say Jan, Feb, Mar. The column through which I'll partition is a datetime type column with an ISO Format ('20190101', '20190201', etc).
For example, I have sales data for jan, feb, mar. I'd like the data to be partitioned by daily partitioned . ('20190101', '20190201','20190301' etc)
E.X:
Jan, Feb, Mar etc. Also I would like to keep the data less so I would like to delete daily day wise data keeping only 1 month data maximum, for example I will create jan 31 , feb 28 , mar 31, apr 30. How do I manage partition dynamically as some month is 31 days some are 28 days and 30 days. Also I need to retain only one month data for example if its, 1st of sep then I need to keep aug 31 days data, and can delete 31st jul day data now on 2nd sep I can delete 1st august data so I need to delete daily data and keep only 30 days data .
My question is: is it even possible? If it is, how an I automate the process using SSIS?
You may try this. As you want to remove previous 30 days data from current date or any specific date, so you can easily calculate the date range by subtracting 30 days from the current date.
For 30 days
--- Instead of getdate() you may use any of your date column for filter
delete from yourtable where yourdate < DATEADD( day, -30, getdate()) ---- here on place of 30 you may use any days you want to delete
For 1 month
--- Instead of getdate() you may use any of your date column for filter
delete from yourtable where yourdate < DATEADD( month, -1, getdate()) ---- here on place of 30 you may use any days you want to delete
Instead of having your partition boundaries be the end of the month, have them be the beginning. That is, do something like:
[2019-01-01, 2019-02-01),
[2019-02-01, 2019-03-01),
[2019-03-01, 2019-04-01),
[2019-04-01, 2019-05-01),
[2019-05-01, 2019-06-01),
etc
That is, the left-hand boundary is in the partition and the right-hand boundary isn't. If you're using actual Partitioning, you'd define your partition function as a "boundary left" function. See the documentation for more details.

MONTHS_BETWEEN function does not give the expected result [duplicate]

This question already has answers here:
Months between not returning correct value
(2 answers)
Closed 4 years ago.
I am using MONTHS_BETWEEN function to get the difference between 2 dates , but the result is not 100% correct i think this function mines 1 day .
i tried this SQL
SELECT MONTHS_BETWEEN(TO_DATE('20170630','YYYYMMDD'),
TO_DATE('20170501','YYYYMMDD') ) "Months"
FROM DUAL;
here in this case it should return 2 but the result is 1.93548387096774
So, Any help ?? or is there any way to add 1 more day to date??
Try
SELECT ROUND( MONTHS_BETWEEN(
TO_DATE('20170630','YYYYMMDD'),
TO_DATE('20170501','YYYYMMDD')))
"Months" FROM DUAL;
MONTHS_BETWEEN returns decimal result if days are different and they are not both specify the last day of the month. For more info see http://www.sqlines.com/oracle/functions/months_between
Months between will give you a decimal value with respect to a whole month. So from 1st Jan to 1st Feb, you will get 1. But from 1st Jan to 31st Jan you will not get exact 1. It will be 0.9.... Similarly from 31st Jan to 28th Feb (non leap year) you will get 1.
So you will get 2 from 1st May to 1st July OR from 30th April to 30th June,
From 1st May to 30th June, you will never get exact 2.
If you want exact 2, then either add 1 day to greater date or subtract 1 day from start_date.
DBFiddle Demo

Max Nested Level SQL Server - Create Calendar type table

I currently have a table which holds rate periods for services. These periods need to be created in the following way based on a provided start date and end date
If start date is not the start of a week, a record must be inserted
from the Start date until the end of the week containing the start
date.
The next record to be inserted will be the start of the week after the start date up until the end date of the last full date prior to the end date (it can be up until the end date, if the end date is a last day of the week.
There is also a requirement to add individual records for bank holidays
The table is currently populated using recursive stored procedures,but has been failing recently due to exceeding the max nest level for SP', functions etc.
I want to remove this issue and I have no issues creating the table where there are no bank holidays, but I am having problems dealing with the bank holiday insertion and update of previous rates entered.
For example take the following
Start Date: 5th Jan 2017
End Date: 8th April 2017
Last Day of Week: Sunday
Bank Holidays: Mar 9th and Apr 6th
The returned records should be
5th Jan - 8th Jan (5th is not a Monday)
9th Jan - 5th Mar (End week prior to Bank Holiday)
6th Mar - 8th Mar (part week due to Bank Holiday)
9th Mar - 9th Mar (Bank Holiday)
10th Mar - 12th Mar (Part week due to Bank Holiday)
13th Mar - 2nd Apr (Full weeks)
3rd Apr - 5th Apr (Part week due to Bank Holiday)
6th Apr - 6th Apr (Bank Holiday)
7th Apr - 8th Apr (End of Period)
I have looked into using recursive CTE's to do this but I am having issues with this.
Any ideas on the best way to implement the above?

On-going Rolling 12 month sum for KPI

I have been asked to produce 2 KPI charts which give a Rolling 12 month percentage of:
1.Percentage of hours lost due to long term sickness against hours available
2.Percentage of hours lost due to short term sickness against hours available
As you can see in the image below I have the totals as per the last day of the month up until the day the KPI is viewed. (see as at date) This is saved as a view.
KPI View
Can anybody now help me with displaying the data so that it totals up the hours as per the last 12 months? once I have these the percentages I can do, its the totalling the hours over the rolling 12 months I am struggling with.
e.g
if ran today (23/03/2016)
march 2016 would be the sum of all the results from april 2015 to 23 march 2016
Feb 2016 would be the sum of all the results from march 2015 to 29th feb 2016
and so on...
Thank you in advance.
I would consider window function. For example, generating running total of AvailableHours:
sum(AvailableHours)over(order by calendarshortyearmonth asc) as run_total_AvailableHours