# Macro for week number

Is there a macro or package to calculate the ISO week number or alternative can someone help me with one?

-

## 3 Answers

There is no package as such, but Taco Hoekwater, wrote a macro called calendarweek that you can use. You find it on CTAN at weekday.

Remark. The macro returns 0 for the first 4 days of 2015, while the 5th day returns week 2. Because the algorithm is not explained, there does not seem to be an easy way to find out what is wrong. Most weeks have the correct number though.

Here is a minimal example, as to how to use it:

\documentclass{article}
%% calendarweek.tex
%% 2006 (C) Taco Hoekwater, public domain
%% Watch out: Dec 29 can be week 1 of the next year; and Jan 3 can be
%% week 53 of the previous year.

\def\Expr#1{\the\numexpr #1\relax}

\def\Modulonumber#1#2{\Expr{#2-((((#2+(#1/2))/#1)-1)*#1)}}
\def\Divisionnumber#1#2{\Expr{(2*#2-#1)/(2*#1)}}

\def\Mod#1#2{\Modulonumber{\Expr{#2}}{\Expr{#1}}}
\def\Div#1#2{\Divisionnumber{\Expr{#2}}{\Expr{#1}}}

\def\Jday#1#2#3%
{\Expr{#1+\Div{((153*(\Expr{#2+(12*(\Div{14-#2}{12}))-3}))+2)}
{5}+365*(\Expr{#3+4800-(\Div{14-#2}{12})})+
(\Div{\Expr{#3+4800-(\Div{14-#2}{12})}}{4})-
(\Div{\Expr{#3+4800-(\Div{14-#2}{12})}}{100})+
(\Div{\Expr{#3+4800-(\Div{14-#2}{12})}}{400})-32045 }}

\def\cwhlp#1#2#3%
{\Expr{\Mod {\Mod {\Mod {\Expr
{\Jday{#1}{#2}{#3}+31741-\Mod{\Jday{#1}{#2}{#3}}{7}}}%
{146097}}{36524}}{1461}}}

\def\calendarweek#1#2#3%
{\Expr{\Expr{\Div{\Expr{\Mod{\cwhlp{#1}{#2}{#3}-
\Expr{\Div{\cwhlp{#1}{#2}{#3}}{1460}}}{365}+
\Expr{\Div{\cwhlp{#1}{#2}{#3}}{1460}}}}{7} +1}}}

\begin{document}

\calendarweek{28}{2}{2011}

\end{document}

-

Here is expl3:

\documentclass{minimal}

\usepackage{expl3}

\ExplSyntaxOn

%% http://www.tondering.dk/claus/cal/week.php#calcweekno
\int_new:N \l_week_number_year_int
\int_new:N \l_week_number_month_int
\int_new:N \l_week_number_day_int
\int_new:N \l_week_number_a_int
\int_new:N \l_week_number_b_int
\int_new:N \l_week_number_c_int
\int_new:N \l_week_number_s_int
\int_new:N \l_week_number_e_int
\int_new:N \l_week_number_f_int
\int_new:N \l_week_number_g_int
\int_new:N \l_week_number_d_int
\int_new:N \l_week_number_n_int
\int_new:N \l_week_number_W_int

\cs_new:Nn \week_number:nnn {

\int_set:Nn \l_week_number_year_int { #1 }
\int_set:Nn \l_week_number_month_int { #2 }
\int_set:Nn \l_week_number_day_int { #3 }

\int_compare:nNnTF { \l_week_number_month_int } < { 3 } % jan or feb
{ % true

\int_set:Nn \l_week_number_a_int { \l_week_number_year_int - 1 }

\int_set:Nn \l_week_number_b_int {
\int_div_truncate:nn { \l_week_number_a_int } { 4 }
- \int_div_truncate:nn { \l_week_number_a_int } { 100 }
+ \int_div_truncate:nn { \l_week_number_a_int } { 400 }
}

\int_set:Nn \l_week_number_c_int {
\int_div_truncate:nn { \l_week_number_a_int - 1 } { 4 }
- \int_div_truncate:nn { \l_week_number_a_int - 1 } { 100 }
+ \int_div_truncate:nn { \l_week_number_a_int - 1 } { 400 }
}

\int_set:Nn \l_week_number_s_int {
\l_week_number_b_int - \l_week_number_c_int }

\int_zero:N \l_week_number_e_int

\int_set:Nn \l_week_number_f_int { \l_week_number_day_int - 1
+ 31 * ( \l_week_number_month_int - 1 ) }

} % end true
{ % false

\int_set_eq:NN \l_week_number_a_int \l_week_number_year_int

\int_set:Nn \l_week_number_b_int {
\int_div_truncate:nn { \l_week_number_a_int } { 4 }
- \int_div_truncate:nn { \l_week_number_a_int } { 100 }
+ \int_div_truncate:nn { \l_week_number_a_int } { 400 }
}

\int_set:Nn \l_week_number_c_int {
\int_div_truncate:nn { \l_week_number_a_int - 1 } { 4 }
- \int_div_truncate:nn { \l_week_number_a_int - 1 } { 100 }
+ \int_div_truncate:nn { \l_week_number_a_int - 1 } { 400 }
}

\int_set:Nn \l_week_number_s_int {
\l_week_number_b_int - \l_week_number_c_int }

\int_set:Nn \l_week_number_e_int { \l_week_number_s_int + 1 }

\int_set:Nn \l_week_number_f_int { \l_week_number_day_int
+ \int_div_truncate:nn {
153 * ( \l_week_number_month_int - 3 ) + 2 } { 5 }
+ 58 + \l_week_number_s_int }

} % end false

\int_set:Nn \l_week_number_g_int {
\int_mod:nn { \l_week_number_a_int + \l_week_number_b_int } { 7 }  }

\int_set:Nn \l_week_number_d_int {
\int_mod:nn { \l_week_number_f_int + \l_week_number_g_int
- \l_week_number_e_int } { 7 }  }

\int_set:Nn \l_week_number_n_int {
\l_week_number_f_int + 3 - \l_week_number_d_int }

\int_compare:nNnTF { \l_week_number_n_int } < { 0 }
{ %true

\int_set:Nn \l_week_number_W_int { 53
- \int_div_truncate:nn { \l_week_number_g_int
- \l_week_number_s_int } { 5 } }

} % end true
{ % false

\int_compare:nNnTF { \l_week_number_n_int } > { 364
+ \l_week_number_s_int }
{ % true

\int_set:Nn \l_week_number_W_int { 1 }

} % end true
{ % false

\int_set:Nn \l_week_number_W_int { \int_div_truncate:nn {
\l_week_number_n_int } { 7 } + 1 }

} % end false

} % end false

}
\ExplSyntaxOff

\begin{document}

\ExplSyntaxOn
\week_number:nnn { 2010 } { 01 } { 01 }
\int_to_arabic:n { \l_week_number_W_int }
\ExplSyntaxOff

\end{document}

-

Just an idea:

The datenumber package can give you the day as number. By subtracting the number of Jan 1st of the same year and adding one you can get the day of the year. The number of the week is then about this number divided by seven.

Because ISO weeks start by definition with a Monday you have to add an offset:

[ISO week number] =
floor( ( [number of selected date] - [number of first Monday of the year] + 1 ) / 7 ) + 1


The package also gives you the possibility to check the day of the week, which allows you to find the first Monday of the year.

I'm not sure if I understood ISO week numbers correctly and I might be off with the equations (it's 1.30am), but you get the idea.

-
The ISO week number starts with a Thursday! So some months can have 5 weeks and others 4. It is a somewhat convoluted scheme. Thanks for the answer though. –  Yiannis Lazarides Feb 13 '11 at 1:42
@saltypen: The Wikipedia article you linked states: "Weeks start with Monday". Ok, I see now: "Week 1 := the week with the year's first Thursday in it (the ISO 8601 definition)". But the principle is the same! –  Martin Scharrer Feb 13 '11 at 1:47
Thanks, but how do I determine the first Thursday of the year? –  Yiannis Lazarides Feb 18 '11 at 7:45
@saltypen: The package gives you the day-of-the-week as number in datedayname Mo=1,Su=7 => Thu=5. You look which day-of-the-week the 1.1. is, then you simply calculate (5 - weekday(1.1.) ) modulo 7. The result is the number of days you have to add to 1.1. to get to the first Thursday. –  Martin Scharrer Feb 18 '11 at 8:25