summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/dates
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/dates
Initial commit
Diffstat (limited to 'macros/latex/contrib/dates')
-rw-r--r--macros/latex/contrib/dates/MANIFEST6
-rw-r--r--macros/latex/contrib/dates/README18
-rw-r--r--macros/latex/contrib/dates/dates.dtx2395
-rw-r--r--macros/latex/contrib/dates/dates.ins96
4 files changed, 2515 insertions, 0 deletions
diff --git a/macros/latex/contrib/dates/MANIFEST b/macros/latex/contrib/dates/MANIFEST
new file mode 100644
index 0000000000..3ddf96e688
--- /dev/null
+++ b/macros/latex/contrib/dates/MANIFEST
@@ -0,0 +1,6 @@
+This package consists of:
+
+ MANIFEST
+ README
+ dates.dtx
+ dates.ins
diff --git a/macros/latex/contrib/dates/README b/macros/latex/contrib/dates/README
new file mode 100644
index 0000000000..f5ea1aa72f
--- /dev/null
+++ b/macros/latex/contrib/dates/README
@@ -0,0 +1,18 @@
+dates.dtx
+(C) Frank Bennett 1996, 1997
+
+This package provides facilities for parsing a string
+of dates in a loosely structured format, returning the
+result in an orderly fashion in count register. The
+parser, meant to be called by other packages, is extensible,
+and full documentation is provided. A demonstration
+file is included in the distribution which shows off
+its major features.
+
+This package also requires the overword package,
+also on CTAN.
+
+Current version: 1.3
+Feb 17 1997
+Frank Bennett
+fb@soas.ac.uk
diff --git a/macros/latex/contrib/dates/dates.dtx b/macros/latex/contrib/dates/dates.dtx
new file mode 100644
index 0000000000..430ee85b3b
--- /dev/null
+++ b/macros/latex/contrib/dates/dates.dtx
@@ -0,0 +1,2395 @@
+%\iffalse
+%
+% File dates.dtx
+% Copyright (C) 1996, 1997 by Frank Bennett. All rights reserved.
+%
+% IMPORTANT NOTICE:
+%
+% You are not allowed to change this file. You may however copy
+% this file to a file with a different name and then change the
+% copy if (a) you do not charge for the modified code, (b) you
+% acknowledge the author(s) in the new file, if it
+% is distributed to others, and (c) you attach these same
+% conditions to the new file.
+%
+% You are not allowed to distribute this file alone. You are not
+% allowed to take money for the distribution or use of this file
+% (or a changed version) except for a nominal charge for copying
+% etc.
+%
+% You are allowed to distribute this file under the condition that
+% it is distributed with all of its contents, intact.
+%
+% For error reports, or offers to help make this a more powerful,
+% friendlier, and altogether more thrilling package, please contact me on
+% fb@soas.ac.uk
+%
+%<*dtx>
+ \ProvidesFile{dates.dtx}
+%</dtx>
+%<style>\NeedsTeXFormat{LaTeX2e}[1995/06/01]
+%<style>\ProvidesPackage{dates}
+%<style> [1997/02/17 v1.3 Dates parsing support (Frank Bennett)]
+% \fi
+%
+% \def\fileversion{v1.3}
+% \def\filedate{1997/02/17}
+%
+%
+% \iffalse
+%<*driver>
+\documentclass{ltxdoc}
+%\CodelineIndex
+%
+%\EnableCrossrefs
+\begin{document}
+%\OnlyDescription % comment out for implementation details
+\DocInput{dates.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \changes{v1.0}{1996/12/10}{Initial version separated from calendar.dtx}
+% \changes{v1.0}{1996/12/12}{Overhauled to provide error handling and
+% various other features}
+% \changes{v1.0}{1996/12/14}{Adapted the plain \TeX{} code for the phases
+% of the moon and used it to set it up a function item in a list. It works!}
+% \changes{v1.0}{1996/12/14}{Tidied up some sloppiness in the handling of groups.
+% No active characters now appear in braced text, and functions no longer
+% require square braces. Documentation updated to this effect.}
+% \changes{v1.0}{1996/12/15}{Modified toXmac to allow no-frills ranges.}
+% \changes{v1.1}{1996/12/27}{Minor bug fixes for final release with the
+% Calendar package.}
+% \changes{v1.2}{1997/01/18}{Changed gdef of characters in capsdown to
+% plain def, so that diacritics and maths will not be screwed up
+% by calendar. Capsdown state is fixed by xdef immediately
+% before group enclosing the capsdown; definition is in force
+% only just before and just after the high-speed read of the
+% argument.}
+% \changes{v1.2}{1997/01/18}{Fixed a bug that the above fix produced
+% in the handling of function definitions.}
+% \changes{v1.3}{1997/02/17}{Added code to support recursive dates
+% falling on exactly the same day of the month in every month.
+% Perhaps such dates should be permitted to conditionally shift to a nearby
+% day in the event of a holiday. Perhaps not.}
+%
+% \title{User's Guide to the Dates package\thanks{This file is version number
+% \fileversion{}. It was last revised on
+% \filedate.}}
+%
+% \author{Frank G. Bennett, Jr.\thanks{The code contained in this file just
+% provides a smart \LaTeXe front end to
+% the \texttt{calendar} macros for \TeX{} that I
+% found on CTAN. The \TeX{} macros work quite
+% well, but lack any documentation. Their provenance is also a
+% mystery. If anyone can tell me who wrote them, I will gladly
+% include an acknowledgement in this documentation.}}
+%
+% \maketitle
+%
+% \DoNotIndex{\@,\@@par,\@beginparpenalty,\@empty}
+% \DoNotIndex{\@flushglue,\@gobble,\@input}
+% \DoNotIndex{\@makefnmark,\@makeother,\@maketitle}
+% \DoNotIndex{\@namedef,\@ne,\@spaces,\@tempa}
+% \DoNotIndex{\@tempb,\@tempswafalse,\@tempswatrue}
+% \DoNotIndex{\@thanks,\@thefnmark,\@topnum}
+% \DoNotIndex{\@@,\@elt,\@forloop,\@fortmp,\@gtempa,\@totalleftmargin}
+% \DoNotIndex{\",\/,\@ifundefined,\@nil,\@verbatim,\@vobeyspaces}
+% \DoNotIndex{\|,\~,\ ,\active,\advance,\aftergroup,\begingroup,\bgroup}
+% \DoNotIndex{\cal,\csname,\def,\documentstyle,\dospecials,\edef}
+% \DoNotIndex{\egroup}
+% \DoNotIndex{\else,\endcsname,\endgroup,\endinput,\endtrivlist}
+% \DoNotIndex{\expandafter,\fi,\fnsymbol,\futurelet,\gdef,\global}
+% \DoNotIndex{\hbox,\hss,\if,\if@inlabel,\if@tempswa,\if@twocolumn}
+% \DoNotIndex{\ifcase}
+% \DoNotIndex{\ifcat,\iffalse,\ifx,\ignorespaces,\index,\input,\item}
+% \DoNotIndex{\jobname,\kern,\leavevmode,\leftskip,\let,\llap,\lower}
+% \DoNotIndex{\m@ne,\next,\newpage,\nobreak,\noexpand,\nonfrenchspacing}
+% \DoNotIndex{\obeylines,\or,\protect,\raggedleft,\rightskip,\rm,\sc}
+% \DoNotIndex{\setbox,\setcounter,\small,\space,\string,\strut}
+% \DoNotIndex{\strutbox}
+% \DoNotIndex{\thefootnote,\thispagestyle,\topmargin,\trivlist,\tt}
+% \DoNotIndex{\twocolumn,\typeout,\vss,\vtop,\xdef,\z@}
+% \DoNotIndex{\,,\@bsphack,\@esphack,\@noligs,\@vobeyspaces,\@xverbatim}
+% \DoNotIndex{\catcode,\end,\escapechar,\frenchspacing,\glossary}
+% \DoNotIndex{\hangindent,\hfil,\hfill,\hskip,\hspace,\ht,\it,\langle}
+% \DoNotIndex{\leaders,\long,\makelabel,\marginpar,\markboth,\mathcode}
+% \DoNotIndex{\mathsurround,\mbox,\newcount,\newdimen,\newskip}
+% \DoNotIndex{\nopagebreak}
+% \DoNotIndex{\parfillskip,\parindent,\parskip,\penalty,\raise,\rangle}
+% \DoNotIndex{\section,\setlength,\TeX,\topsep,\underline,\unskip,\verb}
+% \DoNotIndex{\vskip,\vspace,\widetilde,\\,\%,\@date,\@defpar}
+% \DoNotIndex{\[,\{,\},\]}
+% \DoNotIndex{\count@,\ifnum,\loop,\today,\uppercase,\uccode}
+% \DoNotIndex{\baselineskip,\begin,\tw@}
+% \DoNotIndex{\a,\b,\c,\d,\e,\f,\g,\h,\i,\j,\k,\l,\m,\n,\o,\p,\q}
+% \DoNotIndex{\r,\s,\t,\u,\v,\w,\x,\y,\z,\A,\B,\C,\D,\E,\F,\G,\H}
+% \DoNotIndex{\I,\J,\K,\L,\M,\N,\O,\P,\Q,\R,\S,\T,\U,\V,\W,\X,\Y,\Z}
+% \DoNotIndex{\1,\2,\3,\4,\5,\6,\7,\8,\9,\0}
+% \DoNotIndex{\!,\#,\$,\&,\',\(,\),\+,\.,\:,\;,\<,\=,\>,\?,\_}
+% \DoNotIndex{\discretionary,\immediate,\makeatletter,\makeatother}
+% \DoNotIndex{\meaning,\newenvironment,\par,\relax,\renewenvironment}
+% \DoNotIndex{\repeat,\scriptsize,\selectfont,\the,\undefined}
+% \DoNotIndex{\arabic,\do,\makeindex,\null,\number,\show,\write,\@ehc}
+% \DoNotIndex{\@author,\@ehc,\@ifstar,\@sanitize,\@title,\everypar}
+% \DoNotIndex{\if@minipage,\if@restonecol,\ifeof,\ifmmode}
+% \DoNotIndex{\lccode,\newtoks,\onecolumn,\openin,\p@,\SelfDocumenting}
+% \DoNotIndex{\settowidth,\@resetonecoltrue,\@resetonecolfalse,\bf}
+% \DoNotIndex{\clearpage,\closein,\lowercase,\@inlabelfalse}
+% \DoNotIndex{\selectfont,\mathcode,\newmathalphabet,\rmdefault}
+% \DoNotIndex{\bfdefault}
+% \setcounter{StandardModuleDepth}{1}
+% \DeleteShortVerb{\|}
+% \MakeShortVerb{\"}
+%
+% \begin{abstract}
+% \noindent This package provides two low-level macros for the parsing of text
+% using \LaTeXe{}.
+% \end{abstract}
+%
+%
+% \CheckSum{1737}
+%
+% \section{Introduction}
+%
+% This package provides a macro, "\dateread", that can
+% be used to parse date strings, either individually
+% or recursively. The macro expects a human-readable
+% syntax, which it converts into an integer (a ``long
+% date'') that can
+% be more easily used for some types of computation.
+% A set of companion macros and token registers
+% is also provided for
+% converting long dates into human-readable form.
+%
+% Dates may be specified either individually,
+% or as recursive dates within a range.
+% The human-readable syntax for two
+% types of recursive date are built
+% into the package, but an interface for writing
+% specialized extensions in native \LaTeX{} is also provided.
+% The handling of parsed dates is also within
+% user control; it is defined in a
+% single argument fed to "\dateread" when it is invoked
+% in front of a list of dates.
+%
+% This package was
+% developed as one of the building blocks of
+% the "calendar" package, but is released as a separate
+% chunk of code because the date parsing task is a function
+% discrete from the work of building a calendar from
+% constituent blocks of information (which is the
+% main task of the "calendar" package proper).
+% If other applications are found for this package,
+% that is all to the good. Put my name on it,
+% let me know, and we'll have a drink together sometime.
+%
+% This user guide is brief, because the parser is
+% flexible enough that a long catalogue of strictures
+% is unnecessary. The next section describes the syntax
+% for entering dates. It is followed by a brief description
+% of how the macro can be called upon in another package,
+% and notes on extending the parser to provide enhanced
+% functionality. I have also provided guidance notes
+% in the code itself.
+%
+% \InputIfFileExists{datesynt}
+% {}
+% {\PackageError{calendar}
+% {Unpack dates.dtx before printing these docs.}
+% {}}
+%
+%
+% \section{Calling the Parser}
+%
+% As mentioned above, the short description in curly
+% braces can only contain plain text. Printing of
+% variable text (such as the text of the date) is
+% done through the argument to the "\dateread" macro.
+% This argument is an action that will be performed
+% once after each date in the list is read. The
+% date and the description text may be included by
+% using the appropriate commands. These are:
+%
+% \begin{tabular}{ll}
+% "\theyear" & The year (four digits).\\
+% "\themonth" & The full name of the month.\\
+% "\theshortmonth" & The name of the month (3 characters).\\
+% "\themonthnumber" & The number of the month.\\
+% "\theday" & The day of the month.\\
+% "\thetimestart" & Starting time for an item.\\
+% "\thetimeend" & Ending time for an item.\\
+% "\theweekday" & The name of the day of the week.\\
+% "\theshortweekday" & Abbreviated day of the week (3 characters).\\
+% "\theshorttext" & The text describing the date.\\
+% "\thelongtext" & A longer description of the date.\\
+% "\thelongdate" & The long date (an integer).\\
+% "\thedays" & The maximum number of days this month.\\
+% \end{tabular}
+%
+% You can also call up information using lower-level
+% registers and macros that contain date-related
+% information. Go to the code and commentary
+% section for further details.
+%
+% The demonstration file included in this package
+% lists dates on the terminal using the "\message"
+% command. In a more serious application, text can
+% be printed, stored to registers or boxes, or
+% sent in pre-processed form to an external file.
+%
+% The following is a valid invocation of the
+% macro:
+%
+% \begin{quote}
+% \begin{verbatim}
+% \dateread{%
+% \message{%
+% \theweekday, %
+% \theday\space%
+% \themonthname\space%
+% \theyear}}
+% %
+% % The list of dates to be parsed
+% %
+% June 15 1997 {Summer Holiday Begins}
+% September 25 1997 {Summer Holiday Ends}
+% January 1 1997 {First day of January}
+% February 18 1997 {Frank's Birthday}
+% Every Monday at 2:00 {Go to the Beach}
+% Every 20 {20th day of the month}
+% %
+% % The end of the list.
+% %
+% \relax{}
+% \end{verbatim}
+% \end{quote}
+%
+% A style package that uses the date parser
+% should of course conceal stretches of code
+% like that above from the end user. If lists
+% of dates are maintained in separate files, you
+% can do something like the following,
+%
+% \begin{quote}
+% \begin{verbatim}
+% \def\readinput{%
+% \dateread{\message{\theweekday^^J}}}
+%
+% \def\inputandread{%
+% \expandafter\readinput%
+% \@@input \filename\relax{}
+% }
+% \end{verbatim}
+% \end{quote}
+%
+% \noindent where "\filename" contains the name of a file
+% to be read. One would then confirm the existence
+% of the file, then run "\inputandread".
+%
+% \section{Extending the Parser}
+%
+% When the parser is used in a package, it may be
+% necessary to modify its behaviour to perform
+% special actions in the course of processing.
+% For example, you may want to provide a facility
+% for setting the range in files containing
+% recursive dates from a single file so that,
+% say, an academic schedule can be moved forward
+% to the next year without a lot of typing.
+% This kind of effect can be achieved by defining a
+% word which diverts processing to a macro that
+% performs the desired action before continuing
+% to digest the list of dates.
+%
+% The flow of processing can be diverted at two
+% points:
+%
+% \begin{enumerate}
+% \item Immediately after a word is read;
+% or
+% \item Immediately after a date and its
+% text have been digested.
+% \end{enumerate}
+%
+% The parser can be
+% re-entered in any of three states:
+%
+% \begin{enumerate}
+% \item One that
+% looks for the next word in a date string;
+% \item One that digests the description text; or
+% \item One
+% that completes the processing of a date
+% entry and its text.
+% \end{enumerate}
+%
+% Each of the exit points and reentry states is
+% associated with a macro name. Diversion is
+% accomplished by defining a word that "\let"s the
+% exit macro name be the user's own macro. Reentry
+% is accomplished in the user's macro by ending
+% with the appropriate macro name. The names
+% the macros to use as exit points are,
+% in the order of the first list above:
+%
+% \begin{enumerate}
+% \item "\dates@@@read"
+% \item "\dates@read@exit"
+% \end{enumerate}
+%
+% The names of macros to use for reentry
+% states are:
+%
+% \begin{enumerate}
+% \item "\dates@@@read@default"
+% \item "\dates@@@@read@default"
+% \item "\dates@read@exit@default"
+% \end{enumerate}
+%
+% An extension therefore consists of a user-defined
+% macro, and a user-defined word that invokes
+% "\let" as appropriate. Words should be padded
+% to exactly three characters using "X", and should
+% be appended with the suffix "mac". The following
+% defines a word, "if", which sets a toggle and
+% continues parsing a date:
+%
+% \begin{quote}
+% \begin{verbatim}
+% \newif\ifusedif
+%
+% \def\myownmacro{%
+% \usediftrue%
+% \dates@@@read@default}
+%
+% \def\ifXmac{%
+% \let\dates@@@read=\myownmacro}
+% \end{verbatim}
+% \end{quote}
+%
+% This is the same method used in the package
+% itself to provide recursive dates and the
+% function entry type; see the code commentary section
+% for less trivial examples.
+%
+%\StopEventually{\PrintIndex}
+%
+% \section{The Macros}
+%
+% \subsection{External Utilities}
+%
+% \begin{macro}{\@ifoverword}
+%
+% A macro for breaking strings into words is provided by
+% a package distributed separately.
+%
+% \begin{macrocode}
+%<*style>
+\RequirePackage{overword}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{The Engine Core}
+%
+% \begin{macro}{\dateread}
+% \begin{macro}{\date@read}
+% \begin{macro}{\date@@read}
+% \begin{macro}{\date@@@read}
+% \begin{macro}{\@gobble@enditalls}
+%
+% The interface macro starts by setting "\dates@action"
+% to be its first argument. It then opens with the initialization
+% of variables that are zeroed only at the start of a run
+% of dates, and passes control to the next macro in the chain.
+% At this point dates are unsorted, so an alternative
+% format such as HTML should \textit{not} be generated
+% by the argument text, unless you have a filter for sorting
+% the text after \TeX{} exits. In normal use,
+% events should be sorted and selected
+% first, in the package that calls
+% "dates.sty". The argument can be used to choose
+% between modes of \LaTeX{} handling, however. For example,
+% you might want to export the text to a file, or
+% store it directly into a list macro. By inserting a "\let"
+% into the hook in "\dates@analyze", you can put toggles
+% into the event files themselves. This is used in "calendar"
+% to provide for the selective ``freezing'' of events files
+% in a pre-processed form.
+%
+% \begin{macrocode}
+\long\gdef\dateread#1{%
+ \csname dates@reset@longtext\endcsname%
+ \let\dates@read\dates@read@default%
+ \gdef\dates@action{#1}%
+ \def\dates@subranges{}%
+ \dates@subrange@start=0%
+ \dates@subrange@end=0%
+ \dates@read}
+% \end{macrocode}
+%
+% The next macro continues with initialization, and
+% makes uppercase characters active inside a group.
+% Square braces are made grouping characters, so that
+% when the next chained macro runs
+% and grabs everything up to the next curly brace,
+% we will have a means of grouping within the
+% grabbed text. Square braces will be used for
+% grouping in user-defined functions for the automatic
+% generation of dates.
+%
+% \begin{macrocode}
+\long\gdef\dates@read@default{%
+ \dates@time@start=0%
+ \dates@time@end=0%
+ \setyear{1900}%
+ \dates@month=0%
+ \dates@day=0%
+ \dates@weekd@target=7%
+ \def\theshorttext{}%
+ \def\thelongtext{}%
+ \dates@suppressfalse%
+ \global\let\dates@init\relax%
+ \global\let\dates@increment\relax%
+ \let\dates@@@read=\dates@@@read@default%
+ \let\dates@@@@read=\dates@@@@read@default%
+ \let\dates@read@exit=\dates@read@exit@default%
+ \bgroup%
+ \dates@capsdown%
+ \dates@@read}
+% \end{macrocode}
+%
+% Once we have the text with the catcodes set appropriately,
+% we cut off the catcode change and run a macro in front of
+% the gobbled text which will chew it up while looping.
+% The "\enditall" terminator is a misnomer, really; it
+% ends the parsing of a single date, but we will continue
+% parsing until "\end" or "\relax{}" are encountered.
+%
+% \begin{macrocode}
+\long\def\dates@@read#1#{%
+ \let\end\relax%
+ \xdef\cal@temp{#1 }%
+ \egroup%
+ \expandafter\dates@@@read\cal@temp\enditall}
+% \end{macrocode}
+%
+% The following macro does the chewing. The macro
+% "\dates@analyze" will alter the values of
+% "\dates@@@read" and of "\dates@read@exit"
+% to achieve special effects. Any hooks that
+% redefine these functions should chain to
+% their defaults, which end in "@default".
+%
+% \begin{macrocode}
+\def\dates@@@read@default{%
+ \@ifoverword\enditall%
+ {\expandafter\dates@analyze\@overword{}%
+ \@gobble@enditalls}%
+ {\expandafter\dates@analyze\@overword{}%
+ \dates@@@read}%
+ {\expandafter\dates@analyze\@overword{}%
+ \ifnum\dates@year>0% If date exists, process
+ \let\dates@read\relax% ... and expire
+ \dates@read@exit% May be a range, so not default
+ \fi%
+ \expandafter\end\@gobbletwo}}%
+% \end{macrocode}
+%
+% Package extensions that import files on the fly may
+% produce multiple "\enditall"s in the scan text for
+% a date. This will chomp all of them. The change involves
+% introducing the following macro via the second
+% argument to "\@ifoverword", above.
+% \changes{v1.1}{1996/12/21}{Added handler for multiple enditall's.}
+%
+% \begin{macrocode}
+\def\@gobble@enditalls#1{%
+ \@ifnextnparchar\enditall%
+ {\let\next\@gobble@enditalls%
+ \next}%
+ {\dates@@@@read}%
+ {\message{This can't happen}}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Selective Handling}
+%
+% \subsubsection{Defaults}
+%
+% There are three points at which special handling can
+% be spliced into the parsing routine. Below, the defaults
+% are presented first, followed by alternatives that are
+% built into the package. Other special handling routines
+% can be spliced in, as discussed below under \ref{analyze}.
+%
+% \begin{macro}{\dates@@@@read}
+% \begin{macro}{\dates@@@@@read}
+%
+% The following will read arguments (one mandatory
+% argument in curly braces, one optional one in square
+% braces) and save them for
+% use as text descriptions applying to the date.
+% After the arguments are stored, we
+% chain to the exit routine that will perform the action
+% that the user gave to "\dateread".
+%
+% There are some dirty tricks here involving the square
+% brace. We define the macro globally inside a group,
+% so that our catcode change will not affect other
+% code. Then we set the open brace to be a grouping
+% character like "{". We can't use this inside the
+% definition directly (because \TeX{} will try to keep reading
+% text until it finds the matching brace), so we "\let"
+% a macro have this token's value. The "\let" is
+% global because the value of "{" is global.
+% Then we use the funny brace macro inside the
+% definition to look for a square brace coming up.
+%
+% All of this jiggery-pokery is necessary because
+% the "\futurelet" command (used by "\@ifnextchar") will stamp
+% a category code on the brace when it sees it.
+% The end result, though, is that \TeX{} will
+% read all the way to the last closing square
+% brace, not just to the next one it finds.
+% Any square braces inside the text will disappear
+% in printed text, but at least the user will not
+% find the style blowing up in his face.
+%
+% We also make capital letters active, with "\dates@capsdown".
+% This is done in a separately nested group, so that
+% it can be turned off before reading any square-braced
+% text, without affecting the catcode of the braces.
+%
+% \begin{macrocode}
+\bgroup
+ \catcode`\[=1
+ \global\let\dates@funny@brace=[
+ \gdef\dates@@@@read@default#1{%
+ \def\theshorttext{#1}%
+ \bgroup%
+ \catcode`\[=1\catcode`\]=2\relax%
+ \bgroup%
+ \dates@capsdown%
+ \@ifnextnparchar\dates@funny@brace%
+ {\egroup%
+ \dates@@@@@read}%
+ {\egroup%
+ \egroup%
+ \dates@read@exit}%
+ {\egroup%
+ \egroup%
+ \dates@read@exit}}
+\egroup
+% \end{macrocode}
+%
+% The optional argument uses bog-standard \LaTeX{}
+% option syntax. The only wrinkle is in the
+% catcode changes invoked within a group in the
+% macro above. These are cut off here.
+%
+% \begin{macrocode}
+\def\dates@@@@@read#1{%
+ \egroup%
+ \iflongtext%
+ \def\thelongtext{#1}%
+ \fi%
+ \dates@read@exit}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% The following is the default value of "\dates@read@exit".
+% It fixes the date and rationalizes the registers
+% containing human-readable date information, and
+% saves the date for future reference (i.e.~in case
+% we need it as the bottom end of a range).
+% It then performs the action given by the user in the
+% argument to "\dates@read", and chains back to continue
+% parsing within the presented list of dates.
+%
+% \begin{macrocode}
+\def\dates@read@exit@default{%
+ \dates@fix%
+ \caldate%
+ \dates@lastdate\dates@date%
+ \ifdates@suppress@global%
+ \else%
+ \ifdates@suppress%
+ \else%
+% \bgroup%
+% \dates@capsup%
+ \dates@action%
+% \egroup%
+ \fi%
+ \fi%
+ \dates@read}
+% \end{macrocode}
+%
+% \subsubsection{Recursive Handling}
+%
+% \begin{macro}{\dates@read@exit@range}
+%
+% This is meant to be spliced into the parser immediately
+% before the macro:
+%
+% \begin{quote}
+% "\dates@read@exit@default"
+% \end{quote}
+%
+% It is invoked
+% by the word "to" in the current date entry. Invoked
+% after the text argument describing the current date
+% has been grabbed, it begins by rationalizing the machine
+% and human readable dates. It then expands the registers
+% containing the starting and ending long dates describing
+% a range into a list macro. The dates are stepped down one
+% and up one day respectively, so that a simple ">" or "<"
+% will tell us whether a given date is within a subrange.
+% The list macro will later
+% be used as a series of bounds
+% in the generation of recursive dates and dates
+% defined by a function.
+%
+% \begin{macrocode}
+\def\dates@read@exit@range{%
+ \dates@fix%
+ \caldate%
+ \dates@subrange@end\dates@date%
+ \dates@reg=\expandafter{\dates@subranges}%
+ \edef\dates@subranges{%
+ \the\dates@reg%
+ \noexpand\delim{\the\dates@subrange@start}%
+ {\the\dates@date}}%
+ \let\dates@read@exit\dates@read@exit@default%
+ \dates@read@exit}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@read@exit@recurse}
+% \begin{macro}{\dates@read@exit@@recurse}
+% \begin{macro}{\dates@read@exit@@@recurse}
+%
+% This is the generic routine for generating dates according
+% to a recursively invoked formula. It is also intended
+% for splicing in in front of the macro:
+%
+% \begin{quote}
+% "\dates@read@exit@default"
+% \end{quote}
+%
+% The first macro in this chain checks
+% to be sure that a list of ranges exists.
+% It then defines the macro used to delimit the list
+% to something that will recurse within a subrange.
+% The list macro is then dumped into the document
+% for complete expansion. When it finishes,
+% control is passed back to the top, so that
+% reading can continue through the list of dates.
+%
+% \begin{macrocode}
+\def\dates@read@exit@recurse{%
+ \expandafter\ifcat\expandafter$\dates@subranges$%
+ \PackageError{dates}{No range given}%
+ {You need to specify a range before %
+ recursive entries and formulae}%
+ \fi\relax%
+ \ifx\dates@init\relax%
+ \ifnum\dates@day>0\relax
+ \dates@everymonth@day\dates@day%
+ \global\let\dates@init\dates@init@monthly@dom%
+ \global\let\dates@increment\dates@increment@monthly@dom%
+ \else%
+ \PackageError{dates}{Incomplete recursive entry}%
+ {You need to specify a day of the week or a day of %
+ the month or something for entries beginning with %
+ the word Every.}
+ \fi%
+ \fi%
+ \let\delim\dates@read@exit@@recurse%
+ \dates@subranges%
+ \dates@read}
+% \end{macrocode}
+%
+% This is the macro to which "\delim" is set above.
+% It sets up registers with the top and bottom boundaries
+% of the range, as given in the list, then sets the
+% current date to be the bottom of the range.
+% It then executes an (arbitrary) function to find
+% the first calculated date above the bottom of the range,
+% rationalizes the human-readable date registers, and
+% performs the user's requested action. It then chains to
+% the macro that will loop until the range is exceeded.
+%
+% \begin{macrocode}
+\def\dates@read@exit@@recurse#1#2{%
+ \dates@subrange@start#1\relax%
+ \dates@subrange@end#2\relax%
+ \global\dates@date=\dates@subrange@start\relax%
+ \caldate%
+ \dates@init%
+ \caldate%
+ \ifdates@suppress@global%
+ \else%
+ \ifdates@suppress%
+ \else%
+% \bgroup%
+% \dates@capsup%
+ \dates@action%
+% \egroup%
+ \fi%
+ \fi%
+ \let\next\dates@read@exit@@@recurse%
+ \dates@read@exit@@@recurse}
+% \end{macrocode}
+%
+% This is the macro that does the actual recursion for recursive entries.
+% It increments, checks the date, performs the action if appropriate,
+% otherwise breaks the loop so that control can pass back to
+% "\dates@read@exit@recurse".
+%
+% \begin{macrocode}
+\def\dates@read@exit@@@recurse{%
+ \dates@increment\relax%
+ \ifnum\dates@date<\dates@subrange@end\relax%
+ \caldate%
+ \ifdates@suppress@global%
+ \else%
+ \ifdates@suppress%
+ \else%
+ \dates@action%
+ \fi%
+ \fi%
+ \else%
+ \let\next\relax%
+ \fi%
+ \next}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\dates@increment@daily}
+% \begin{macrocode}
+\def\dates@increment@daily{%
+ \global\advance\dates@date by 1\relax}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@init@weekly}
+% \begin{macro}{\dates@increment@weekly}
+%
+% The following is the initialization macro for weekly recursion.
+% It moves to the first instance of the targetted
+% day of the week above the bottom of the subrange.
+%
+% \begin{macrocode}
+\def\dates@init@weekly{%
+ \mod7\dates@date\dates@weekd%
+ \dates@three=\dates@weekd@target\relax%
+ \advance\dates@three by -\dates@weekd\relax%
+ \ifnum\dates@three<0\relax%
+ \advance\dates@three by7%
+ \fi%
+ \global\advance\dates@date by \dates@three\relax}
+% \end{macrocode}
+%
+% This is the increment macro used for weekly recursion.
+% It just bumps up the date seven days each time it is invoked.
+%
+% \begin{macrocode}
+\def\dates@increment@weekly{%
+ \global\advance\dates@date by7\relax}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\dates@init@monthly@dow}
+% \begin{macro}{\dates@increment@monthly@dow}
+%
+% The following is the general initialization macro for finding
+% an instance of a day of the week within a month. It begins
+% by setting the value of a macro with which it terminates
+% to be "\relax", in the hope that a match will be found
+% the first time it is invoked. We then move the date
+% forward, if necessary, to find the targetted day of the week.
+% When this is found, we set the human-readable register
+% information according to that long date (including the
+% day of the month). Dividing and multiplying by "7" yields
+% the largest multiple of "7" that is equal to or less than the
+% day of the month. If this is "0", we're in the first week,
+% if "7" we're in the second, and so forth. If the value
+% of the current day is too low, we move up the date.
+% If it is too high, we move to the first day
+% of the next month, and request a loop back through
+% the same routines.
+%
+% \begin{macrocode}
+\def\dates@init@monthly@dow{%
+ \let\dates@init@monthly@dow@recurse\relax%
+ \nextday\dates@weekd@target%
+ \caldate%
+ \dates@one\dates@day%
+ \divide\dates@one by 7\relax%
+ \multiply\dates@one by 7\relax%
+ \ifnum\dates@modulo>\dates@one\relax%
+ \dates@two\dates@modulo%
+ \advance\dates@two by -\dates@one%
+ \global\advance\dates@date by \dates@two%
+ \else%
+ \ifnum\dates@modulo<\dates@one\relax%
+ \dates@next@month%
+ \let\dates@init@monthly@dow@recurse\dates@init@monthly@dow%
+ \fi%
+ \fi%
+\dates@init@monthly@dow@recurse}
+\def\dates@init@monthly@dom{%
+ \let\dates@init@monthly@dom@recurse\relax%
+ \ifnum\dates@day>\dates@everymonth@day%
+ \dates@next@month%
+ \let\dates@init@monthly@dom@recurse\dates\init@monthly@dom%
+ \else%
+ \dates@day\dates@everymonth@day%
+ \dates@fix%
+ \fi%
+ \dates@init@monthly@dom@recurse}
+% \end{macrocode}
+%
+% This is the general incrementing macro for monthly entries.
+% It's pretty simple; we just move to the first day of the
+% next month, then run the initialization macro again to
+% find the appropriate date within the month.
+%
+% \begin{macrocode}
+\def\dates@increment@monthly@dow{%
+ \dates@next@month%
+ \dates@init@monthly@dow}
+\def\dates@increment@monthly@dom{%
+ \dates@next@month%
+ \dates@init@monthly@dom}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\dates@@@@read@function}
+% \begin{macro}{\dates@@@@read@@function}
+%
+% This is designed to be spliced into the parser
+% immediately before the macro:
+%
+% \begin{quote}
+% "\dates@@@@read@default".
+% \end{quote}
+%
+% It is invoked, like the other special handling routines,
+% via the "\dates@execute" hook in the text analyzer
+% (see \ref{analyze} for details). It reads two
+% arguments immediately following the word that
+% triggers it. It stores these for reference.
+% The third argument is read after checking to be
+% sure that we have reached the end of the parsing
+% string, and are looking at the delimiter that
+% ends it. Then this is gobbled, and dumped into the
+% document so that the definitions it contains will
+% take effect. The jiggery-pokery with grouping
+% limits the effect of "\makeatletter" to the
+% scope of the braces delimiting the user's
+% function definition, while the macros he defines
+% there can be defined locally.
+%
+% This third argument should not produce any printed output, and should define,
+% at minimum, two macros, the names of which are given as
+% the first and second arguments following the invoking
+% word in the parsed text. The first of these will
+% initialize to the first date conforming to the formula,
+% counting from the bottom of a range of dates, and should
+% return a long date in "\dates@date". The second should
+% increment upward one date from a given date, also returning
+% the result in "\dates@date". The demonstration file
+% contains a sample of code which calculates the phases of
+% the moon.
+%
+% \begin{macrocode}
+\long\def\dates@@@@read@function #1 #2 {%
+ \edef\dates@init{\csname#1\endcsname}%
+ \edef\dates@increment{\csname#2\endcsname}%
+ \@ifnextnparchar\enditall%
+ {\bgroup%
+ \makeatletter%
+ \expandafter\dates@@@@read@@function\@gobble}%
+ {\PackageError%
+ {dates}%
+ {Extra text after function names}%
+ {The third argument must be in curly braces.}}%
+ {\relax}}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\long\def\dates@@@@read@@function#1{%
+ \long\gdef\dates@temp{#1}%
+ \egroup%
+ \dates@temp%
+ \let\dates@temp\relax%
+ \dates@@@@read@default}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{The Analyzer}
+%
+% Human-readable dates are fetched word by word by
+% the above routines. The "\dates@@@read@default"
+% macro feeds individual words to the analyzer
+% described here.
+%
+% \begin{macro}{dates@analyze}
+%
+% This
+% is a pretty straightforward set of nested
+% conditions that will uniquely identify an item
+% as a month, a year, a day or a time, and respond
+% accordingly. The macro is somewhat long, so
+% comments are provided to indicate nesting
+% levels and their functions.
+%
+% \begin{macrocode}
+\long\def\dates@analyze#1#2#{%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level One] Check to see if we're dealing with a number.
+% If so, define a macro containing only zero to use in a series of
+% parsing checks.
+% \end{description}
+%
+% \begin{macrocode}
+ \ifcat\noexpand#11%
+ \def\dates@zero{0}%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level Two] Check to see if this is is not a range of times.
+% \end{description}
+%
+% \begin{macrocode}
+ \expandafter\dates@check@hyphen\@overword-{}%
+ \ifx\dates@arg@b\dates@zero%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level Three] It now looks like this either a lone time or
+% an integer. Check to see if it's not a time. (We use "\@overword",
+% but it will have the same content as "\dates@arg@a").
+% \end{description}
+%
+% \begin{macrocode}
+ \expandafter\dates@check@colon\@overword:{}%
+ \ifx\dates@arg@b\dates@zero%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level Four] Alright, so it's an integer. That means it's either a year
+% or a day of the month. The instructions require a 4-digit
+% year, which is always larger than a day of the month.
+% \end{description}
+%
+% \begin{macrocode}
+ \expandafter\ifnum\@overword>31%
+ \setyear{\dates@arg@a}%
+ \else%
+ \ifnum\dates@day>0%
+ \dates@dayerror%
+ \else%
+ \global\dates@day=\dates@arg@a%
+ \fi%
+ \fi%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level Three (again)] If the item was a lone time, we set variables
+% accordingly.
+% \end{description}
+%
+% \begin{macrocode}
+ \else%
+ \expandafter\dates@strip@colon\dates@arg@b%
+ \global\dates@time@start=\dates@arg@a%
+ \multiply\dates@time@start by 60%
+ \advance\dates@time@start by \dates@arg@b%
+ \global\dates@time@end=\dates@time@start%
+ \fi%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level Two (again)] If it was a range of times, we have the
+% extremes of the range in "\dates@arg@a" and "\dates@arg@b".
+% We process each so that a colon delimiter is not required,
+% but will be recognized if given. Note the "0" in the definition
+% of "\dates@check@colon" et al., above; this produces a default of zero
+% if this is a bare number with no colon delimiter.
+%
+% We proceed by first setting aside the contents of "\dates\arg@b"
+% so that they will not be overwritten. We then check for the
+% existence of a colon and, if one is found, the trailing
+% colon left by the test macro is stripped off. We then
+% set the time.
+% \end{description}
+%
+% \begin{macrocode}
+ \else%
+ \expandafter\dates@strip@hyphen\dates@arg@b%
+ \let\dates@temp\dates@arg@b%
+ \expandafter\dates@check@colon\dates@arg@a:{}%
+ \ifx\dates@arg@b\dates@zero%
+ \else%
+ \expandafter\dates@strip@colon\dates@arg@b%
+ \fi%
+ \dates@time@start=\dates@arg@a\relax%
+ \multiply\dates@time@start by 60\relax%
+ \global\advance\dates@time@start by \dates@arg@b\relax%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level Two (continued)] We then do exactly the same thing for the second time
+% given.
+% \end{description}
+%
+% \begin{macrocode}
+ \expandafter\dates@check@colon\dates@temp:{}%
+ \ifx\dates@arg@b\dates@zero%
+ \else%
+ \expandafter\dates@strip@colon\dates@arg@b%
+ \fi%
+ \dates@time@end=\dates@arg@a\relax%
+ \multiply\dates@time@end by 60\relax%
+ \global\advance\dates@time@end by \dates@arg@b%
+ \fi%
+% \end{macrocode}
+%
+% \begin{description}
+% \item[Level one (again)] \label{analyze} If "\dates@word" does not look like a
+% number, then it is handled as text.
+% We pass control to a macro that will
+% simply execute a macro name derived from the first three
+% characters of the word. If it's unknown chaff, it will therefore
+% effectively be ignored. This can be used as a hook
+% for defining options not included in the "dates" package
+% proper. The description of the hooks used by the
+% vanilla version of "dates" is given below.
+% \end{description}
+%
+% \begin{macrocode}
+ \else%
+ \dates@execute#1#2XXX{}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@execute}
+%
+% Used as the default action in the analyzer, this just blindly
+% executes a macro that may match a day, month or option
+% name. If the date string is limited by "\relax{}",
+% the macro name "\relax" will be read in as a token
+% for interpretation. To prevent unexpected results,
+% we therefore convert a leading control sequence to a string
+% within "\csname" "\endcsname". We must not give
+% the same treatment to non-control-sequence items,
+% however, because this would prevent the expansion of
+% uppercase characters, which have been read in as active
+% characters, to their lowercase counterparts. An "\ifcat"
+% is used to choose which action is appropriate. The
+% macros invoked by "\dates@execute" never take arguments,
+% so they can be expanded within the scope of "\ifcat".
+%
+% \begin{macrocode}
+\def\dates@execute#1#2#3#4#{%
+ \ifcat#1\relax%
+ \expandafter\csname%
+ \string#1#2#3mac\endcsname%
+ \else%
+ \expandafter\csname#1#2#3mac\endcsname%
+ \fi}%
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Fodder for the Analyzer}
+%
+% As can be gleaned from an examination of "\dates@execute",
+% a word is read by executing a macro named using
+% its first three letters. We provide definitions
+% for a number of such macros here.
+%
+% \begin{macro}{\evemac}
+%
+% "Every" sets up for recursion, and for a default of
+% incrementing over days of the week.
+%
+% \begin{macrocode}
+\def\evemac{%
+ \global\let\dates@read@exit=\dates@read@exit@recurse}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\daymac}
+%
+% The following was suggested by Miroslav Novak:
+%
+% \begin{macrocode}
+\def\daymac{%
+ \global\let\dates@increment=\dates@increment@daily}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\othmac}
+%
+% "Other" will modify the effect of "every" to
+% choose every other date within the range. You
+% can't choose the starting dates within the
+% subrange --- but some automation is better than none.
+%
+% \begin{macrocode}
+\def\othmac{%
+ \global\let\dates@increment=\dates@increment@semiweekly}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\firmac}
+% \begin{macro}{\secmac}
+% \begin{macro}{\thimac}
+%
+% "First", "second" and "third" will set a counter than controls which
+% instance of a day of the week within a month should be chosen,
+% and modifies the effect of "every" to recurse on that
+% instance within every month, within the subrange.
+% \begin{macrocode}
+\def\firmac{%
+ \dates@modulo=0%
+ \global\let\dates@init=\dates@init@monthly@dow%
+ \global\let\dates@increment=\dates@increment@monthly@dow}%
+%
+\def\secmac{%
+ \dates@modulo=7%
+ \global\let\dates@init=\dates@init@monthly@dow%
+ \global\let\dates@increment=\dates@increment@monthly@dow}%
+%
+\def\thimac{%
+ \dates@modulo=14%
+ \global\let\dates@init=\dates@init@monthly@dow%
+ \global\let\dates@increment=\dates@increment@monthly@dow}%
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\1stmac}
+% \begin{macro}{\2ndmac}
+% \begin{macro}{\3rdmac}
+%
+% These are just aliases of the macros above.
+%
+% \begin{macrocode}
+\expandafter\let\csname1stmac\endcsname=\firmac%
+\expandafter\let\csname2ndmac\endcsname=\secmac%
+\expandafter\let\csname3rdmac\endcsname=\thimac%
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\toXmac}
+%
+% The following responds to "to" in the parsed text. If
+% the year is zero, it sets
+% the bottom of a range to the last date encountered, and
+% lets the exit macro for processing a finished date be
+% one which will set the top of the range before performing
+% the action specified by the user.
+% If the year is greater than zero, we grab the \textit{current}
+% date, reset everything to zero, and continue parsing.
+% This permits ``no frills'' range designations, as
+% in the "calendar" package.
+%
+% The "X" is appended to
+% fill out to three characters. For reasons that I do not
+% fully understand, this was necessary to prevent the
+% package from exiting within the scope of a group.
+%
+% \begin{macrocode}
+\def\toXmac{\relax%
+ \ifnum\dates@year=0%
+ \dates@subrange@start\dates@lastdate%
+ \else%
+ \dates@fix%
+ \dates@subrange@start\dates@date%
+ \dates@month=0%
+ \dates@day=0%
+ \setyear{1900}%
+ \fi%
+ \let\dates@read@exit\dates@read@exit@range}%
+ % \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\funmac}
+%
+% The following causes a function definition to be read
+% immediately after the word "function" in the date text.
+%
+% \begin{macrocode}
+\def\funmac{%
+ \global\let\dates@read@exit=\dates@read@exit@recurse%
+ \global\let\dates@@@read=\dates@@@@read@function}
+% \end{macrocode}
+% \end{macro}
+%
+% The following causes the suppression of any action
+% in respect of the entry in which it is found.
+%
+% \begin{macrocode}
+\def\remmac{%
+ \global\dates@suppresstrue}
+% \end{macrocode}
+%
+% \begin{macro}{\janmac}
+% \begin{macro}{\jancheckmac}
+%
+% The months are defined globally using a recursive engine
+% that is discarded when the macros have been defined.
+% Each month macro first sets a counter to the number of
+% days in the month, so that a range check can be performed
+% when the date is interpreted. It then checks to
+% see if a month has already been selected, and if so
+% it forces a fatal error; otherwise, the month counter
+% is set to the appropriate value.
+%
+% \begin{macrocode}
+\bgroup
+ \def\monthdata#1#2#3#4#5\end{%
+ \expandafter\gdef\csname#2#3#4mac\endcsname{%
+ \ifnum\dates@month>0%
+ \dates@montherror%
+ \else%
+ \global\dates@month=#1%
+ \fi}%
+ \ifcat$#5$\let\next\@gobble\else\let\next\monthdata\fi%
+ \next#5\end}%
+% \end{macrocode}
+%
+%
+% The following does the action generation of month macros.
+% \begin{macrocode}
+ \monthdata1jan2feb3mar4apr5may6jun%
+ 7jul8aug9sep{10}oct{11}nov{12}dec\end
+\egroup
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\monmac}
+%
+% Days of the week are specified in a similar fashion.
+%
+% \begin{macrocode}
+\bgroup
+ \def\weekdata#1#2#3#4#5\end{%
+ \expandafter\gdef\csname #2#3#4mac\endcsname{%
+ \ifnum\dates@weekd@target<7\relax%
+ \dates@weekerror%
+ \else%
+ \global\dates@weekd@target=#1\relax%
+ \ifx\dates@increment\relax%
+ \global\let\dates@init\dates@init@weekly%
+ \global\let\dates@increment\dates@increment@weekly%
+ \fi%
+ \fi}%
+ \ifcat$#5$\let\next\@gobble\else\let\next\weekdata\fi%
+ \next#5\end}
+
+ \weekdata0sun1mon2tue3wed4thu5fri6sat\end
+\egroup
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@montherror}
+% \begin{macro}{\dates@weekerror}
+% \begin{macro}{\dates@dayerror}
+%
+% These three macros are used in the above definitions
+% to produce error messages if something is wrong
+% with a date.
+%
+% \begin{macrocode}
+\def\dates@montherror{%
+ \PackageError{dates}{Month multiply defined}{%
+ You have set the month more than once here.}}
+%
+\def\dates@dayerror{%
+ \PackageError{dates}{Day multiply defined}{%
+ You have set the day more than once here.}}
+%
+\def\dates@weekerror{%
+ \PackageError{dates}{Week multiply defined}{%
+ You have set the day of the week more than once here.}}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Low-level Bits and Pieces}
+%
+% \begin{macro}{\dates@capsdown}
+%
+% The "\lowercase" function provided in \TeX{} does not
+% operate in \TeX{}'s mouth, and so cannot be used to
+% create lowercase strings for export to a non-DVI
+% file or for display on the terminal.
+% We can get around this problem by
+% making all upper-case characters
+% active, and defining them to lowercase themselves. The
+% operative definition is "\dates@capsdown".
+% The
+% grouping culls the bootstrapping definitions used to
+% create these macros from memory. A detailed explanation
+% these macros is not given here, but they do work.
+% Essentially, they function by looping over sets of three
+% characters, two uppercase and one lowercase, building a
+% macro ("\dates@capsdown") that will make the uppercase
+% characters in the list locally active, with the appropriate
+% definition. Two uppercase characters are required in the
+% list because on is read to identify the character so
+% that it can be made active in order, on the second read,
+% to take its active form and define it.
+%
+% \begin{macrocode}
+\bgroup
+\newtoks\dates@reg
+\dates@reg={}
+\def\dates@capsdown{}
+\def\dates@capsup{}
+\def\dates@capsactive#1{%
+ \ifx#1\end%
+ \let\next\relax%
+ \else%
+ \catcode`#1=13%
+ \let\next\dates@@capsactive%
+ \fi%
+ \next}
+\def\dates@@capsactive#1#2{%
+ \dates@reg=\expandafter{%
+ \dates@capsdown\catcode`#1=13\def#1{#2}}%
+ \xdef\dates@capsdown{\the\dates@reg}%
+ \dates@reg=\expandafter{%
+ \dates@capsup\edef#1{\string#1}}%
+ \xdef\dates@capsup{\the\dates@reg}%
+ \let\next\dates@capsactive%
+ \next}
+\dates@capsactive%
+ AAaBBbCCcDDdEEeFFfGGgHHhIIiJJjKKk%
+ LLlMMmNNnOOoPPpQQqRRrSSsTTtUUuVVv%
+ WWwXXxYYyZZz\end
+\egroup
+% \end{macrocode}
+% \end{macro}
+%
+% For parsing strings, we use some little
+% macros to identify strings that have a colon in
+% them (which will be assumed to be a time)
+% or a hyphen (assumed to be a range of times),
+% and to strip those off where necessary.
+%
+% \begin{macrocode}
+\def\dates@check@colon#1:#2#{%
+ \def\dates@arg@a{#1}%
+ \def\dates@arg@b{0#2}}
+\def\dates@strip@colon#1:{%
+ \def\dates@arg@b{#1}}
+\def\dates@check@hyphen#1-#2#{%
+ \def\dates@arg@a{#1}%
+ \def\dates@arg@b{0#2}}
+\def\dates@strip@hyphen#1-{%
+ \def\dates@arg@b{#1}}
+% \end{macrocode}
+%
+% The following macro is used to terminate
+% processing.
+%
+% \begin{macrocode}
+\expandafter\expandafter\expandafter\def%
+ \expandafter\csname%
+ \string\relaxXXmac\endcsname{%
+ \let\dates@@@@read\relax}
+% \end{macrocode}
+%
+%
+%
+% \subsection{Interface Macros for Date Info}
+%
+% \begin{macro}{\theyear}
+% \begin{macro}{\themonth}
+% \begin{macro}{\theshortmonth}
+% \begin{macro}{\themonthnumber}
+% \begin{macro}{\theday}
+% \begin{macro}{\theweekday}
+% \begin{macro}{\theshortweekday}
+% \begin{macro}{\thelongdate}
+% \begin{macro}{\themonthdays}
+% \begin{macro}{\theshorttext}
+% \begin{macro}{\thelongtext}
+%
+% \label{interface} These macros can be used to include date information
+% in the text fed to "\dateread". They do not contain
+% unprintable operations, and so can be used to display
+% text on the terminal as well as in a document. All
+% are updated from the long date by the "\caldate" command.
+% The macros "\theshorttext" and "\thelongtext" are
+% defined elsewhere on the fly; token registers cannot
+% be used for these because they must be allowed to
+% expand fully on the terminal.
+%
+% \begin{macrocode}
+\def\theyear{\the\dates@year@full}
+\def\themonth{\the\dates@monthname}
+\def\theshortmonth{\the\dates@monthname}
+\def\themonthnumber{\the\dates@month}
+\def\theday{\the\dates@day}
+\def\theweekday{\the\dates@dayname}
+\def\theshortweekday{\the\dates@shortweekday}
+\def\thelongdate{\the\dates@date}
+\def\themonthdays{\the\dates@days}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Maths Functions for Dates}
+%
+% The following code is an almost direct rip-off of the
+% "calendar" macros for plain \TeX{} that are stored on
+% CTAN. If anyone knows who the author is, I will be happy
+% to include a credit here. I have made scant effort
+% to document the code, but it works well.
+%
+% \begin{macro}{\setyear}
+%
+% Set the current year.
+%
+% \begin{macrocode}
+\def\setyear#1{\dates@year=#1%
+ \advance\dates@year by -1900\calculateyearbase}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\nextyear}
+%
+% Advance by one year
+%
+% \begin{macrocode}
+\def\nextyear{\advance\dates@year by1%
+ \calculateyearbase}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@next@month}
+% Advance by one month.
+%
+% \begin{macrocode}
+\def\dates@next@month{%
+ \ifnum\dates@month=12%
+ \advance\dates@year by 1\calculateyearbase%
+ \dates@month=1%
+ \dates@day=1%
+ \else%
+ \advance\dates@month by 1%
+ \dates@day=1%
+ \fi%
+ \dates@fix\caldate}
+% \end{macrocode}
+% \end{macro}
+%
+% Set the current time zone.
+%
+% \begin{macro}{\settimezone}
+% \begin{macrocode}
+\def\settimezone#1{\dates@timezone=#1%
+ \multiply\dates@timezone by 1000%
+ \divide\dates@timezone by24}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\calculateyearbase}
+%
+% Set the "\ifleapyear" toggle. Set "\dates@yearbase" to the number of
+% days passed from 1900, Jan 0 to New year's date in the target year.
+%
+% \begin{macrocode}
+\def\calculateyearbase{%
+ \dates@yearbase=-1%
+ {\count0=\dates@year\divide\count0 by4%
+ \multiply\count0 by4\relax%
+ \ifnum\dates@year=\count0%
+ \global\dates@catch=0%
+ \else%
+ \global\dates@catch=1%
+ \fi}%
+ \ifcase\dates@catch \leapyeartrue\or%
+ \leapyearfalse\fi%
+ {\count0=\dates@year\multiply\count0%
+ by1461\advance\count0 by3%
+ \divide\count0 by4%
+ \global\dates@catch=\count0}%
+ \global\advance\dates@yearbase by\dates@catch\relax%
+ \ifnum\dates@year=0\global\dates@yearbase=0\leapyearfalse\fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\monthdays}
+%
+% Set the number of days passed at the end of each month in "\dates@day".
+%
+% \begin{macrocode}
+\def\monthdays{%
+\global\dates@catch\ifcase\dates@month%
+ 0\or31\or%
+ 59\or90\or120\or151\or181\or212\or%
+ 243\or273\or304\or334\or365\fi%
+ {\ifleapyear\ifnum\dates@month>1%
+ \global\advance\dates@catch by1\fi\fi}%
+ \dates@day=\dates@catch}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@fix}
+%
+% Return the long date of "\dates@month", "\dates@day" in the year "\dates@year"
+% in "\dates@date" after checking to be sure that the month and the day
+% have been set, if confirmation has been toggled on, and that
+% the number of days
+% in the month conforms to the constraints of reality.
+%
+% \begin{macrocode}
+\def\dates@fix{%
+ \ifnum\dates@month=0%
+ \ifdates@requiremonth%
+ \PackageError{dates}{Missing month}{%
+ You need to specify a date for the month in this date entry.}%
+ \else%
+ \dates@month=1%
+ \fi%
+ \fi%
+ \ifnum\dates@day=0%
+ \ifdates@requireday%
+ \PackageError{dates}{Missing day of the month}{%
+ You need to specify a day of the month in this date entry.}%
+ \else%
+ \dates@day=1%
+ \fi%
+ \fi%
+ \dates@monthname@get%
+ \ifnum\dates@days<\dates@day%
+ \PackageError{dates}{Day of month out of range}{%
+ There are only \the\dates@days\space days in %
+ \themonth, but you have tried^^J%
+ to specify \the\dates@day.}%
+ \else%
+ \dates@date=\dates@day{\advance\dates@month by-1%
+ \monthdays%
+ \advance\dates@date by\dates@day%
+ \global\advance\dates@date by\dates@yearbase}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\mod}
+%
+% Long date MOD 7 will give the week day.
+% Sunday is 0 and Saturday is 6. The base
+% number is returned in "\dates@three".
+%
+% \begin{macrocode}
+\def\mod#1#2#3{\dates@three=#2\relax%
+ \dates@four=\dates@three%
+ \divide\dates@three by #1%
+ \multiply\dates@three by #1%
+\advance\dates@four by -\dates@three%
+ #3=\dates@four}
+
+\def\dates@year@get{%
+ \dates@year@full\dates@year%
+ \global\advance\dates@year@full by 1900\relax}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\theweekday}
+%
+% Set the names of week day (Local).
+%
+% \begin{macrocode}
+\def\dates@dayname@get{%
+ \mod7\dates@date\dates@weekd%
+ \ifcase\dates@weekd%
+ \global\dates@dayname{Sunday}%
+ \global\dates@shortweekday{Sun}%
+ \or \global\dates@dayname{Monday}%
+ \global\dates@shortweekday{Mon}%
+ \or \global\dates@dayname{Tuesday}%
+ \global\dates@shortweekday{Tue}%
+ \or \global\dates@dayname{Wednesday}%
+ \global\dates@shortweekday{Wed}%
+ \or \global\dates@dayname{Thursday}%
+ \global\dates@shortweekday{Thu}%
+ \or \global\dates@dayname{Friday}%
+ \global\dates@shortweekday{Fri}%
+ \or \global\dates@dayname{Saturday}%
+ \global\dates@shortweekday{Sat}%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\caldate}
+%
+% Gives the usual calendar date for
+% a long date in counter "\dates@date".
+% Returned in "\dates@day", "\dates@month" and "\dates@year"
+% and other registers. See the interface macros above
+% under \ref{interface}.
+%
+% \begin{macrocode}
+\def\caldate{\dates@year=\dates@date%
+ \multiply\dates@year by4\divide\dates@year by1461%
+ \calculateyearbase%
+ {\advance\dates@date by-\dates@yearbase\dates@month=0%
+ \loop\monthdays\ifnum\dates@day<\dates@date%
+ \global\advance\dates@month by1\repeat%
+ {\advance\dates@month by-1\monthdays%
+ \advance\dates@date by-\dates@day%
+ \global\dates@day=\dates@date}}%
+ \dates@year@get%
+ \dates@monthname@get%
+ \dates@dayname@get}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\dates@monthname@get}
+%
+% This stores the names of the months to registers.
+% It is run by "\caldate".
+%
+% \begin{macrocode}
+\def\dates@monthname@get{%
+ \ifcase\dates@month%
+ \or \global\dates@monthname{January}%
+ \global\dates@shortmonthname{Jan}%
+ \global\dates@days=31\relax%
+ \or \global\dates@monthname{February}%
+ \global\dates@shortmonthname{Feb}%
+ \ifleapyear%
+ \global\dates@days=29\relax%
+ \else%
+ \global\dates@days=28\relax%
+ \fi%
+ \or \global\dates@monthname{March}%
+ \global\dates@shortmonthname{Mar}%
+ \global\dates@days=31\relax%
+ \or \global\dates@monthname{April}%
+ \global\dates@shortmonthname{Apr}%
+ \global\dates@days=30\relax%
+ \or \global\dates@monthname{May}%
+ \global\dates@shortmonthname{May}%
+ \global\dates@days=31\relax%
+ \or \global\dates@monthname{June}%
+ \global\dates@shortmonthname{Jun}%
+ \global\dates@days=30\relax%
+ \or \global\dates@monthname{July}%
+ \global\dates@shortmonthname{Jul}%
+ \global\dates@days=31\relax%
+ \or \global\dates@monthname{August}%
+ \global\dates@shortmonthname{Aug}%
+ \global\dates@days=31\relax%
+ \or \global\dates@monthname{September}%
+ \global\dates@shortmonthname{Sep}%
+ \global\dates@days=30\relax%
+ \or \global\dates@monthname{October}%
+ \global\dates@shortmonthname{Oct}%
+ \global\dates@days=31\relax%
+ \or \global\dates@monthname{November}%
+ \global\dates@shortmonthname{Nov}%
+ \global\dates@days=30\relax%
+ \or \global\dates@monthname{December}%
+ \global\dates@shortmonthname{Dec}%
+ \global\dates@days=31\relax%
+ \fi}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\nextday}
+%
+% Find the next (previous) day after
+% (before) "\dates@date" with "\mod7=#1".
+%
+% \begin{macrocode}
+\def\nextday#1{{\count0=#1\mod7\dates@date\dates@weekd%
+ \advance\count0 by-\dates@weekd\relax%
+ \ifnum\count0<0\advance\count0 by7\fi%
+ \global\advance\dates@date by\count0}}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prevday}
+%
+% \begin{macrocode}
+\def\prevday#1{\snextday#1%
+ \global\advance\dates@date by-7}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\snextday}
+%
+% \begin{macrocode}
+\def\snextday#1{\global\advance\dates@date by1%
+ \nextday#1}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\sprevday}
+%
+% \begin{macrocode}
+\def\sprevday#1{\global\advance\dates@date by-1%
+ \prevday#1}
+% \end{macrocode}
+% \end{macro}
+%
+% Convert from Julian date and time in
+% \date to long date (in local time)
+%
+% \begin{macrocode}
+\def\jdttol{\advance\dates@date by500%
+ \advance\dates@date by\dates@timezone\divide\dates@date by1000}
+% \end{macrocode}
+%
+% \subsection{Trigonometric Functions}
+%
+% \begin{macrocode}
+\def\sintable#1{\ifcase #1 0\or100\or199%
+ \or296\or389\or479\or565\or644\or717%
+ \or783\or841\or891\or932\or964\or985%
+ \or997\or1000\or992\or974\or946\or909%
+ \or863\or808\or746\or675\or598\or516%
+ \or427\or335\or239\or141\or42\or-58%
+ \or-158\fi}
+% \end{macrocode}
+%
+% Reduces modulo "2\pi" (requires positive
+% argument theta):
+% "theta := theta" "MOD 2\pi", where
+% "theta = count1*10^(-3)"
+%
+% \begin{macrocode}
+\def\twopimod{\count2 =\count1%
+ \divide\count2 by6284 \count3 =1853%
+ \count4 =6283\multiply\count3 by\count2%
+ \multiply\count4 by\count2%
+ \divide\count3 by10000%
+ \advance\count3 by\count4%
+ \advance\count1 by-\count3}%
+% \end{macrocode}
+%
+% "v := sin(theta)", where
+% "v = count4*10^(-3)";
+% "theta = count1*10^(-3)"
+% theta is reduced "MOD 2\pi" to be
+% "0<=theta<2\pi" by "\TWOPIMOD",
+% then linear interpolation is performed
+% using "\SINTABLE".
+%
+% \begin{macrocode}
+\def\sin{\relax%
+ \ifnum\count1<0 \signtrue%
+ \count1=-\count1\else \signfalse\fi%
+ \loop\ifnum\count1>6284\twopimod\repeat\relax%
+ \ifnum\count1>3142%
+ \advance\count1 by-3142%
+ \ifsign\signfalse\else\signtrue\fi\fi%
+ \multiply\count1 by10\count3=\count1%
+ \divide\count3 by1000\count2=\count3%
+ \multiply\count3 by1000%
+ \advance\count3 by-\count1 %
+ \count5 =\sintable{\count2 }%
+ \count4 =\count5\advance\count2 by1%
+ \advance\count4 by -\sintable{\count2}%
+ \multiply\count4 by\count3%
+ \divide\count4 by1000%
+ \advance\count4 by\count5%
+ \ifsign\count4 =-\count4\fi}%
+% \end{macrocode}
+%
+% "v := cos(theta)", where
+% "v = count4*10^(-3)";
+% "theta = count1*10^(-3)".
+% "\SIN" is evaluated on "pi/2-theta".
+% \begin{macrocode}
+\def\cos{\advance\count1 by-1571%
+ \multiply\count1 by-1\sin}%
+% \end{macrocode}
+% Linear transformation of T giving
+% "theta := a*T+b", where
+% "T = count0*10^(-6)";
+% "theta = count1*10^(-3)";
+% "a = #1*10^3+#2+#3*10^(-3)";
+% "b = #4*10^(-3)"
+%
+% \begin{macrocode}
+\def\lin#1.#2.#3+#4.{\count1=#3%
+ \count2=#2\count3=#1%
+ \multiply\count1 by\count0%
+ \multiply\count2 by\count0\relax%
+ \multiply\count3 by\count0%
+ \divide\count1 by1000%
+ \advance\count1 by\count2%
+ \divide\count1 by1000%
+ \advance\count1 by\count3%
+ \advance\count1 by #4\relax}
+% \end{macrocode}
+%
+% Accumulate value returned by a
+% trigonometric function, scaled by
+% factor f, into count6:
+% "ac := ac+f*v", where
+% "ac = count6*10^(-7)"
+% "v = value" of "SIN" or "COS =count4*10^(-3)"
+% "f = #1*10^(-4)"
+%
+% \begin{macrocode}
+\def\fac#1{\multiply\count4 by #1%
+ \advance\count6 by\count4}
+\def\id{\count4=\count1} % Identity
+% \end{macrocode}
+%
+% \subsection{Initialization}
+%
+% This initializes
+% "\uselongtext" to the value selected by the user
+% in the package calling "dates".
+% \begin{macrocode}
+\def\dates@initialize@longtext{%
+ \ifuselongtext%
+ \def\dates@reset@longtext{%
+ \longtexttrue}%
+ \else%
+ \def\dates@reset@longtext{%
+ \longtextfalse}%
+ \fi}
+% \end{macrocode}
+%
+% Before anything further is executed, the following registers
+% and macros need to be in place.
+%
+% \begin{macrocode}
+\newcount\dates@year
+\newcount\dates@timezone
+\dates@timezone=0
+\newcount\dates@catch
+\newcount\dates@day
+\newcount\dates@everymonth@day
+\newcount\dates@month
+\newcount\dates@date
+\newcount\dates@one
+\newcount\dates@two
+\newcount\dates@three
+\newcount\dates@four
+\newcount\dates@weekd
+\newcount\dates@time@start
+\newcount\dates@time@end
+\newcount\dates@subrange@start
+\newcount\dates@subrange@end
+\newcount\dates@days
+\newcount\dates@lastdate
+\newcount\dates@yearbase
+\newcount\dates@weekd@target
+\newcount\dates@modulo
+\newcount\dates@year@full
+\newcount\dates@extra@day
+\newtoks\dates@reg
+\newtoks\dates@dayname
+\newtoks\dates@shortweekday
+\newtoks\dates@monthname
+\newtoks\dates@shortmonthname
+\newif\iflongtext
+\longtexttrue
+\newif\ifdates@requiremonth
+\newif\ifdates@requireday
+\newif\ifdates@suppress
+\newif\ifdates@suppress@global
+\newif\ifleapyear
+\let\delim\relax
+\def\enditall{END IT ALL}
+\def\dates@empty{}
+%</style>
+% \end{macrocode}
+%
+% \section{The Demo File}
+%
+% \begin{macrocode}
+%<*demo>
+\documentclass{minimal}
+\usepackage{dates}
+\begin{document}
+
+\makeatletter
+
+%<demo>%
+%<demo>% We invoke the \dateread command.
+%<demo>%
+\dateread
+%<demo>%
+%<demo>% We tell it to report a few details to the terminal.
+%<demo>%
+{\message{\theshorttext}%
+ \message{\theday/\the\dates@month/\the\dates@year}%
+ \ifx\thelongtext\dates@empty%
+ \else%
+ \message{\thelongtext}%
+ \fi}
+%<demo>%
+%<demo>% The following are ranges.
+%<demo>%
+ december 10 1995 {^^JStart of First}
+to jan 10 1996 {End of First}
+ december 10 1996 {^^JStart of Second}
+to jan 10 1997 {End of Second^^J}
+%<demo>%
+%<demo>% The following are specific dates (obviously)
+%<demo>%
+February 18 1997 {^^JFrank's Next Birthday}
+ [The best presents come in small packages.^^JIt
+ would be a terrific present for someone to make
+ this one smaller.]
+February 18 1998 {^^JFrank's Next Birthday But One}
+%<demo>%
+%<demo>% These are a couple of recursive dates.
+%<demo>%
+Every Monday {^^JMonday Coffee}
+Every Third Tuesday {^^JMeeting}
+%
+%<demo>% Here is a sample function definition, which gives
+%<demo>% the phases of the moon within the ranges. The code
+%<demo>% was ripped off from the calendar package for plain
+%<demo>% TeX
+%<demo>%
+
+function \moonsinit \moonsincrement
+
+ {
+ \newcount\moonno
+ \newif\ifsign
+
+ \def\firstmoon{\moonno=\dates@year
+ \multiply\moonno by123685
+ \divide\moonno by10000
+ \multiply\moonno by4\advance\moonno by-1
+ \loop\moondate\relax
+ \ifnum\dates@date<\dates@subrange@start
+ \advance\moonno by1\repeat}
+
+%<demo>% Compute date for cycle quarter MOONNO
+
+ \def\moondate{{\count0=\moonno
+ \lin 202.126.369+0.\count0=\count1
+ \count6=0
+ \lin 0.2.319+2907.\sin\fac{3}
+ \divide\count6 by1000
+ \lin 365.249.86+7593.\id\fac{1}
+ \divide\count6 by10\count7 =\count6
+ \ifodd\moonno\quarters
+ \else\fullornew\fi\global\dates@date=\count7}
+ \jdttol}
+
+%<demo>% Correction for full and new moon
+
+ \def\fullornew{\count6=0
+ \lin -393.0.0+0.
+ \divide\count1 by100000000
+ \advance\count6 by\count1
+ \lin 0.628.300+6269.\sin
+ \multiply\count6 by\count4
+ \lin -7.-700.-369+ 928.\sin\fac{ -74}
+ \lin 0. 628. 300+ 6269.\sin\fac{ 1734}
+ \lin 1. 256. 600+12539.\sin\fac{ 21}
+ \lin 8. 328. 670+ 5341.\sin\fac{-4068}
+ \lin 8. 538. 220+-4597.\sin\fac{ 10}
+ \lin 8. 956. 970+11610.\sin\fac{ -51}
+ \lin 16. 238. 589+-5526.\sin\fac{ -4}
+ \lin 16. 657. 340+10682.\sin\fac{ 161}
+ \lin 16. 866. 890+ 743.\sin\fac{ 104}
+ \lin 17. 285. 640+16951.\sin\fac{ 50}
+ \lin 17. 495. 190+ 7013.\sin\fac{ 4}
+ \lin 24. 986. 10+16023.\sin\fac{ -4}
+ \lin 25. 195. 560+ 6084.\sin\fac{ -6}
+ \divide\count6 by10000
+ \advance\count7 by\count6 }
+
+%<demo>% Correction for quarters
+
+ \def\quarters{\lin -393.0.0+0.
+ \divide\count1 by100000000
+ \count6 =\count1 \lin 0.628.300+6269.
+ \sin\multiply\count6 by\count4
+ \lin -16. -29. -40+-4413.\sin\fac{ 40}
+ \lin -7.-700.-369+ 928.\sin\fac{ -47}
+ \lin -7. -72. -69+ 7198.\sin\fac{ -30}
+ \lin 0. 628. 300+ 6270.\sin\fac{ 1721}
+ \lin 1. 256. 600+12539.\sin\fac{ 21}
+ \lin 8. 328. 670+ 5341.\sin\fac{-6280}
+ \lin 8. 538. 220+-4598.\sin\fac{ 21}
+ \lin 8. 956. 970+11611.\sin\fac{ -119}
+ \lin 16. 238. 589+-5526.\sin\fac{ -4}
+ \lin 16. 657. 340+10682.\sin\fac{ 89}
+ \lin 16. 866. 890+ 743.\sin\fac{ 79}
+ \lin 17. 285. 640+16952.\sin\fac{ 3}
+ \lin 17. 495. 190+ 7013.\sin\fac{ 3}
+ \lin 24. 986. 10+16023.\sin\fac{ -4}
+ \lin 25. 195. 560+ 6085.\sin\fac{ -6}
+ \count8=\count6\count6=28000
+ \lin 628. 300. 373+ 6270.\cos\fac{ -4}
+ \lin 8. 328. 670+ 5341.\cos\fac{ 3}
+ \count2=\moonno
+ \advance\count2 by-1\divide\count2 by2
+ \ifodd\count2\multiply\count6 by-1 \fi
+ \advance\count6 by\count8
+ \divide\count6 by10000
+ \advance\count7 by\count6 }
+
+%<demo>% Events for phases.
+%<demo>% Uses PHASE (local).
+
+ \def\phase{{\count0=\moonno
+ \count1=\moonno
+ \divide\count0 by4\multiply\count0 by4
+ \advance\count1 by-\count0\relax
+ \global\edef\themoon{\ifcase\count1
+ New Moon\or First Quarter\or
+ Full Moon\or Last Quarter\fi}}}
+
+ \gdef\moonsinit{%
+ \firstmoon
+ \dates@month=12\dates@day=31\dates@fix\advance\dates@date by1
+ \count1=\dates@date
+ \moondate
+ \phase
+ \caldate}
+
+ \gdef\moonsincrement{%
+ \advance\moonno by 1
+ \moondate\phase
+ \caldate}
+
+ }
+ {\themoon}
+
+\end{document}
+%</demo>
+% \end{macrocode}
+%
+%\iffalse
+% \begin{macrocode}
+%<syntax>% \section{Date Syntax}
+%<syntax>%
+%<syntax>% \subsection{General Rules}
+%<syntax>%
+%<syntax>% The rules themselves are explained here first. If you
+%<syntax>% want to cut to the chase, have a look at the examples
+%<syntax>% and experiment a bit with the demo file. It's all
+%<syntax>% pretty straightforward.
+%<syntax>%
+%<syntax>% The parser is indifferent to extra spaces and blank
+%<syntax>% lines in dates. It will read a string word by word,
+%<syntax>% and classify each word as a time, a day of the month,
+%<syntax>% the name of a month, a year or a special function.
+%<syntax>% With two exceptions, strings beginning in a number must not mix numbers and
+%<syntax>% other characters --- this will produce a low-level
+%<syntax>% error from \TeX, and at the moment I can't think of
+%<syntax>% an economical way of protecting against this.
+%<syntax>%
+%<syntax>% Any string
+%<syntax>% beginning in a number is interpreted as either a
+%<syntax>% time, a day of the month or a year. A string
+%<syntax>% containing a colon (the ":" character) is assumed
+%<syntax>% to be a time of day. "AM" and "PM" are not recognized;
+%<syntax>% you should use 24-hour format when specifying
+%<syntax>% times. A numeric string containing a hyphen is assumed
+%<syntax>% to be a range of times. In this instance, a colon
+%<syntax>% is not necessary if the time is given in whole-hours.
+%<syntax>% Pure numeric strings are construed as a day of the month
+%<syntax>% if less than 32, or as a year if greater than 31.
+%<syntax>%
+%<syntax>% Character strings are interpreted on the basis of their
+%<syntax>% first three characters; the rest are ignored. Case is
+%<syntax>% also irrelevant. Months and days of the week (used for
+%<syntax>% defining recursive dates, described below) as well as certain
+%<syntax>% special functions are specified as character strings.
+%<syntax>% Any word that does not match an existing function
+%<syntax>% will be ignored.
+%<syntax>%
+%<syntax>% Dates are always terminated by a short description
+%<syntax>% of the date, which must be in curly braces.
+%<syntax>% The description should contain plain text only;
+%<syntax>% do not put macros (like "\LaTeX") here.
+%<syntax>%
+%<syntax>% Dates will be processed until "\dateread" encounters
+%<syntax>% "\end{<"\meta{environment name}">}", or the string
+%<syntax>% "\relax{}". At the "\end" of an environment,
+%<syntax>% the processing of the current date will be completed,
+%<syntax>% and the "\end" will be executed. "\relax{}" will
+%<syntax>% cause processing to end silently without doing
+%<syntax>% anything on the last item (which is the "\relax{}" itself).
+%<syntax>%
+%<syntax>% \subsection{Specific Dates}
+%<syntax>%
+%<syntax>% Applying the above rules, the following is a valid
+%<syntax>% list of dates. The use of "\dateread" is explained
+%<syntax>% below.
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% \begin{quote}
+%<syntax>% \dateread{\message{\theshorttext}}
+%<syntax>% Jan 1 1996{New Year's Day}
+%<syntax>% 1 January 1996 at 10:00
+%<syntax>% {New Year Bash}"\\
+%<syntax>% 1996
+%<syntax>% jan 1 8-20:30
+%<syntax>% {New Year Cleaning. Rats.}"
+%<syntax>% \end{quote}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% Note that the parser is indifferent to word order,
+%<syntax>% and that commas should not be used to separate
+%<syntax>% words.\footnote{In fact, commas do no harm if
+%<syntax>% they follow a string of three or more letters, but
+%<syntax>% it is best to keep things simple and clean.}
+%<syntax>%
+%<syntax>% \subsection{Recursive Dates}
+%<syntax>%
+%<syntax>% \subsubsection{Ranges}
+%<syntax>%
+%<syntax>% Any recursive dates (such as "Every" "Monday") must
+%<syntax>% be preceded by one or more range specifications,
+%<syntax>% which fix the time period or periods within which to
+%<syntax>% recurse.
+%<syntax>% A range is simply two specific dates separated by the
+%<syntax>% word "to". You may specify multiple ranges;
+%<syntax>% effect will be given to each of them individually.
+%<syntax>%
+%<syntax>% The following is a valid range specification:
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% February 1 1996 {Start First Period}
+%<syntax>% to April 1 1996 {End First Period}
+%<syntax>% November 3 1996 {Start Second Period}
+%<syntax>% to December 24 1996 {End Second Period}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% \subsubsection{Shorthand Dates}
+%<syntax>%
+%<syntax>% Three types of recursive date can be entered in a
+%<syntax>% human-readable syntax. Entries of all types
+%<syntax>% begin with the word "every". To put an event
+%<syntax>% on every occurence of a day of the week within
+%<syntax>% a specified set of subranges, simply indicate the day
+%<syntax>% of the week, followed by a short description
+%<syntax>% in curly braces.
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% Every Monday {Monday!}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% To put an event at 14-day intervals, beginning
+%<syntax>% with the first occurrence of a specified day
+%<syntax>% of the week within each subrange, add the
+%<syntax>% word "other".
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% Every other Monday 7:00 {Monday Morning Exercise}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% To place an event on the "N"th occurrence of
+%<syntax>% a specified day of the week within each month, within
+%<syntax>% subrange, add "first", "second" or "third".
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% Every third Monday 8:00-9:00
+%<syntax>% {Monday Morning Meeting}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% To place an event on the same day (as opposed to
+%<syntax>% day of the week) in every month, just put the
+%<syntax>% number of that day after "every":
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% Every 20 {Mortgage payment}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% \subsubsection{Suppressing the Action}
+%<syntax>%
+%<syntax>% There are two ways of suppressing the user-defined action.
+%<syntax>% To quickly comment out an entry, put the word "rem" in
+%<syntax>% front of it. The date will be read, but the action
+%<syntax>% in the argument to "\dateread" will not be performed.
+%<syntax>% This can be used, for example, to suppress the appearance
+%<syntax>% of a range in the output text.
+%<syntax>%
+%<syntax>% The second method uses a toggle, and is meant for use by
+%<syntax>% style authors. Setting:
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% "\dates@suppress@globaltrue"
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% \noindent will cause the user action to be suppressed
+%<syntax>% throughout the invocation of "\dateread". In order for
+%<syntax>% the action to be performed on the next invocation,
+%<syntax>% the toggle must be set to "false" in the external
+%<syntax>% code that calls the parser.
+%<syntax>%
+%<syntax>% \subsubsection{Functions}
+%<syntax>%
+%<syntax>% It is possible to specify dates within the subranges
+%<syntax>% using an arbitrary formula. Entries of this type
+%<syntax>% begin with the word "function". This is followed
+%<syntax>% by two control strings, a block of \LaTeX{} code in
+%<syntax>% curly braces, and the usual short description, also in
+%<syntax>% curly braces.
+%<syntax>%
+%<syntax>% The first control string is the name of a
+%<syntax>% user-defined macro that will find the position
+%<syntax>% of the first desired date after the start of the
+%<syntax>% range. The second is the name of a macro to
+%<syntax>% use in incrementing afterward. The block of
+%<syntax>% \LaTeX{} code contains the definitions of these
+%<syntax>% and any subsidiary macros.
+%<syntax>%
+%<syntax>% The following will place an entry on every date within
+%<syntax>% the specified subranges.
+%<syntax>%
+%<syntax>% \begin{quote}
+%<syntax>% \begin{verbatim}
+%<syntax>% Function \myinit \myincrement
+%<syntax>% {\def\myinit{%
+%<syntax>% \dates@date=\dates@subrange@start}
+%<syntax>% \def\myincrement{%
+%<syntax>% \advance\dates@date by 1\relax}
+%<syntax>% }
+%<syntax>% {A Day}
+%<syntax>% \end{verbatim}
+%<syntax>% \end{quote}
+%<syntax>%
+%<syntax>% See the code commentary section of the Dates package for information
+%<syntax>% on macros that can be used for manipulating dates.
+% \end{macrocode}
+%
+% \section{The Installation File}
+% \begin{macrocode}
+%<*installer>
+\def\batchfile{dates.ins}
+\input docstrip.tex
+
+\keepsilent
+
+\preamble
+
+This file is part of the Dates package.
+Copyright (C) 1996, 1997 Frank Bennett, Jr.
+All rights reserved.
+------------------------------------------
+This is a generated file.
+
+IMPORTANT NOTICE:
+
+You are not allowed to change this file. You may however copy
+this file to a file with a different name and then change the
+copy if (a) you do not charge for the modified code, (b) you
+acknowledge the author(s) in the new file, if it
+is distributed to others, and (c) you attach these same
+conditions to the new file.
+
+You are not allowed to distribute this file alone. You are not
+allowed to take money for the distribution or use of this file
+(or a changed version) except for a nominal charge for copying
+etc.
+
+You are allowed to distribute this file under the condition that
+it is distributed with all of its contents, intact.
+
+For error reports, or offers to help make this a more powerful,
+friendlier, and better package, please contact me on
+`fb' at soas.ac.uk
+
+\endpreamble
+
+\generate{\file{dates.sty} {\from{dates.dtx}{style}}
+ }
+
+\preamble
+
+This file is part of the Dates package,
+Copyright (C) 1996, 1997 Frank Bennett, Jr.
+All rights reserved.
+------------------------------------------
+This file is provided for demonstration purposes; feel free
+to edit it in any way whatsoever.
+------------------------------------------
+
+
+
+\endpreamble
+
+\postamble
+\endpostamble
+
+\generate{\file{demo.tex}{\from{dates.dtx}{demo}}
+ }
+
+\preamble
+\endpreamble
+
+\let\WritePreamble\@gobble
+\let\WritePostamble\@gobble
+
+\generate{\file{datesynt.tex}{\from{dates.dtx}{syntax}}
+ }
+
+\Msg{***********************************************************}
+\Msg{*}
+\Msg{* To finish the installation, you have to move the following}
+\Msg{* file into a directory searched by TeX:}
+\Msg{*}
+\Msg{* \space\space dates.sty}
+\Msg{*}
+\Msg{***********************************************************}
+}
+%</installer>
+% \end{macrocode}
+%\fi
+% \Finale \PrintChanges
diff --git a/macros/latex/contrib/dates/dates.ins b/macros/latex/contrib/dates/dates.ins
new file mode 100644
index 0000000000..2dc187e9d7
--- /dev/null
+++ b/macros/latex/contrib/dates/dates.ins
@@ -0,0 +1,96 @@
+%%
+%% This is file `dates.ins',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% dates.dtx (with options: `installer')
+%%
+%% IMPORTANT NOTICE:
+%%
+%% For the copyright see the source file.
+%%
+%% You are *not* allowed to modify this file.
+%%
+%% You are *not* allowed to distribute this file.
+%% For distribution of the original source see
+%% the terms for copying and modification in the file dates.dtx.
+%%
+\def\batchfile{dates.ins}
+\input docstrip.tex
+
+\keepsilent
+
+\preamble
+
+This file is part of the Dates package.
+Copyright (C) 1996 Frank Bennett, Jr.
+All rights reserved.
+------------------------------------------
+This is a generated file.
+
+IMPORTANT NOTICE:
+
+You are not allowed to change this file. You may however copy
+this file to a file with a different name and then change the
+copy if (a) you do not charge for the modified code, (b) you
+acknowledge the author(s) in the new file, if it
+is distributed to others, and (c) you attach these same
+conditions to the new file.
+
+You are not allowed to distribute this file alone. You are not
+allowed to take money for the distribution or use of this file
+(or a changed version) except for a nominal charge for copying
+etc.
+
+You are allowed to distribute this file under the condition that
+it is distributed with all of its contents, intact.
+
+For error reports, or offers to help make this a more powerful,
+friendlier, and better package, please contact me on
+`fb' at soas.ac.uk
+
+\endpreamble
+
+\generate{\file{dates.sty} {\from{dates.dtx}{style}}
+ }
+
+\preamble
+
+This file is part of the Dates package,
+Copyright (C) 1996 Frank Bennett, Jr.
+All rights reserved.
+------------------------------------------
+This file is provided for demonstration purposes; feel free
+to edit it in any way whatsoever.
+------------------------------------------
+
+\endpreamble
+
+\postamble
+\endpostamble
+
+\generate{\file{demo.tex}{\from{dates.dtx}{demo}}
+ }
+
+\preamble
+\endpreamble
+
+\let\WritePreamble\@gobble
+\let\WritePostamble\@gobble
+
+\generate{\file{datesynt.tex}{\from{dates.dtx}{syntax}}
+ }
+
+\Msg{***********************************************************}
+\Msg{*}
+\Msg{* To finish the installation, you have to move the following}
+\Msg{* file into a directory searched by TeX:}
+\Msg{*}
+\Msg{* \space\space dates.sty}
+\Msg{*}
+\Msg{***********************************************************}
+}
+\endinput
+%%
+%% End of file `dates.ins'.