Disclaimer: I am just looking for a logic not code
John discovered a strange island called Rasa. The years and weeks on the island are weird. Digging deeper into the island's calendar, he found out that it is similar to rest-of-the-world's (ROW) calendar but the island calendar's Year starts on 1st week of February's calendar. John is asking you to help him solve the problem of converting ROW's calendar into Island's calendar. Here is the question.
You are given a date (today's date). You have to determine the Island week's number. The catch here is that the Island year starts from 1st week of February and every Island's week starts from Sunday and ends on a Saturday. Write a SQL statement in SQL Server to achieve this. Use SQL Server functions and devise a logic.
Input parameter: Any date.
Output parameter: Week No in Rasa Calendar.
Here is an example:
Date: 5th May 2015 --
Week No in ROW Calendar:19
Week No in Rasa's Calendar:14
Date: Jan 1 2017:
Week No in ROW Calendar:1
Week No in Rasa's Calendar:49
My question: can this be achieved in SQL Server?
My homework: I tried a couple of ways to solve the problem.
Approach #1:
Step 1: Calculate the total no of days between today and Feb 1.
Step 2: Divide it by 7 and add 1 to the result.
Later found out that this approach will not work if Feb 1 is on any day other than Sunday.
Eg: 1st Feb is on Wednesday. 5th Feb will be on Monday
So, 1st Feb is on Rasa's week 1, and 5th Feb is on Rasa's week no 2. According to my approach 1st and 5th feb are on week 1 which is incorrect.
Approach #2:
I thought removing 5 weeks of Jan from ROW's calendar should work
select
case
when f.RasaWeek = -4 then 48
when f.RasaWeek = -3 then 49
when f.RasaWeek = -2 then 50
when f.RasaWeek = -1 then 51
when f.RasaWeek = 0 then 52
else
f.RasaWeek
end as Rasa_week,
f.year, f.month, f.date
from
(select
datepart(wk, date) - 5 as RasaWeek, *
from
<datetable>
where
Year(date) in (2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018)) as f
Info: I tested this on a <datetable> but this code will break if there is a 53rd week. Notice that I was not able to take care of the 53rd week.
Any inputs to solve this problem are welcome.
With dates, it's almost always easier to make a calendar table and store the data you care about rather than trying to do anything beyond basic date arithmetic. Use SQL's strengths: storing and retrieving data.
In this case, what you care about are all of the first Sundays in February. If you store these dates in a table, the solution is:
RETURN
SELECT TOP 1
DATEDIFF(day,[date],#input_date) / 7
FROM IslandCalendarStartDates
WHERE [date] <= #input
ORDER BY [date] DESC
This way you don't need to worry about leap years or 53-weeks, or any of the edge cases. Just count the days from the most recent first Sunday in February and divide by 7. If you need to change the solution to accommodate a different start date, you only change the data, not the code.
Related
I need to return the year (number) for the previous month. Like 15-Jan-2023, returns 2022.
Simple but I could not find any related solution.
So far I´m using -31 days but this is not as good as February I need to take care and adjust.
< year(getdate()-32)
SELECT DATEPART(YEAR,DATEADD(MONTH,-1,GETDATE()))
example:
SELECT DATEPART(YEAR,DATEADD(MONTH,-1,'15-JAN-2023'))
returns 2022
I am trying to calculate the number of days that have passed between 1/1/1900 and 5/1/2019.
I have tried this using several dates and get the same out come.
The value returned is 2 days off.
--
-- calculate the number of days between 1/1/1900 and 5/1/2018
--
SELECT DATEDIFF(DAY,CONVERT(DATE,'1/1/1900'),CONVERT(DATE,'5/1/2018'))
Expected Result: 43221
Actual Result: 43219
Thank you for your help!
DATEDIFF returns the number of days between the two dates. So if you want 1900-01-01 to be numbered as day 1, then you must add 1 to any difference you get from DATEDIFF. In Excel, day 0 is 1899-12-31.
Secondly, Excel treats 1900 as a leap year, and has a 29-Feb-1900 (day 60 in the Excel numbering system iirc). This was a holdover from Lotus 1-2-3 which originally used a simplified algorithm for leap years (treating every year divisible by 4 as a leap), and remains for backward compatibility
If you combine these two faults, these account for your off-by-two results.
Following are two ways of adding days and months to a given date. Both seem to be logically correct but returns different values.
Column number 1: Add months and then days,
Column number 2: Add days and then months
DECLARE #d DATE = '20140128'
SELECT DATEADD(DAY, 3, DATEADD(MONTH, 1, #d)) Add_Months_Days,
DATEADD(MONTH, 1, DATEADD(DAY, 3, #d)) Add_Days_Months
Results and fiddle
Add_Months_Days Add_Days_Months
---------------- ----------------
2014-03-03 2014-02-28
I understand why it is happening and both are logical too. But in a situation where we need to add months and days to a given date at the same time, is there a standard way to do this?
They are both logical but return different results as implicit in your question is the truncation of the add-month result to month-end, should it take you over a month-boundary. You have this in the second query, but not the first.
I believe they are both correct, but they do different things.
MSDN states:
If datepart is month and the date month has more days than the return
month and the date day does not exist in the return month, the last
day of the return month is returned.
In the first example you first add 1 month to 20140128 making it 20140228 (a valid date) and then add 3 days, ending up with 20140303.
In the second example however you add 3 days, getting 20140131 and then add 1 month, but since February 2014 only has 28 days you'll get 20140228 as the result as the dateadd operation returns the last day of the month as stated above.
I don't believe there is a standard way of doing this, I would think it comes down to the specific business requirements, however I personally think doing month-day and getting the latter end date might be "more correct" as it seem to follow from the intent (the day-month method seem to lose a few days).
Adding MONTH (1) to a date ("20140128"), will not add total days of the month (Jan - 31, Feb - 28 or 29, etc.). It will add the given MONTH value (1) to the input date and result will be "20140228".
Please refer this Question and Answer
I have produced a report where the user will need to view financial years data.
So for example April 2010 - March 2011 will have one years data however if the user selects this as in my image, data for January, February, March in 2010 will be brought as well as January, Febrary and March 2011, when I dont want the Jan,Feb,Mar for 2010 as the financial year begins in April.
I therfore need to be able select a data range using parameters to stop bringing data through that I didnt ask for.
Can anyone advise me how to do this?
You can build a month-year key to use instead of your ad-hoc year and month parameters. You can then display it for example as YYYY/MM - so that you can select 2010/04 through 2011/03.
Another option would be to have from month (with year) to month (with year).
Yet another option would be to have a year, month, and number-of-months, selecting 2010, 04, then 12 for number-of-months.
Your two parameters aren't aware of eachother in the way that you want it to be.
I want to make a user defined function for calculating the month number from date.
But the problem is that I have the months numbered as 1, 2, 3 ... and each month is of 26 days, that makes a total of 13 months in the year, rather than 12
any useful help?
I'm not going to ask you why you'd want to do this. But here we go:
select convert(int, (datepart(Dayofyear, #date)-1)/26.0)+1