(An extra answer, since this method is a bit different.)
This method is about using a tally table with dates and date related stuff.
Then such calendar table can be used to lookup the year and week.
For example
Create calendar table
create table REF_Calendar (
cal_date date primary key not null,
cal_year smallint not null,
cal_month tinyint not null,
cal_day tinyint not null,
cal_dayofyear smallint not null,
cal_quarter tinyint not null,
cal_weekday_abbrev char(3) not null,
cal_iso_week tinyint,
cal_df7_week tinyint not null,
cal_df7_weekday tinyint not null,
cal_df1_week tinyint,
cal_df1_weekday tinyint,
cal_mooncycle tinyint,
index idx_Calendar_year_week unique (cal_year, cal_df7_week, cal_df7_weekday)
);
Fill the calendar
SET DATEFIRST 7; -- 7: week starts on sunday
declare @startdate date="2020-01-01";
declare @enddate date="2023-01-01";
with rcte_calendar as (
select @startdate as cal_date
union all
select dateadd(day, 1, cal_date)
from rcte_calendar
where cal_date < @enddate
)
insert into ref_calendar
(cal_date, cal_year, cal_month, cal_day, cal_dayofyear, cal_quarter, cal_weekday_abbrev,
cal_df7_week, cal_df7_weekday, cal_mooncycle)
select
cal_date
, datepart(year, cal_date) as cal_year
, datepart(month, cal_date) as cal_month
, datepart(day, cal_date) as cal_day
, datepart(dayofyear, cal_date) as cal_dayofyear
, datepart(quarter, cal_date) as cal_quarter
, lower(left(datename(weekday, cal_date), 3)) as cal_weekday_abbrev
, datepart(week, cal_date) as cal_df7_week
, datepart(weekday, cal_date) as cal_df7_weekday
, abs(1-abs(round(((14-1.0*CONVERT(int, CONVERT(nvarchar(2), cal_date, 131)))/14)
, 1, 1)))*100 as cal_mooncycle
from rcte_calendar cte
where not exists (
select 1
from ref_calendar cal
where cal.cal_date = cte.cal_date
)
option (maxrecursion 0);
Updating extra’s
SET DATEFIRST 1; -- 1: week starts on monday
update ref_calendar
set cal_df1_week = datepart(week, cal_date)
, cal_df1_weekday = datepart(weekday, cal_date)
, cal_iso_week = datepart(iso_week, cal_date)
where cal_df1_week is null
or cal_df1_weekday is null
or cal_iso_week is null;
Check how it looks
select top 9 *
from ref_calendar
where cal_mooncycle = 100
and cal_date >= getdate()
and cal_year <= 1 + datepart(year, current_timestamp)
order by cal_date asc;
cal_date | cal_year | cal_month | cal_day | cal_dayofyear | cal_quarter | cal_weekday_abbrev | cal_iso_week | cal_df7_week | cal_df7_weekday | cal_df1_week | cal_df1_weekday | cal_mooncycle |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2021-12-17 | 2021 | 12 | 17 | 351 | 4 | fri | 50 | 51 | 6 | 51 | 5 | 100 |
2021-12-18 | 2021 | 12 | 18 | 352 | 4 | sat | 50 | 51 | 7 | 51 | 6 | 100 |
2021-12-19 | 2021 | 12 | 19 | 353 | 4 | sun | 50 | 52 | 1 | 51 | 7 | 100 |
2022-01-16 | 2022 | 1 | 16 | 16 | 1 | sun | 2 | 4 | 1 | 3 | 7 | 100 |
2022-01-17 | 2022 | 1 | 17 | 17 | 1 | mon | 3 | 4 | 2 | 4 | 1 | 100 |
2022-01-18 | 2022 | 1 | 18 | 18 | 1 | tue | 3 | 4 | 3 | 4 | 2 | 100 |
2022-02-14 | 2022 | 2 | 14 | 45 | 1 | mon | 7 | 8 | 2 | 8 | 1 | 100 |
2022-02-15 | 2022 | 2 | 15 | 46 | 1 | tue | 7 | 8 | 3 | 8 | 2 | 100 |
2022-02-16 | 2022 | 2 | 16 | 47 | 1 | wed | 7 | 8 | 4 | 8 | 3 | 100 |
Test applying the calendar to a table
DECLARE @Test TABLE (col char(7));
INSERT INTO @Test VALUES
('2021-01'), ('2021-02')
, ('2021-48')
, ('2022-01'), ('2022-02')
;
select *
from @test t
outer apply (
select
min(cal_date) as startofweek
, max(cal_date) as endofweek
from (values (try_cast(left(col, 4) as int),
abs(try_cast(right(col, 2) as int)))
) as val(yr, ww)
join ref_calendar as cal
on ((cal_year = yr and cal_df7_week = ww)
or (ww = 1 and cal_year = yr-1 and cal_df7_week = 53)
or (ww = 53 and cal_year = yr+1 and cal_df7_week = 1))
) cal
col | startofweek | endofweek |
---|---|---|
2021-01 | 2020-12-27 | 2021-01-02 |
2021-02 | 2021-01-03 | 2021-01-09 |
2021-48 | 2021-11-21 | 2021-11-27 |
2022-01 | 2021-12-26 | 2022-01-01 |
2022-02 | 2022-01-02 | 2022-01-08 |
Demo on db<>fiddle here