Your challenge is to write a procedure that returns the week number for a given date. If week number belongs to a week numbering of the previous year then that week number should be returned instead of the zero week.
Here is my PL/I version using bit strings to turn calculations into simple string search:
*PROCESS MARGINS(1, 140);
test: proc options (main);
dcl 1 date_type based,
2 day pic'99',
2 month pic'99',
2 year pic'9999';
dcl d like date_type;
/* fill date structure */
d.day = '06';
d.month = '11';
d.year = '2018';
/* test our proggy */
put skip list (trim(week(d)));
/****************************************************************************************************************/
week: proc (day) returns (fixed bin (31));
dcl day like date_type;
dcl (from, to) like date_type;
dcl (days_from, days_to) fixed bin (31);
dcl total_days fixed bin (31);
dcl week_index fixed bin (31);
dcl weeknro fixed bin (31);
dcl result bit (*) aligned controlled;
dcl weeks (7) bit (7) aligned nonasgn
init ('0100000'b, '0010000'b, '0001000'b, '0000100'b, '0000100'b, '0000010'b, '0000001'b);
dcl masks (7) bit (7) aligned nonasgn
init ('0111100'b, '1111000'b, '1110001'b, '1100011'b, '1000111'b, '0001111'b, '0011110'b);
dcl bool bit (1);
dcl (days, weekday, tally, substr, lbound, hbound, copy, omitted) builtin;
/* we start from first of january, naturally */
from.day = '01';
from.month = '01';
from.year = day.year;
to = day;
days_from = days(string(from), 'DDMMYYYY');
days_to = days(string(to), 'DDMMYYYY');
/* calculate required length for the bit string */
total_days = days_to - days_from + 1;
/* allocate bit string, holding date range */
allocate result bit (total_days);
/* fill bit string with correct rotation of the week pattern */
week_index = weekday(days_from);
result = copy(weeks(week_index), total_days / 7) || substr(weeks(week_index), 1, mod(total_days, 7));
/* find the number of weeks starting on monday */
weeknro = tally(result, '1'b);
/* free allocated storage */
free result;
/* first week can be partial and if it includes thursday, then add it to the result */
bool = substr(masks(week_index), 1, 1);
if bool then weeknro += 1;
/* maybe first days of the year belong to week numbering of the previous year? */
if weeknro = 0 then
do;
from.year -= 1;
to = from;
to.day = '31';
to.month = '12';
days_from = days(string(from), 'DDMMYYYY');
days_to = days(string(to), 'DDMMYYYY');
total_days = days_to - days_from + 1;
allocate result bit (total_days);
week_index = weekday(days_from);
result = copy(weeks(week_index), total_days / 7) || substr(weeks(week_index), 1, mod(total_days, 7));
weeknro = tally(result, '1'b);
free result;
end;
return (weeknro);
end week;
/****************************************************************************************************************/
end test;