juergen@julien.informatik.uni-dortmund.de (Juergen Stuber) (04/10/91)
Recently someone posted a tex file to generate a calendar.
It didn't suit me, so I hacked up my own. It is in german,
but customization to other languages should be easy.
---------- cut here ----------
% calendar.sty - print calendar
% Copyright (C) 1991 J"urgen Stuber
%
% This program is free software; you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation; either version 1, or (at your option)
% any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have a copy of the GNU General Public License;
% if not, write to the Free Software Foundation, Inc.,
% 675 Mass Ave, Cambridge, MA 02139, USA.
%
% History:
% 10.4.1991 js - posted
%
% Description:
% This will generate a calendar in the following format:
% +----------+----------+ ... +----------+
% | Januar | Februar | | Dezember |
% +----------+----------+ ... +----------+
% + 1 DI | 1 FR | | 1 SO |
% +----------+----------+ ... +----------+
% + 2 MI | 2 SA | | 2 MO |
% +----------+----------+ ... +----------+
% .
% .
% .
%
% +----------+----------+ ... +----------+
% |31 DO | | |31 DI |
% +----------+----------+ ... +----------+
%
% Because of space limitations the calendar is printed on 3 pages.
%
% Features:
% - number of week in year
% - handles holidays and birthdays in a flexible way
% - computes day of week & easter date
%
% Limitations:
% - does not print year due to lack of space
% - number of annotations per date is limited to two due to lack of space
% - does not compute moon phases
% - does not compute beginning of spring, summer, etc.
%
% Usage:
% generate a LaTex file calendar.tex like the following:
%
%--- beginning of calendar.tex ------------------------------
% \documentstyle[german]{calendar}
%
% \def\weekdayname#1{%
% \ifcase#1 \relax
% MO\or DI\or MI\or DO\or FR\or SA\or SO%
% \fi
% }
%
% \def\monthname#1{%
% \ifcase#1 \relax
% Januar\or Februar\or M"arz\or April\or Mai\or Juni\or
% Juli\or August\or September\or Oktober\or November \or Dezember%
% \fi
% }
%
% \begin{document}%
% \setYear{1991}%
% \input{holiday}%
% \input{birthday}%
% \typesetYear%
% \end{document}
%--- end of calendar.tex ------------------------------
%
% holiday.tex and birthday.tex contain declarations in the following
% formats:
%
% \annual{text}{day.month.}{holidayflag}
% \annualMovable{text}{day.month.}{dayOfWeek}{holidayflag}
% \easterRelative{text}{offset}{holidayflag}
% \anniversary{text}{day.month.year}{holidayflag}
%
% \annual will generate an annotation for the specified day containing
% the given text. If holidayflag is 1 the day will be marked as
% a holiday, i.e., printed in boldface.
% \annualMovable will generate the annotation for the next day with
% matching day of the week on or after the specified date.
% The day of the week is encoded as 0 for monday up to 6 for sunday.
% \easterRelative will generate the annotation for the day with
% the specified offset from easter.
% \anniversary will generate an annotation consisting of text and the
% number of the anniversary.
%
% Here is a sample file containing declarations of holidays for
% Northrhine-Westfalia. Some other german holidays are included but
% commented out.
%
%--- beginning of holiday.tex ------------------------------
% \annual{Neujahr}{1.1.}{1}%
% \annual{Heilige Drei K"onige}{6.1.}{0}%
% %\annual{Valentinstag}{14.2.}{0}%
% \easterRelative{Rosenmontag}{-48}{0}%
% %\easterRelative{Fastnacht}{-47}{0}%
% \easterRelative{Aschermittwoch}{-46}{0}%
% \easterRelative{Karfreitag}{-2}{1}%
% \easterRelative{Ostern}{0}{1}%
% \easterRelative{Ostern}{1}{1}%
% \annual{Tag der Arbeit}{1.5.}{1}%
% \easterRelative{Himmelfahrt}{39}{1}%
% \easterRelative{Pfingsten}{49}{1}%
% \easterRelative{Pfingsten}{50}{1}%
% \easterRelative{Fronleichnam}{60}{1}%
% %\annual{Mari"a Himmelfahrt}{15.8.}{0}%
% %\annual{Reformationstag}{31.10.}{0}%
% \annual{Allerheiligen}{1.11.}{1}%
% %\annualMovable{Volkstrauertag}{13.11.}{6}{0}%
% \annualMovable{Bu"s- und Bettag}{16.11.}{2}{1}%
% %\annualMovable{Totensonntag}{20.11.}{6}{0}%
% %\annualMovable{1. Advent}{27.11.}{6}{0}%
% %\annualMovable{2. Advent}{4.12.}{6}{0}%
% %\annualMovable{3. Advent}{11.12.}{6}{0}%
% %\annualMovable{4. Advent}{18.12.}{6}{0}%
% %\annual{Mari"a Empf"angnis}{8.12.}{0}%
% \annual{Heiligabend}{24.12.}{0}%
% \annual{Weihnachten}{25.12.}{1}%
% \annual{Weihnachten}{26.12.}{1}%
% \annual{Silvester}{31.12.}{0}%
%--- end of holiday.tex ------------------------------
%
% You may change the following parameters:
% \columnheight height of the entire column, including title
% \titleheight height of title containing month name
% \itemwidth width of one column
% \daywidth position of right edge of day number in column
% \weekdaywidth width reserved for day of week
%
%----------------------------------------------------------------------
\input{article.sty}
\pagestyle{empty}%
\evensidemargin=0pt
\oddsidemargin=\evensidemargin
\topmargin=0pt
\topmargin 0pt
\headheight 0pt
\headsep 0pt
\footskip 0pt
%
\textheight 280mm
%----------------------------------------------------------------------
% list macros (see TeXBook, Dirty Tricks)
\let\sep\relax
\toksdef\tb=2
\def\leftlist#1{%
\def\sep##1{\relax##1\cr}%
\vbox{\halign{##\hfil\cr#1}}%
}
\def\@ifundef#1{\expandafter\ifx\csname#1\endcsname\relax}
\def\@nameedef#1{\expandafter\edef\csname #1\endcsname}
\newcount\tmpcnt
\def\remainder#1by#2{%
\tmpcnt=#1 %
\divide\tmpcnt by #2 %
\multiply\tmpcnt by #2 %
\advance #1 by -\tmpcnt}
%----------------------------------------------------------------------
\newcount\curday % day
\newcount\curmonth % month
\newcount\curweekday % day of week, 0=Monday
\newcount\curyear % year
\newcount\daycount % day of year
\newcount\weekcount % week of year
\newcount\leapyear % 0=normal year, 1=leap year
\newcount\easter % easter date, as day of year
\newcount\startweekday % first day of week in year
\def\setYear#1{
\global\curyear=#1 %
{% compute leap year
\newcount\rf \rf=\curyear \remainder\rf by{4}%
\newcount\rh \rh=\curyear \remainder\rh by{100}%
\newcount\rfh \rfh=\curyear \remainder\rfh by{400}%
\ifnum\rfh=0 %
\global\leapyear=1 %
\else
\ifnum\rh=0 %
\global\leapyear=0 %
\else
\ifnum\rf=0 %
\global\leapyear=1 %
\else
\global\leapyear=0 %
\fi
\fi
\fi
}%
{% compute easter date
% this is the easter formula by C.F.Gauss -- valid up to 8201
% (no limitation, considering the current rate of environmental destruction)
\newcount\tmpa \tmpa=\curyear \remainder\tmpa by{19}%
\newcount\tmpb \tmpb=\curyear \remainder\tmpb by{4}%
\newcount\tmpc \tmpc=\curyear \remainder\tmpc by{7}%
\newcount\yh \yh=\curyear \divide\yh by 100 %
\newcount\yfh \yfh=\curyear \divide\yfh by 400 %
\newcount\m \m=\yh
\multiply\m by 8 %
\advance\m by 13 %
\divide\m by 25 %
\advance\m by -2 %
\newcount\s \s=\yh \advance\s by -\yfh \advance\s by -2 %
\newcount\M \M=15 %
\advance\M by \s
\advance\M by -\m
\remainder\M by{30}%
\newcount\N \N=6 %
\advance\N by \s
\remainder\N by{7}%
\newcount\d \d=\tmpa
\multiply\d by 19 %
\advance\d by \M
\remainder\d by{30}%
\newcount\D
\ifnum\d=29 %
\D=28 %
\else
\ifnum\d=28 %
\ifnum\d>10 %
\D=27 %
\else
\D=\d
\fi
\else
\D=\d
\fi
\fi
\multiply\tmpb by 2 %
\multiply\tmpc by 4 %
\newcount\e \e=\D
\multiply\e by 6 %
\advance\e by \tmpb
\advance\e by \tmpc
\advance\e by \N
\remainder\e by{7}%
\advance\e by 80 %
\advance\e by \leapyear
\advance\e by \D
\global\easter=\e
}% pooh -- done it
{% compute starting day of week --- we know easter is on a sunday
\newcount\fsd \fsd=\easter \remainder\fsd by{7}%
\newcount\wd \wd=6 \advance\wd by -\fsd
\global\startweekday=\wd
}%
}
%----------------------------------------------------------------------
\def\monthlength#1{%
\ifnum\leapyear=0
\ifcase#1 %
31\or28\or31\or30\or31\or30\or
31\or31\or30\or31\or30\or31%
\fi
\else
\ifcase#1 %
31\or29\or31\or30\or31\or30\or
31\or31\or30\or31\or30\or31%
\fi
\fi
}
\def\monthoffset#1{%
\ifnum\leapyear=0 %
\ifcase#1 %
0\or31\or59\or90\or120\or151\or
181\or212\or243\or273\or304\or334%
\fi
\else
\ifcase#1 %
0\or31\or60\or91\or121\or152\or
182\or213\or244\or274\or305\or335%
\fi
\fi
}
%----------------------------------------------------------------------
% typesetting individual days
% #1 : day in month
% #2 : Holiday flag (0=workday, 1=holiday)
\def\typesetDay#1#2{\relax%
\ifnum#2=0 %
{#1}%
\else
{\bf #1}%
\fi
}
% #1 : weekday code 0..7, 0=Monday
% #2 : Holiday flag (0=workday, 1=holiday)
\def\typesetWeekday#1#2{%
\ifnum#2=0 %
{\weekdayname{#1}}%
\else
{\bf\weekdayname{#1}}%
\fi
}
% #1 : annotations, format a1\sepa 2\sep..\sep an
\def\typesetAnnotations#1{{\leftlist{#1}}}
\newdimen\columnheight \columnheight=247mm
\newdimen\titleheight \titleheight=10mm
\newdimen\itemwidth \itemwidth=43mm
\newdimen\daywidth \daywidth=6mm
\newdimen\weekdaywidth \weekdaywidth=9mm
\newdimen\itemheight \itemheight=\columnheight
\advance\itemheight by -\titleheight
\divide\itemheight by 31
\advance\itemheight by -2.4pt
\def\typesetItem{%
\@ifundef{ann\the\daycount}%
\def\ann{}%
\else
\def\ann{\@nameuse{ann\the\daycount}}%
\fi
\@ifundef{hol\the\daycount}%
\ifnum\curweekday=6 %
\def\hol{1}%
\else
\def\hol{0}%
\fi
\else
\def\hol{\@nameuse{hol\the\daycount}}%
\fi
\vbox{%
\kern1pt%
\hbox to \itemwidth{%
\vbox to \itemheight{%
\vfil
\hbox to\daywidth{\hfil{\large\typesetDay{\the\curday}{\hol}}}%
\vfil}%
\kern2mm%
\vbox to \itemheight{%
\vfil
\hbox to\weekdaywidth{%
{\large\typesetWeekday{\the\curweekday}{\hol}}%
\hfil}%
\vfil}%
\vbox to \itemheight{%
{\scriptsize\typesetAnnotations{\ann}}%
\vfil
}%
\hfil
\ifnum\curweekday=0 %
\vbox to \itemheight{%
\kern1pt%
\hbox{{\scriptsize\the\weekcount}\kern1pt}%
\vfil
}%
\global\advance \weekcount by 1 %
\else\relax\fi
}%
\kern1pt%
\hrule}}
\def\typesetDummyItem{%
\vbox{%
\kern1pt%
\hbox to \itemwidth{%
\vbox to \itemheight{%
\vfil
}%
\hfil
}%
\kern1pt
\hrule}}
\newcount\lastday
% #1 : number of month, 1=January
\def\typesetMonth#1{%
\vbox{%
\vbox to \titleheight{%
\hrule
\kern2pt%
\vfil
\hbox to \itemwidth{\hfil{\LARGE\bf\strut\monthname{#1}}\hfil}%
\vfil
\hrule height0.8pt%
}
\curday=0 %
\edef\lastday{\monthlength{#1} }%
\loop\ifnum\curday<\lastday
\global\advance \curday by 1 %
\typesetItem
\global\advance \daycount by 1 %
\global\advance \curweekday by 1 %
\ifnum\curweekday>6 %
\global\advance \curweekday by -7 %
\else\relax\fi
\repeat
\loop\ifnum\curday<31 %
\global\advance \curday by 1 %
\typesetDummyItem
\repeat
\vfil
}%
}
% #2 : first month
% #3 : last month+1
\def\typesetPartialYear#1#2{%
\hrule
\hbox{%
\curmonth=#1 %
\loop\ifnum\curmonth<#2 %
\vrule %
\typesetMonth{\the\curmonth}%
\global\advance\curmonth by 1 %
\repeat
\vrule
}%
\hrule
}
\def\typesetYear{%
\curweekday=\startweekday
\weekcount=1 %
\daycount=0 %
\newcount\firstmonth
\newcount\endmonth
\firstmonth=0 %
\loop\ifnum\firstmonth<12 %
\endmonth=\firstmonth \advance\endmonth by 4 %
\typesetPartialYear{\the\firstmonth}{\the\endmonth}%
\eject
\advance\firstmonth by 4 %
\repeat
}
%----------------------------------------------------------------------
\def\dayOf#1.#2.#3 {#1}
\def\monthOf#1.#2.#3 {#2}
\def\yearOf#1.#2.#3 {#3}
\def\addAnn#1#2#3{%
\@ifundef{ann#1}%
\@namedef{ann#1}{}%
\else
\relax
\fi
\tb=\expandafter{#2}%
\@nameedef{ann#1}{\@nameuse{ann#1}\noexpand\sep{\the\tb#3}}%
}
\def\addHol#1#2{%
\ifnum#2=1 %
\@namedef{hol#1}{1}%
\else\relax\fi
}
%----------------------------------------------------------------------
% entries for holidays
% #1 : text
% #2 : date in format d.m.
% #3 : holiday flag
\def\annual#1#2#3{%
\edef\dof{\dayOf#2 }%
\edef\mof{\monthOf#2 }%
\tmpcnt=\mof
\advance\tmpcnt by -1 %
\edef\moff{\monthoffset{\the\tmpcnt}}%
\tmpcnt=\moff
\advance\tmpcnt by \dof
\advance\tmpcnt by -1 %
\edef\doy{\the\tmpcnt}%
\addAnn{\doy}{#1}{}%
\addHol{\doy}{#3}%
}
% #1 : text
% #2 : date in format d.m.
% #3 : day of week
% #4 : holiday flag
\def\annualMovable#1#2#3#4{%
\edef\dof{\dayOf#2 }%
\edef\mof{\monthOf#2 }%
\curday=\mof
\advance\curday by -1 %
\edef\moff{\monthoffset{\the\curday}}%
\curday=\moff %
\advance\curday by \dof
\advance\curday by -1 %
\curweekday=700 %
\advance\curweekday by -\curday
\advance\curweekday by -\startweekday
\advance\curweekday by#3 %
\remainder\curweekday by{7}%
\advance\curday by \curweekday
\edef\doy{\the\curday}%
\addAnn{\doy}{#1}{}%
\addHol{\doy}{#4}%
}
% #1 : text
% #2 : offset to easter (may be negative)
% #3 : holiday flag
\def\easterRelative#1#2#3{%
\tmpcnt=\easter %
\advance\tmpcnt by #2 %
\edef\doy{\the\tmpcnt}%
\addAnn{\doy}{#1}{}%
\addHol{\doy}{#3}%
}
% #1 : text
% #2 : date in format d.m.y
% #3 : holiday flag
\def\anniversary#1#2#3{%
\edef\dof{\dayOf#2 }%
\edef\mof{\monthOf#2 }%
\edef\yof{\yearOf#2 }%
\tmpcnt=\mof
\advance\tmpcnt by -1 %
\edef\moff{\monthoffset{\the\tmpcnt}}%
\tmpcnt=\moff
\advance\tmpcnt by \dof
\advance\tmpcnt by -1 %
\edef\doy{\the\tmpcnt}%
\tmpcnt=\curyear %
\advance\tmpcnt by -\yof
\addAnn{\doy}{#1 }{\the\tmpcnt}%
\addHol{\doy}{#3}%
}
---------- cut here ----------
Enjoy
-------------------------------------------------------
Juergen Stuber (juergen@ls5.informatik.uni-dortmund.de)