texlive[74010] Master: timechart (15feb25)

commits+karl at tug.org commits+karl at tug.org
Sat Feb 15 22:28:35 CET 2025


Revision: 74010
          https://tug.org/svn/texlive?view=revision&revision=74010
Author:   karl
Date:     2025-02-15 22:28:35 +0100 (Sat, 15 Feb 2025)
Log Message:
-----------
timechart (15feb25)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/timechart/
    trunk/Master/texmf-dist/doc/latex/timechart/README.md
    trunk/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf
    trunk/Master/texmf-dist/source/latex/timechart/
    trunk/Master/texmf-dist/source/latex/timechart/timechart.dtx
    trunk/Master/texmf-dist/source/latex/timechart/timechart.ins
    trunk/Master/texmf-dist/tex/latex/timechart/
    trunk/Master/texmf-dist/tex/latex/timechart/timechart.sty
    trunk/Master/tlpkg/tlpsrc/timechart.tlpsrc

Added: trunk/Master/texmf-dist/doc/latex/timechart/README.md
===================================================================
--- trunk/Master/texmf-dist/doc/latex/timechart/README.md	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/timechart/README.md	2025-02-15 21:28:35 UTC (rev 74010)
@@ -0,0 +1,16 @@
+# `timechart` - A package for drawing chronological charts
+
+## Description
+
+This package provides for the easy creation of chronological charts which show visually the relative historical
+positions of people and events. Each event or period can be specified by a single line of LaTeX code comprising
+(possibly uncertain) start and finish dates and a label, and the package takes care of indicating the uncertainties and
+whether intervals extend beyond the specified bounds of the chart.
+
+## Author
+
+This package is by Alan J. Cain: a.j.cain (AT) gmail.com
+
+## Licence
+
+Released under the LaTeX Project Public License v1.3c or later: https://www.latex-project.org/lppl.txt


Property changes on: trunk/Master/texmf-dist/doc/latex/timechart/README.md
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf	2025-02-15 21:26:13 UTC (rev 74009)
+++ trunk/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf	2025-02-15 21:28:35 UTC (rev 74010)

Property changes on: trunk/Master/texmf-dist/doc/latex/timechart/timechart-doc.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/source/latex/timechart/timechart.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/timechart/timechart.dtx	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/timechart/timechart.dtx	2025-02-15 21:28:35 UTC (rev 74010)
@@ -0,0 +1,3458 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2025 Alan J. Cain
+%
+% This file may be distributed and/or modified under the conditions of the LaTeX Project Public Licence, either version
+% 1.3 of this licence or (at your option) any later version. The latest version of this licence is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3c or later is part of all distributions of LaTeX version 2008-05-04 or later.
+%
+% \fi
+%
+% \iffalse
+%<*driver>
+\PassOptionsToPackage{inline}{enumitem}
+\documentclass{l3doc}
+
+
+
+% Make space for larger numbers in contents
+
+\makeatletter
+\ExplSyntaxOn
+
+\cs_gset:Npn \l at subsection { \@dottedtocline{2}{2.5em}{2.8em} }
+\cs_gset:Npn \l at subsubsection { \@dottedtocline{3}{5.3em}{4em} }
+
+\ExplSyntaxOff
+\makeatother
+
+
+
+% Link formatting
+
+\usepackage{xcolor}
+
+\definecolor{linkcolor}{rgb}{0.0,0.4,0.7}
+\colorlet{citecolor}{linkcolor}
+\colorlet{urlcolor}{linkcolor}
+
+\hypersetup{
+  linkcolor=linkcolor,%
+  citecolor=citecolor,%
+  urlcolor=urlcolor,%
+}
+
+\newcommand*\fullref[2]{%
+  \hyperref[#2]{#1\penalty 200\ \ref*{#2}}%
+}
+
+
+
+% Use siunitx for typesetting dimensions
+
+\usepackage{siunitx}
+\sisetup{
+  mode=match,
+}
+\DeclareSIUnit\point{pt}
+
+
+
+% Listings and grammars
+
+\usepackage{listings}
+\lstset{
+  language=[LaTeX]TeX,
+  basicstyle=\small\ttfamily,
+  basewidth=0.5em,
+  numbers=left,
+  numberstyle=\scriptsize\sffamily,
+}
+
+\usepackage{simplebnf}
+
+
+
+% Macros for describing keys
+
+\newlist{optionlist}{description}{1}
+\setlist[optionlist]{
+  leftmargin=3em,
+  style=unboxed,
+  labelsep=1em,
+  font=\descriptionitemcolon,
+  nosep,
+}
+\newcommand*{\descriptionitemcolon}[1]{\kern 1em #1:}
+
+
+\newcommand*\key[1]{\texttt{#1}}
+\newcommand*\val[1]{\texttt{#1}}
+\newcommand*\keyval[2]{\texttt{#1=#2}}
+
+\usepackage{xcolor}
+\definecolor{keycolor}{rgb}{0.8,0.0,0.0}
+\definecolor{keyvaluecolor}{rgb}{0.0,0.65,0.0}
+
+\ExplSyntaxOn
+
+\NewDocumentEnvironment{describekey}{ m m m }{
+  \group_begin:
+  \group_begin:
+  \noindent{\textcolor{keycolor}{\texttt{#1}}}
+  \str_if_empty:nF{#2}
+    {
+      \skip_set:Nn{\parfillskip}{0pt}
+      \str_case:nnF{#2}
+      {
+        {style}
+        {
+          \hfil
+          (style,~initially~#3)
+        }
+      }
+      {
+        \textcolor{keyvaluecolor}{\texttt{=}\meta{#2}}
+        \str_if_empty:nF{#3}
+          {
+            \hfil
+            (default\nobreakspace\texttt{#3})
+          }
+      }
+    }
+  \par
+  \group_end:
+  \nobreak
+  \skip_add:Nn{\leftskip}{\parindent}
+  \noindent\ignorespaces
+}{
+  \par
+  \group_end:
+}
+
+\ExplSyntaxOff
+
+
+\newcommand*\mcode[1]{\texttt{#1}}
+\newcommand*\param[1]{\texttt{\##1}}
+
+
+
+% Other macros
+
+\newcommand*\TikZ{\texorpdfstring{Ti\textit{k}Z}{TikZ}}
+\newcommand*\ISO{\textsc{iso}}
+
+
+
+% Timechart
+
+\usepackage{timechart}
+
+\input{timechart-example1-setup.tex}
+
+
+
+\begin{document}
+\DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+%
+%
+% \GetFileInfo{timechart.sty}
+%
+%
+%
+% \title{^^A
+% \pkg{timechart} ^^A
+%   --- A package for drawing chronological charts^^A
+%   \thanks{This file describes \fileversion, last revised \filedate.}^^A
+% }
+%
+% \author{^^A
+%  Alan J. Cain^^A
+% }
+%
+% \date{Released \filedate}
+%
+% \maketitle
+%
+%
+%
+% \begin{abstract}
+%   This package provides for the easy creation of chronological charts which show visually the relative historical
+%   positions of people and events. Each event or period can be specified by a single line of \LaTeX\ code comprising
+%   (possibly uncertain) start and finish dates and a label, and the package takes care of indicating the uncertainties
+%   and whether intervals extend beyond the specified bounds of the chart.
+% \end{abstract}
+%
+%
+%
+% \tableofcontents
+%
+%
+%
+% \begin{documentation}
+%
+% \setcounter{secnumdepth}{2}
+%
+%
+% \section{Introduction}
+%
+% The \pkg{timechart} package provides a system for the easy creation of chronological charts --- of the type pioneered
+% by Joseph Priestley (1733--1804) in his `Chart of Biography' and more famously in his `New Chart of
+% History'\footnote{\textsc{url}:~\url{https://commons.wikimedia.org/wiki/File:A_New_Chart_of_History_color.jpg}} ---
+% which can show visually the relative historical positions of people and events. An example of what \pkg{timechart} can
+% be used to produce is shown in \fullref{Figure}{fig:example1} on page~\pageref{fig:example1}.
+%
+% \begin{figure}[p]
+%   \centering
+%   \input{timechart-example1-timechart.tex}
+%   \caption{Timechart showing the lifetimes of Roman emperors from \timechartmakebeforeyear{50} to
+%   \timechartmakeafteryear{500}. Marks on each lifetime indicate the beginning (and, where relevant, the end) of that
+%   emperor's reign. Colours generally indicate dynasties, with shades of green indicating periods when the imperial
+%   power shifted between many short-reigning emperors.}
+%   \label{fig:example1}
+% \end{figure}
+%
+% Essentially (and this was a design requirement), \emph{only one line} of \LaTeX\ code is required for each interval
+% (which, in the case of \fullref{Figure}{fig:example1}, are mostly lifetimes). The \pkg{timechart} package takes care
+% of indicating ranges of possible dates by suitable fading from or to transparency. It also handles indicators to show
+% that intervals continue outside the specified scope of the chart.
+%
+% \pkg{timechart} was developed from, and replaced, a set of macros used to create the chronological charts in the
+% author's book \textit{Form \& Number: A History of Mathematical Beauty}, which is available on the Internet Archive
+% under a Creative Commons licence.\footnote{\textsc{url}:
+% \url{https://archive.org/details/cain_formandnumber_ebook_large}}
+%
+%
+%
+% \paragraph*{Licence.} \noindent\pkg{timechart} is released under the LaTeX Project Public Licence v1.3c or
+% later.\footnote{\textsc{url}: \url{https://www.latex-project.org/lppl.txt}}
+%
+%
+%
+% \paragraph*{Acknowledgements.} The author thanks Tânia Paulista for reading and commenting on an earlier draft of the
+% documentation.
+%
+%
+%
+% \section{Requirements}
+%
+% \pkg{timechart} requires PGF/\TikZ\ and a \LaTeX\ kernel with \pkg{expl3} support (any kernel version since 2020-02-02
+% should suffice).
+%
+%
+%
+% \section{Installation}
+%
+% To install manually, run \texttt{tex timechart.ins} and copy the file \file{timechart.sty} to somewhere \LaTeX\ can
+% find it.
+%
+%
+%
+% \section{Getting started}
+%
+% The \pkg{timechart} package is loaded as usual via \cs{usepackage}\texttt{\{timechart\}}. There are no package
+% options.
+%
+% The small example in \fullref{Section}{sec:example} illustrates the basic principles of \pkg{timechart}.
+% \fullref{Section}{sec:full-example} shows the full code used to produce the large example in \fullref{Figure}{fig:example1}.
+%
+%
+%
+%
+%
+% \section{Example}
+% \label{sec:example}
+%
+% This section illustrates how to create the small chart shown in \fullref{Figure}{fig:example2-v2} on
+% page~\pageref{fig:example2-v2}.
+%
+% The basic environment is \env{timechart}, which includes the specification of the start and finish years. The start
+% year \timechartmakebeforeyear{50} is specified as \mcode{-50}, the finish year \timechartmakeafteryear{75} as
+% \mcode{75}. Each interval in the chart is specified using the \cs{timechartinterval} command, which takes three
+% mandatory parameters: a start year, a finish year, and a label. The following code produces the flawed preliminary
+% version shown in \fullref{Figure}{fig:example2-v1}.
+%
+% \lstinputlisting{timechart-example2-v1.tex}
+%
+% \begin{figure}[ht]
+%   \centering
+%   \input{timechart-example2-v1.tex}
+%   \medskip
+%   \caption{Flawed preliminary version of a chart showing the lifetimes of Roman emperors of the Julio-Claudian
+%   dynasty. (The final version is shown in \fullref{Figure}{fig:example2-v2}.)}
+%   \label{fig:example2-v1}
+% \end{figure}
+%
+% This first attempt result illustrates some of the principles of \pkg{timechart}. Each interval has been placed on its
+% own line. More precisely, the \(y\) coordinate of the first interval is \(0\) and each use of \cs{timechartinterval}
+% increments the `current \(y\) coordinate' by a specified amount. (Various commands are available to set the \(y\)
+% coordinate manually or to reset it automatically when it passes certain bounds; see
+% \fullref{Subsection}{subsec:positioning}.) Horizontally, the chart starts and finishes at the specified years. The topmost
+% interval, indicating Augustus' life, has been truncated with an indicator that it begins before the specified start
+% year of the chart. Vertically, the chart has been sized to fit around the specified intervals.
+%
+% But this version is hardly satisfactory, for many reasons. The chart finishes between two minor ticks on the axis,
+% because the intervals between major and minor ticks default respectively to 10 years and 50 years. The black intervals
+% and text do not contrast well with the black axis and grid. The serif font is perhaps not best suited to label the
+% intervals. And the label `Augustus' has been lost, since labels are by default placed on the left of intervals. To
+% rectify these problems, some changes are necessary, all of which can be made using key-value syntax in an optional
+% parameter to the \env{timechart} environment or the \cs{timechartinterval} command:
+% \begin{enumerate}
+%     \item Set the intervals between major and minor ticks to 5 years and 25 years respectively, by setting
+%           \keyval{minor tick interval}{5} and \keyval{major tick interval}{25}.
+%     \item Change the colour of the grid to light grey by appending \keyval{draw}{lightgray} to the \key{grid} style
+%     \item Change the colour of the axis to grey by appending \keyval{draw}{gray} to the \key{axis line}, \key{minor
+%           tick}, and \key{major tick} styles.
+%     \item Change the font used for interval labels to small san-serif by appending \keyval{node
+%           font}{\cs{sffamily}\cs{small}} to the \key{interval label} style
+%     \item Change the colour of the intervals by defining a style \key{julioclaudian} that sets \keyval{interval bar
+%           color}{red!80!black} and applying it to each interval via its optional argument. (While \key{interval bar
+%           color} could be set locally for each interval, it is better to define a style that corresponds to the
+%           semantic meaning of the colour: in this case, a single dynasty.)
+%     \item Use the \key{right} key to place some labels on the right
+% \end{enumerate}
+%
+% The result is the following code, which produces \fullref{Figure}{fig:example2-v2}.
+%
+% \lstinputlisting{timechart-example2-v2.tex}
+%
+% \begin{figure}[ht]
+%   \centering
+%   \input{timechart-example2-v2.tex}
+%   \caption{Chart showing the lifetimes of Roman emperors of the Julio-Claudian dynasty.}
+%   \label{fig:example2-v2}
+% \end{figure}
+%
+%
+%
+% \section{Configuration}
+%
+% All \pkg{timechart} configuration, global or local, is via PGF keys, so some familiarity with their use is beneficial;
+% see the PGF/\TikZ\ manual.
+%
+% Configuration keys for \pkg{timechart} are contained in \key{/timechart/} in the PGF keys hierarchy. The
+% \meta{options} passed to the \env{timechart} environment or any of the commands \cs{timechartinterval},
+% \cs{timecharttext}, or \cs{timechartspace} are processed within \key{/timechart/} (since \key{/timechart/.cd} is
+% executed before keys are processed).
+%
+% The user may wish to define PGF styles for different kinds of interval within a chart. For example, one could
+% define styles \key{science} and \key{art} that set a particular colour for the interval, and write
+% \cs{timechartinterval}\key{[science]}\marg{birth}\marg{death}\marg{name} or
+% \cs{timechartinterval}\key{[art]}\marg{birth}\marg{death}\marg{name} to distinguish visually the lifetimes of
+% various scientists and artists.
+%
+%
+%
+% \section{Specifying dates and date ranges}
+% \label{sec:dates-and-ranges}
+%
+% Using \pkg{timechart} requires specification of dates and date ranges for the start and finish of each interval, both
+% of which may be uncertain.
+%
+% The basic specification of a date uses \ISO~8601 format \mcode{YYYY-MM-DD}. This format specifies a date with
+% day-level precision; use \mcode{YYYY-MM} and \mcode{YYYY} for month- and year-level precision. If the date is prefixed
+% by \mcode{-}, it is treated as the corresponding date before the epoch. (This is a difference with \ISO~8601, in which
+% \texttt{0} represents \timechartmakebeforeyear{1}, \texttt{-1} represents \timechartmakebeforeyear{2}, and so on.) So
+% (assuming that one is using \textsc{bce}/\textsc{ce}) one uses \mcode{-100} to indicate \timechartmakebeforeyear{100}
+% and \mcode{100} to indicate \timechartmakeafteryear{100}. (The era indicators `\textsc{bce}' and `\textsc{ce}' appear
+% on the axis. Alternative era indicators --- or a different epoch --- can be specified; see
+% \fullref{Section}{sec:era-indicators}.)
+%
+% A date can be prefixed with a \mcode{c} to indicate `circa', such as \mcode{c-100} for `circa
+% \timechartmakebeforeyear{100}' and \mcode{c100} for `circa \timechartmakeafteryear{100}'. When an interval is drawn in
+% a chart, `circa' will be indicated by automatically creating (or extending) a range according to the value of the key
+% \key{circa uncertainty} (see \fullref{Subsection}{subsec:intervals}).
+%
+% A date range comprises two dates (each with or without \mcode{c}) separated by a slash \mcode{/}, with the first date
+% being earlier (or equal to) the second date. (The slash indicates a range of dates per \ISO~8601.) A date
+% range can be used to indicate a broader uncertainty than the default `circa', or to indicate a definite range within
+% which an interval starts or ends.
+%
+% \begin{description}
+%     \item[Examples of correctly formatted dates and date ranges:] \mcode{-50}, \mcode{100}, \mcode{c-50},
+%           \mcode{c100}, \mcode{-50/100}, \mcode{c-50 / +100}, \mcode{-50/c100}, \mcode{c-50/c100}, \mcode{-585-05-28},
+%           \mcode{1947-12-01}, \mcode{1989-11}.
+%
+%     \item[Examples of incorrectly formatted date and date ranges:] \mcode{100?}, \mcode{100CE}, \mcode{100BCE},
+%           \mcode{-50-100}, \mcode{100/-50}.
+% \end{description}
+%
+% \noindent That is, the syntax for dates and date ranges is per the following (not-quite-formal) grammar:
+%
+% \smallskip
+%
+% \begin{bnf}
+%   \meta{cdate-or-crange} ::= \meta{cdate}
+%   | \meta{crange} ;;
+%   \meta{cdate} ::= \meta{date}
+%   | \mcode{c}\meta{date} ;;
+%   \meta{date} ::= \meta{pdate}
+%   | \mcode{-}\meta{pdate} ;;
+%   \meta{pdate} ::= \meta{year}\mcode{-}\meta{month}\mcode{-}\meta{day}
+%   | \meta{year}\mcode{-}\meta{month}
+%   | \meta{year} ;;
+%   \meta{crange} ::= \meta{\(\text{date}_1\)}\mcode{/}\meta{\(\text{date}_2\)}
+%   | \mcode{c}\meta{\(\text{date}_1\)}\mcode{/}\meta{\(\text{date}_2\)}
+%   | \meta{\(\text{date}_1\)}\mcode{/}\mcode{c}\meta{\(\text{date}_2\)}
+%   | \mcode{c}\meta{\(\text{date}_1\)}\mcode{/}\mcode{c}\meta{\(\text{date}_2\)} ~~~(with \(\text{date}_1 \leq \text{date}_2\)) ;;
+% \end{bnf}
+%
+% \smallskip
+%
+% \noindent The bounds of the \env{timechart} environment (see \fullref{Section}{sec:timechart-env}) must satisfy
+% \meta{cdate} in this grammar (although only the \meta{year} is used); the start and finish dates of an
+% \cs{timechartinterval} command (see \fullref{Subsection}{subsec:intervals}) must satisfy \meta{cdate-or-crange}; the
+% parameter of an \cs{timecharttext} command (see \fullref{Subsection}{subsec:text}) must satisfy \meta{date}.
+%
+% \medskip
+% \noindent \textit{Note.} For performance reasons, the date parser does only limited error-checking. Months outside the
+% range from \mcode{01} to \mcode{12} or days outside the range of the specified month will be ignored. Otherwise
+% malformed dates or date ranges may produce obscure error messages or unexpected results.
+%
+%
+%
+% \section{\env{timechart} environment}
+% \label{sec:timechart-env}
+%
+% \begin{function}{timechart}
+%   \begin{syntax}
+%     \cs{begin}\texttt{\{}\env{timechart}\texttt{\}}\oarg{options}\marg{start}\marg{finish}
+%       \meta{content}
+%     \cs{end}\texttt{\{}\env{timechart}\texttt{\}}
+%   \end{syntax}
+%   This is the main environment for creating a chronological chart. The mandatory arguments \meta{start} and
+%   \meta{finish} specify the first and last years of the chart. These can be dates with circa indicators (that is, they
+%   satisfy \meta{cdate} in the grammar in \fullref{Section}{sec:dates-and-ranges}), but the circa specifier has no
+%   effect and only the `year' part of the date is used. The optional argument \meta{options} supplies PGF keys that
+%   apply to the entire chart.
+%
+%   The \meta{content} comprises commands like \cs{timechartinterval}, \cs{timecharttext}, \cs{timechartspace},
+%   commands for positioning, as described in \fullref{Section}{sec:within}, and the user's own \TikZ\ code.
+% \end{function}
+%
+%
+%
+% \subsection{General configuration of the \env{timechart} environment}
+%
+% \begin{describekey}{/timechart/width}{dimension}{\cs{textwidth}}
+%   The width of the chart. This refers to the width of the grid and axis of the chart, not
+%   including intervals that pass beyond the specified limits of the chart, or axis labels that protrude beyond the
+%   width of the axis itself.
+% \end{describekey}
+%
+%
+% \begin{describekey}{/timechart/tolerance}{dimension}{5pt}
+%   The length by which an interval is allowed to pass beyond the limits of the chart before it `counts' as doing so
+%   and the appropriate indicator is drawn.
+% \end{describekey}
+%
+%
+% \begin{describekey}{/timechart/beyond length}{dimension}{5pt}
+%   The length of the indicator that an interval passes beyond the limits of the chart.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/beyond x radius}{dimension}{4pt}
+%   The horizontal radius of the concave part of the indicator that an interval passes beyond the limits of the chart.
+%   (The vertical radius will be half the thickness of the bar.)
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/ystep}{dimension}{-10pt}
+%   The default length (positive or negative) by which the current \(y\) coordinate is automatically adjusted after each
+%   interval, text, or space is placed.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/minor tick interval}{number}{10}
+%   The number of years (which must be positive) between each minor tick on the axis.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/major tick interval}{number}{50}
+%   The number of years (which must be positive) between each major tick on the axis and each vertical line in the grid.
+% \end{describekey}
+%
+%
+%
+% \subsection{Grid configuration}
+%
+% \begin{describekey}{/timechart/no grid}{}{}
+% Do not draw the grid.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/grid top ysep}{dimension}{3pt}
+% Distance between the top of the grid and the topmost interval or space.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/grid bottom ysep}{dimension}{3pt}
+% Distance between the bottom of the grid and the bottommost interval or space.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/grid}{style}{empty}
+% Style for drawing the grid.
+% \end{describekey}
+%
+%
+%
+% \subsection{Axis configuration}
+%
+% \begin{describekey}{/timechart/no axis}{}{}
+% Do not draw the axis.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/axis line}{style}{\keyval{line cap}{rect}}
+% Style for drawing the axis line.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/minor tick}{style}{empty}
+% Style for drawing minor ticks.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/minor tick length}{dimension}{1.5mm}
+% Length of minor ticks.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/major tick}{style}{empty}
+% Style for drawing major ticks.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/major tick length}{dimension}{3mm}
+% Length of major ticks.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/major tick label}{style}{as described below}
+%   Style for labels on the major ticks on the axis. The intial style essentially sets \keyval{inner sep}{0},
+%   \keyval{outer sep}{0}, \keyval{anchor}{mid west}, \keyval{rotate}{90}.
+% \end{describekey}
+%
+%
+%
+% \section{Within the \env{timechart} environment}
+% \label{sec:within}
+%
+%
+%
+%
+% \subsection{Intervals}
+% \label{subsec:intervals}
+%
+% \begin{function}{\timechartinterval}
+%   \begin{syntax}
+%     \cs{timechartinterval}\oarg{options}\marg{start}\marg{finish}\marg{label}
+%   \end{syntax}
+%   This command creates an interval in the chart at the current \(y\) coordinate between the specified \meta{start} and
+%   \meta{finish}, with the given \meta{label}. These arguments are mandatory. Each of \meta{start} and \meta{finish}
+%   can be either a year or a range of years, possibly with circa markers. That is, each must satisfy
+%   \meta{cyear-or-crange} in the grammar in \fullref{Section}{sec:dates-and-ranges}.
+%
+%   The optional argument \meta{options} specifies PGF keys within \key{/timechart/} that are applied locally to the
+%   interval.
+%
+%   The current \(y\) coordinate will be adjusted according to \key{/timechart/ystep} unless \key{/timechart/no
+%   autostep} has been set.
+% \end{function}
+%
+%
+%
+% \subsubsection{Interval configuration}
+%
+% \begin{describekey}{/timechart/no autostep}{}{}
+%   Do not automatically alter the current \(y\) coordinate by the amount specified in \key{/timechart/ystep}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/ref}{label}{none}
+%   Make the interval label a hyperlink to the position labelled by \meta{label}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/mark}{comma-separated list of years}{empty}
+%   Draw marks in the interval at the years contained in the list. Each entry in the list must be a definite year (that
+%   is, must satisfy \meta{year} in the grammar in \fullref{Section}{sec:dates-and-ranges}). The colour of marks can be
+%   specified using \key{/timechart/interval mark color}. \key{/timechart/marks} is a synonym for this key.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/circa uncertainty}{number}{3}
+%   Treat a circa indicator \mcode{c} as indicating an uncertainity of \(\pm\meta{number}\).
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval minimum width}{dimension}{1pt}
+%   Ensure that any interval has a width of at least \meta{dimension}. This is useful to ensure that a single event is
+%   visible in the chart.
+%
+%   If an interval is specified with start and finish ranges, and with \keyval{start range}{fade} and \keyval{finish
+%   range}{fade}, then the `certain' portion of the interval will also have width at least \meta{dimension}. (This
+%   restriction prevents a common rendering error where start and finish fadings around a `certain' interval of length
+%   \(0\) would not quite meet.)
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval bar color}{color}{black}
+%   Fill the interval bar with \meta{color}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval bar thickness}{dimension}{8pt}
+%   Set the vertical thickness of the interval bar to \meta{dimension}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval bar node name}{string}{bar node}
+%   Set the name of the node containing the interval bar to \meta{string}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval mark color}{color}{gray}
+%   Draw marks using \meta{color}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval label}{style}{empty}
+%   Style to apply to an interval label.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval label centered}{style}{as below}
+%   Style to apply to an interval label placed centrally. Initially, this style executes the style
+%   \key{/timechart/interval label} and sets \keyval{text}{white}. The reason for a separate style for centred labels is
+%   that often a contrasting colour will be required. For instance, labels positioned to the left and right may be
+%   black, but if the bar is black, a centred label should be a light colour.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval label centered background}{style}{as below}
+%   Style to apply to the `background' interval label placed centrally. Initially, this style executes
+%   \key{/timechart/interval label}. The `background' interval label is simply the usual label and is placed in the same
+%   location, but on a layer behind the bar and, unlike the label itself, is not clipped. The reason for this style is
+%   that if the bar is narrow, part of the label text (such as ascenders and/or descenders) may naturally extend beyond
+%   the bar itself and it may be useful that thse should appear in a different colour.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval label baseline}{dimension}{-3pt}
+%   Position the baseline of the interval label \meta{dimension} below the current \(y\) coordinate (which is the
+%   midpoint of the interval bar).
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval label pos}{position}{left}
+%   Specify where to place the label relative to the interval bar: \meta{position} may be \val{left}, \val{center}, or
+%   \val{right}. The position \val{center} places the label at the midpoint of \emph{the visible segment of the solid
+%   part} of the interval bar (that is, not including fading at the start or finish of the bar, and not including part
+%   of the bart that would extend beyond the bounds of the chart). Further, a centred label is clipped to the size of
+%   the bar and a unclipped `background' copy of it is drawn behind the bar, so that the portion appearing `on' and
+%   `outside' the bar can have different styles. (See the keys \key{/timechart/interval label centered} and
+%   \key{/timechart/interval label centered background}.)
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/interval label node name}{string}{label node}
+%   Set the name of the node containing the interval label to \meta{string}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/start range}{range-type}{fade}
+%   Type of indication of the range where an interval may start. \meta{range-type} can be \val{fade}, which produces an
+%   indicator like \timechartlegendstartrange[legend item width=8mm], or \val{slant}, which produces
+%   \timechartlegendstartrange[legend item width=8mm,start range=slant].
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/finish range}{range-type}{fade}
+%   Type of indication of the range where an interval may finish. \meta{range-type} can be \val{fade}, which produces an
+%   indicator like \timechartlegendfinishrange[legend item width=8mm], or \val{slant}, which produces
+%   \timechartlegendfinishrange[legend item width=8mm,finish range=slant].
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/fade minimum width}{dimension}{0pt}
+%   No start or finish range indicator of type \val{fade} will be drawn if it is smaller than \meta{dimension}. Using
+%   this key is sometimes necessary because, under certain limited circumstances, a very narrow fading can cause
+%   PGF/\TikZ\ to produce a \texttt{dimension too large} error.
+% \end{describekey}
+%
+%
+%
+% \subsection{Text}
+% \label{subsec:text}
+%
+% \begin{function}{\timecharttext}
+%   \begin{syntax}
+%     \cs{timecharttext}\oarg{options}\marg{year}\marg{text}
+%   \end{syntax}
+%   Place \meta{text} in the time chart at the current \(y\) coordinate and at the horizontal position of \meta{year},
+%   which must be a definite year (that is, must satsify \meta{year} in the grammar in
+%   \fullref{Section}{sec:dates-and-ranges}).
+%
+%   The optional argument \meta{options} specifies PGF keys within \key{/timechart/} that are applied locally.
+%
+%   The current \(y\) coordinate will be adjusted according to \key{/timechart/ystep} unless \key{/timechart/no
+%   autostep} has been set.
+% \end{function}
+%
+%
+%
+% \subsubsection{Text configuration}
+%
+% \begin{describekey}{/timechart/text node name}{string}{text node}
+%   Set the name of the node containing the text to \meta{string}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/text}{style}{empty}
+%   Style to apply to the text.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/text baseline}{dimension}{-3pt}
+%   Position the baseline of the text \meta{dimension} below the current \(y\) coordinate.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/text pos}{position}{left}
+%   Specify where to place the label relative to the given \meta{year}: \meta{position} may be \val{left}, \val{center},
+%   or \val{right}.
+% \end{describekey}
+%
+%
+%
+% \subsection{Space}
+%
+% \begin{function}{\timechartspace}
+%   \begin{syntax}
+%     \cs{timechartspace}\oarg{options}
+%   \end{syntax}
+%   Create a space in the time chart at the current \(y\) coordinate, with the same effect on vertical spacing as an
+%   interval. More precisely, the current \(y\) coordinate will be adjusted according to \key{/timechart/ystep} unless
+%   \key{/timechart/no autostep} has been set.
+%
+%   The optional argument \meta{options} specifies PGF keys within \key{/timechart/} that are applied locally.
+% \end{function}
+%
+%
+%
+% \subsection{Positioning}
+% \label{subsec:positioning}
+%
+% The commands \cs{timechartinterval}, \cs{timecharttext}, and \cs{timechartspace} all act at the current \(y\)
+% coordinate and change its value according to \key{/timechart/ystep} (unless \key{/timechart/no autostep} is used).
+% There are several functions to set the current \(y\) coordinate and to have it reset automatically.
+%
+% \begin{function}{\timechartsety}
+%   \begin{syntax}
+%     \cs{timechartsety}\marg{dimension}
+%   \end{syntax}
+%   Set the current \(y\) coordinate to \meta{dimension}.
+% \end{function}
+%
+% \begin{function}{\timechartsavey}
+%   \begin{syntax}
+%     \cs{timechartsavey}
+%   \end{syntax}
+%   Save the current \(y\) coordinate. If \cs{timechartresety} is used, the \(y\) coordinate resets to the last saved
+%   \(y\) coordinate. If the current \(y\) coordinate exceeds the minimum or maximum set by
+%   \cs{timechartsetyminimumautoreset} and \cs{timechartsetymaximumautoreset}, it will be reset to the last saved \(y\)
+%   coordinate.
+% \end{function}
+%
+% \begin{function}{\timechartresety}
+%   \begin{syntax}
+%     \cs{timechartresety}
+%   \end{syntax}
+%   Reset the \(y\) coordinate to the last coordinate saved using \cs{timechartsavey}, or to \(0\) if there has been no
+%   use of \cs{timechartsavey} within the current \env{timechart} environment.
+% \end{function}
+%
+% \begin{function}{\timechartsetyminimumautoreset, \timechartsetymaximumautoreset}
+%   \begin{syntax}
+%     \cs{timechartsetyminimumautoreset}\marg{min-coordinate}
+%     \cs{timechartsetymaximumautoreset}\marg{max-coordinate}
+%   \end{syntax}
+%   Set \(y\) coordinates that automatically trigger \cs{timechartresety} if the current \(y\) coordinate goes below
+%   \meta{min-coordinate} or above \meta{max-coordinate}.
+% \end{function}
+%
+% \begin{function}{\timechartstepy}
+%   \begin{syntax}
+%     \cs{timechartstepy}\oarg{count}
+%   \end{syntax}
+%   Manually step the current \(y\) coordinate by \meta{count} times the value of \key{/timechart/ystep}. The default
+%   value of \meta{count} is 1. (The \key{/timechart/no autostep} does not affect \cs{timechartstepy}.)
+% \end{function}
+%
+%
+%
+% \subsection{Completion}
+%
+% \begin{function}{\timechartfinish}
+%   Signal that the chart is complete and that the grid and axis should be drawn (unless the keys \key{/timechart/no
+%   grid} and/or \key{/timechart/no axis} have been used). It is not necessary to use this command: if it is not given,
+%   the grid and axis will be drawn at the end of the \env{timechart} environment. But after this command, the \TikZ\
+%   nodes \texttt{grid} and \texttt{axis} are available, containing (respectively) the grid and the axis. These can be
+%   used in for further \TikZ\ drawing.
+%
+%   Note that after \cs{timechartfinish}, none of the various \cs{timechart}\ldots\ commands are available inside that
+%   \env{timechart} environment.
+% \end{function}
+%
+%
+%
+% \subsection{Shortcut keys}
+%
+% \begin{describekey}{/timechart/left}{}{}
+%   Equivalent to setting \key{/timechart/interval label pos} and \key{/timechart/text pos} to \val{left}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/center}{}{}
+%   Equivalent to setting \key{/timechart/interval label pos} and \key{/timechart/text pos} to \val{center}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/right}{}{}
+%   Equivalent to setting \key{/timechart/interval label pos} and \key{/timechart/text pos}{right} to \val{right}.
+% \end{describekey}
+%
+%
+%
+% \section{Era indicators}
+% \label{sec:era-indicators}
+%
+% \begin{function}{\timechartmakebeforeyear,\timechartmakeafteryear}
+%   \begin{syntax}
+%     \cs{timechartmakebeforeyear}\marg{number}
+%     \cs{timechartmakeafteryear}\marg{number}
+%   \end{syntax}
+%   Typeset \meta{number} (which should be a positive whole number) as a year before or after the epoch. By default,
+%   \cs{timechartmakebeforeyear}\marg{number} produces \timechartmakebeforeyear{\meta{number}} and
+%   \cs{timechartmakeafteryear}\marg{number} produces \timechartmakeafteryear{\meta{number}}.
+%
+%   These commands are used for axis labels and can be re-defined by the user. For example, if \textsc{bc}/\textsc{ad}
+%   is preferred to \textsc{bce}/\textsc{ce}, the user can define
+% \iffalse
+%<*example>
+% \fi
+\begin{lstlisting}
+\renewcommand*{\timechartmakebeforeyear}[1]{#1~\textsc{bc}}
+\renewcommand*{\timechartmakeafteryear}[1]{\textsc{ad}~#1}
+\end{lstlisting}
+% \iffalse
+%</example>
+% \fi
+%   Similarly, if \textsc{ah}/\textsc{bh} is preferred, the user can define
+% \iffalse
+%<*example>
+% \fi
+\begin{lstlisting}
+\renewcommand*{\timechartmakebeforeyear}[1]{#1~\textsc{bh}}
+\renewcommand*{\timechartmakeafteryear}[1]{\textsc{ah}~#1}
+\end{lstlisting}
+% \iffalse
+%</example>
+% \fi
+% \end{function}
+%
+%
+%
+% \section{Legend}
+% \label{sec:keys}
+%
+% \pkg{timechart} supplies a number of auxiliary macros for creating a legend to explain, for example the significance
+% of different colours of intervals. For example, \fullref{Figure}{fig:example1-legend} shows a suitable legend for
+% \fullref{Figure}{fig:example1}.
+%
+% \begin{figure}[t]
+%   \centering
+%   \input{timechart-example1-legend.tex}
+%   \caption{Example legend for the timechart shown in \fullref{Figure}{fig:example1}.}
+%   \label{fig:example1-legend}
+% \end{figure}
+%
+% The \cs{timechartlength}\ldots\ macros are \emph{not} meant to be used inside a \env{timechart} environment, but in
+% locations such as running text or a \env{tabular} environment.
+%
+% \begin{function}{\timechartlegenditem}
+%   \begin{syntax}
+%     \cs{timechartlegenditem}\oarg{options}
+%   \end{syntax}
+%   Draw a bar suitable for use in a legend. \meta{options} specifies PGF keys that are applied within
+%   \key{/timechart}. The same PGF keys that affect interval bars affect the drawn bar, as do the keys listed below.
+% \end{function}
+%
+% \begin{function}{\timechartlegendstartrange, \timechartlegendfinishrange}
+%   \begin{syntax}
+%     \cs{timechartlegendstartrange}\oarg{options}
+%     \cs{timechartlegendfinishrange}\oarg{options}
+%   \end{syntax}
+%   Draw a bar suitable for use in a legend, with a start or finish range. \meta{options} specifies PGF keys that are
+%   applied within \key{/timechart/}. The same PGF keys that affect interval bars affect the drawn bar, as do the
+%   keys listed below.
+% \end{function}
+%
+% \begin{describekey}{/timechart/legend item width}{dimension}{9mm}
+%   When using macros \cs{timechartlegenditem}, \cs{timechartlegendstartrange}, or \cs{timechartlegendfinishrange}, draw
+%   a bar of total width \meta{dimension}.
+% \end{describekey}
+%
+% \begin{describekey}{/timechart/legend item range width}{dimension}{3mm}
+%   When using \cs{timechartlegendstartrange} or \cs{timechartlegendfinishrange}, draw a bar with a range of width
+%   \meta{dimension}.
+% \end{describekey}
+%
+%
+%
+% \section{Usage notes}
+%
+% \subsection{Additional \TikZ\ code}
+%
+% The \env{timechart} environment is a \env{tikzpicture}. The user can add any \TikZ\ code before, between, or after
+% content created using the \cs{timechart}\ldots\ commands. Each use of \cs{timechartinterval} defines two nodes. One,
+% by default named \val{bar node}, contains the interval bar; the other, by default named \val{label node}, contains the
+% interval label. Similarly, text added using \cs{timecharttext} is contained in a node, by default named \val{text
+% node}. (The default names are re-used, but can be changed using the keys \key{/timechart/interval bar node name},
+% \key{/timechart/interval label node name}, and \key{/timechart/text node name}.) The user can use these nodes to
+% position extra content.
+%
+% If the \cs{timechartcomplete} command is used (after which the \cs{timechart}\ldots\ commands are no longer available
+% within the \env{timechart} environment) the nodes \mcode{grid} and \mcode{axis}, which contain the grid and the axis,
+% are also available.
+%
+%
+%
+% \subsection{\texorpdfstring{`year zero'}{year zero}}
+%
+% Although calendars typically do not admit a `year zero' (for instance, \timechartmakebeforeyear{1} is immediately
+% followed by \timechartmakeafteryear{1}, with no intervening `year zero'), \pkg{timechart} does allow \val{0} for the
+% \meta{start} or \meta{finish} of the \env{timechart} environment or as the \meta{start} or \meta{finish} of
+% \cs{timechartinterval} or the \meta{year} of \cs{timecharttext}. But `year zero' is indicated on the axis by a special
+% epoch marker showing the last year before and first year after the epoch.
+%
+%
+%
+% \subsection{\texorpdfstring{\texttt{dimension too large}}{dimension too large} error}
+%
+% Under certain limited circumstances, a very narrow fading can cause PGF/\TikZ\ to produce a \texttt{dimension too
+% large} error. This error can be triggered by a range of type \val{fade} at the start or end of an interval when the
+% range is small compared to the width of the chart. In this case, the fading is unlikely to be visible, so one can
+% simply set \key{/timechart/fade minimum width} to a suitable small positive value, which will stop the fading from
+% being drawn and so prevent the error.
+%
+%
+%
+% \section{Appendix: full example source}
+% \label{sec:full-example}
+%
+% This section contains the necessary source code to produce the example timechart and legend shown in
+% \fullref{Figures}{fig:example1} and \ref{fig:example1-legend} on pages \pageref{fig:example1} and
+% \pageref{fig:example1-legend}.
+%
+%
+%
+% \subsection{Setup source}
+%
+% \lstinputlisting{timechart-example1-setup.tex}
+%
+%
+%
+% \subsection{Timechart source}
+%
+% \lstinputlisting[breaklines=true]{timechart-example1-timechart.tex}
+%
+%
+%
+% \subsection{Legend source}
+%
+% \lstinputlisting{timechart-example1-legend.tex}
+%
+%
+%
+% \end{documentation}
+%
+%
+%
+% \begin{implementation}
+%
+% \setcounter{secnumdepth}{7}
+%
+%
+%
+% \section{Implementation}
+%
+%    \begin{macrocode}
+%<*package>
+%<@@=timechart>
+%    \end{macrocode}
+%
+%
+%
+% \subsection{Coding standard}
+%
+% This package makes extensive use of \pkg{pgfmath} computations. The usual \pkg{expl3} standard of ending variables
+% with a type indicator (\texttt{\_bool}, \texttt{\_int}, etc.) is therefore adapted as follows:
+% \begin{itemize}
+%   \item[\texttt{\_year}] Stores a year, which could in principle be fractional.
+%     \item[\texttt{\_pgf}] Stores a length calculated by \pkg{pgfmath}. (Unlike \texttt{\_dim}, there is no underlying
+%           dimension register.)
+%   \item[\texttt{\_x}] Stores a raw \(x\) coordinate (not in \TikZ's XY-coordinate system).
+%   \item[\texttt{\_y}] Stores a raw \(y\) coordinate (not in \TikZ's XY-coordinate system).
+%   \item[\texttt{\_text}] Stores text (not an \pkg{expl3} string).
+% \end{itemize}
+%
+%
+%
+% \subsection{Initial set-up}
+%
+% Package identification/version information.
+%    \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}[2020-02-02]
+\ProvidesExplPackage{timechart}{2025-02-15}{0.51}
+  {Typesetting chronological charts}
+%    \end{macrocode}
+%
+%
+%
+% \subsection{Load TikZ}
+%
+%    \begin{macrocode}
+\RequirePackage{tikz}
+%    \end{macrocode}
+% In the remainder of the package, only a limited subset of \TikZ\ is used, and PGF code is preferred. For PGF keys, it
+% is necessary to use \texttt{\textasciitilde} in place of a space.
+%
+%
+%
+% \subsection{Scratch variables}
+%
+% \begin{macro}{\l_@@_tmpa_bool,\l_@@_tmpb_bool,\l_@@_tmpc_bool,\l_@@_tmpd_bool}
+%   Scratch boolean variables.
+%    \begin{macrocode}
+\bool_new:N\l_@@_tmpa_bool
+\bool_new:N\l_@@_tmpb_bool
+\bool_new:N\l_@@_tmpc_bool
+\bool_new:N\l_@@_tmpd_bool
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_tmpa_dim,\l_@@_tmpb_dim,\l_@@_tmpc_dim,\l_@@_tmpd_dim}
+%   Scratch dimension variables, reusing \cs{l_tmpa_dim} and \cs{l_tmpb_dim} with uniform names.
+%    \begin{macrocode}
+\cs_set_eq:NN\l_@@_tmpa_dim\l_tmpa_dim
+\cs_set_eq:NN\l_@@_tmpb_dim\l_tmpb_dim
+\dim_new:N\l_@@_tmpc_dim
+\dim_new:N\l_@@_tmpd_dim
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Generic auxiliary functions}
+%
+% \begin{macro}{\@@_make_ref:NN}
+%   Make hyperreference from text, if the supplied target is non-empty.
+%   \begin{arguments}
+%     \item Reference for hyperlink target, or empty.
+%     \item Text.
+%   \end{arguments}
+%    \begin{macrocode}
+\cs_new:Npn\@@_make_ref:NN #1#2
+  {
+    \str_if_empty:NTF #1
+      { #2 }
+      { \hyperref[#1]{#2} }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{PGF auxiliary functions}
+%
+% \begin{macro}{@@_pgfmathsetbool:nn}
+%   Set an \pkg{expl3} boolean variable to the outcome of a \pkg{pgfmath} comparison. This macro is simply a wrapper
+%   around \cs{pgfmathsetmacro} using \mcode{ifthenelse} and returning the boolean literal true or false.
+%    \begin{macrocode}
+\cs_new:Npn\@@_pgfmathsetbool:nn #1#2
+  {
+    \pgfmathsetmacro{#1}{ifthenelse(#2,"\c_true_bool","\c_false_bool")}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_equal:nnF}%
+%   Use \pkg{pgfmath} to check whether \param{1} and \param{2} are equal. If not, execute \param{3}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_if_equal:nnF #1#2#3
+  {
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{#1==#2}
+    \bool_if:NF\l_@@_tmpa_bool{#3}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_pgfextractxy:nnn}
+%   Extract coordinates of \param{3} (a PGF point) to dimension variables \param{1} and \param{2}. This macro simply
+%   combines the functionality of \cs{pgfextractx} and \cs{pgfextracty}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_pgfextractxy:nnn #1#2#3
+  {
+    \pgf at process{#3}
+    #1=\pgf at x\relax
+    #2=\pgf at y\relax
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_hsmash_pgfnode:nnnnn}
+%   Do the same as \cs{pgfnode} but only update the bounding box `vertically'.
+%    \begin{macrocode}
+\cs_new:Npn\@@_hsmash_pgfnode:nnnnn #1#2#3#4#5
+  {
+    \pgfinterruptboundingbox
+    \pgfnode{#1}{#2}{#3}{#4}{#5}
+    \pgfcoordinate
+      {@@_tmpa_coord}
+      {\pgfpointanchor{current~bounding~box}{south}}
+    \pgfcoordinate
+      {@@_tmpb_coord}
+      {\pgfpointanchor{current~bounding~box}{north}}
+    \endpgfinterruptboundingbox
+    \pgfextractx
+      {\l_@@_tmpa_dim}
+      {\pgfpointanchor{@@_tmpa_coord}{center}}
+    \pgfextractx
+      {\l_@@_tmpb_dim}
+      {\pgfpointanchor{@@_tmpb_coord}{center}}
+    \pgfpathmoveto{\pgfpoint{\l_@@_tmpa_dim}{0}}
+    \pgfpathmoveto{\pgfpoint{\l_@@_tmpb_dim}{0}}
+    \pgfusepath{discard}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_make_rectangle_node:nnnn}
+%   Make a node with south west corner \param{1}, north east corner \param{2}, and name \param{3}. \param{1} and
+%   \param{2} should be given as PGF points. \param{4} is a boolean literal indicating whether the path should be
+%   stroked.
+%    \begin{macrocode}
+\cs_new:Npn\@@_make_rectangle_node:nnnn #1#2#3#4
+  {
+    \group_begin:
+    \@@_pgfextractxy:nnn
+      {\l_@@_tmpa_dim}{\l_@@_tmpb_dim}{#1}
+    \@@_pgfextractxy:nnn
+      {\l_@@_tmpc_dim}{\l_@@_tmpd_dim}{#2}
+    \pgftransformshift{#1}
+    \pgfset{
+      minimum~width=\l_@@_tmpc_dim-\l_@@_tmpa_dim,
+      minimum~height=\l_@@_tmpd_dim-\l_@@_tmpb_dim,
+      inner~sep=0,
+      outer~sep=0,
+    }
+    \bool_if:NTF #4
+      { \pgfnode{rectangle}{south~west}{}{#3}{\pgfusepath{draw}} }
+      { \pgfnode{rectangle}{south~west}{}{#3}{\pgfusepath{discard}} }
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_left_nonclip_x,\l_@@_right_nonclip_x}
+%   In order to clip `only on one side', define coordinates for specifying the `other side' of the clipping path.
+%    \begin{macrocode}
+\pgfmathsetmacro{\l_@@_left_nonclip_x}{-16000pt}
+\pgfmathsetmacro{\l_@@_right_nonclip_x}{16000pt}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_style_line_width:nn}
+%   Set macro \param{1} to be the line width set by the PGF style \param{2}. Note that \cs{begingroup} and \cs{endgroup}
+%   are used here because of the definition of \cs{pgfmathsmuggle}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_set_style_line_width:nn #1#2
+  {
+    \begingroup
+    \tikzset{#2}
+    \pgfmathsetlengthmacro{#1}{\pgflinewidth}
+    \pgfmathsmuggle #1
+    \endgroup
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{PGF keys}
+%
+% All PGF keys for this package are under \key{/timechart/}.
+%    \begin{macrocode}
+\pgfkeys{
+  /timechart/.cd,
+%    \end{macrocode}
+% Keys applicable to whole chart.
+%    \begin{macrocode}
+  width/.initial=\textwidth,
+  tolerance/.initial=5pt,
+  beyond~length/.initial=5pt,
+  beyond~x~radius/.initial=4pt,
+  ystep/.initial=-10pt,
+  minor~tick~interval/.initial=10,
+  major~tick~interval/.initial=50,
+%    \end{macrocode}
+% Keys applicable to the grid.
+%    \begin{macrocode}
+  no~grid/.code = { \bool_set_false:N\l_@@_grid_bool },
+  grid~top~ysep/.initial={3pt},
+  grid~bottom~ysep/.initial={3pt},
+  grid/.style={},
+%    \end{macrocode}
+% Keys applicable to the axis.
+%    \begin{macrocode}
+  no~axis/.code = { \bool_set_false:N\l_@@_axis_bool },
+  axis~line/.style={
+    line~cap=rect,
+  },
+  axis~ysep/.initial=3pt,
+  minor~tick/.style={},
+  minor~tick~length/.initial=1.5mm,
+  major~tick/.style={},
+  major~tick~length/.initial=3mm,
+  major~tick~label/.style={
+    inner~sep=0,
+    outer~sep=0,
+    anchor=mid~west,
+    rotate=90,
+  },
+%    \end{macrocode}
+% Keys applicable to intervals, texts, spaces, and legends.
+%    \begin{macrocode}
+  no~autostep/.code = { \bool_set_false:Nz\l_@@_autostep_bool },
+  ref/.initial={},
+  mark/.initial={},
+  marks/.forward~to=/timechart/mark,
+  circa~uncertainty/.initial=3,
+  interval~minimum~width/.initial=1pt,
+  interval~bar~color/.initial=black,
+  interval~bar~thickness/.initial=8pt,
+  interval~bar~node~name/.initial = {bar~node},
+  interval~mark~color/.initial=gray,
+  interval~label/.style={},
+  interval~label~centered/.style={/timechart/interval~label,text=white},
+  interval~label~centered~background/.style={/timechart/interval~label},
+  interval~label~baseline/.initial=-3pt,
+  interval~label~pos/.is~choice,
+  interval~label~pos/left/.code
+    = { \int_set:Nn\l_@@_label_pos_int{0} },
+  interval~label~pos/center/.code
+    = { \int_set:Nn\l_@@_label_pos_int{1} },
+  interval~label~pos/right/.code
+    = { \int_set:Nn\l_@@_label_pos_int{2} },
+  interval~label~node~name/.initial = {label~node},
+  start~range/.is~choice,
+  start~range/fade/.code
+    = { \int_set:Nn\l_@@_start_range_type_int{0} },
+  start~range/slant/.code
+    = { \int_set:Nn\l_@@_start_range_type_int{1} },
+  finish~range/.is~choice,
+  finish~range/fade/.code
+    = { \int_set:Nn\l_@@_finish_range_type_int{0} },
+  finish~range/slant/.code
+    = { \int_set:Nn\l_@@_finish_range_type_int{1} },
+  fade~minimum~width/.initial = 0pt,
+%    \end{macrocode}
+% Keys applicable only to texts.
+%    \begin{macrocode}
+  text~node~name/.initial = {text~node},
+  text/.style={},
+  text~baseline/.initial=-3pt,
+  text~pos/.is~choice,
+  text~pos/left/.code = { \int_set:Nn\l_@@_text_pos_int{0} },
+  text~pos/center/.code = { \int_set:Nn\l_@@_text_pos_int{1} },
+  text~pos/right/.code = { \int_set:Nn\l_@@_text_pos_int{2} },
+%    \end{macrocode}
+% Keys applicable only to legends.
+%    \begin{macrocode}
+  legend~item~width/.initial=9mm,
+  legend~item~range~width/.initial=3mm,
+%    \end{macrocode}
+% Shortcuts for positioning.
+%    \begin{macrocode}
+  left/.code = {
+    \int_set:Nn\l_@@_label_pos_int{0}
+    \int_set:Nn\l_@@_text_pos_int{0}
+  },
+  center/.code = {
+    \int_set:Nn\l_@@_label_pos_int{1}
+    \int_set:Nn\l_@@_text_pos_int{1}
+  },
+  right/.code = {
+    \int_set:Nn\l_@@_label_pos_int{2}
+    \int_set:Nn\l_@@_text_pos_int{2}
+  },
+}
+%    \end{macrocode}
+%
+% \begin{macro}{\l_@@_grid_bool}
+%   Boolean indicating whether the grid will be drawn. This variable is by default true but can be set false via the
+%   \key{/timechart/no grid} PGF key.
+%    \begin{macrocode}
+\bool_new:N\l_@@_grid_bool
+\bool_set_true:N\l_@@_grid_bool
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_axis_bool}
+%   Boolean indicating whether the axis will be drawn. This variable is by default true but can be set false via the
+%   \key{/timechart/no axis} PGF key.
+%    \begin{macrocode}
+\bool_new:N\l_@@_axis_bool
+\bool_set_true:N\l_@@_axis_bool
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_autostep_bool}
+%   Boolean indicating whether to automatically step the \(y\) coordinate after an interval, text, or space. This
+%   variable is by default true but can be set false via the \key{/timechart/no autostep} PGF key.
+%    \begin{macrocode}
+\bool_new:N\l_@@_autostep_bool
+\bool_set_true:N\l_@@_autostep_bool
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_label_pos_int}
+%   An integer to hold the interval label position. This is set via the \key{/timechart/interval label pos} PGF key.
+%    \begin{macrocode}
+\int_new:N \l_@@_label_pos_int
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_text_pos_int}
+%   An integer to hold the text position. This is set via the \key{/timechart/text pos} PGF key.
+%    \begin{macrocode}
+\int_new:N \l_@@_text_pos_int
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\l_@@_start_range_type_int,\l_@@_finish_range_type_int}
+%   Integers to hold the type of the start/end ranges. These are set via the \key{/timechart/start range} and
+%   \key{/timechart/finish range} PGF keys.
+%    \begin{macrocode}
+\int_new:N \l_@@_start_range_type_int
+\int_new:N \l_@@_finish_range_type_int
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Main environment}
+%
+% \begin{macro}{timechart}
+%   The main environment.
+%   \begin{arguments}
+%     \item PGF keys to apply.
+%     \item Start year.
+%     \item End year.
+%   \end{arguments}
+%    \begin{macrocode}
+\NewDocumentEnvironment{timechart}{ O{} m m }
+  { \@@_main_begin:nnn{#1}{#2}{#3} }
+  { \@@_main_end: }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_main_begin:nnn}
+%   This command uses values specified by PGF keys to make some necessary calculations to begin the chart.
+%    \begin{macrocode}
+\cs_new:Npn \@@_main_begin:nnn #1#2#3
+  {
+%    \end{macrocode}
+%   Process the supplied PGF keys and retrieve values that affect the chart as a whole.
+%    \begin{macrocode}
+    \pgfkeys{
+      /timechart/.cd,
+      #1,
+      width/.get=\l_@@_width_pgf,
+      tolerance/.get=\l_@@_tolerance_pgf,
+      ystep/.get=\l_@@_ystep_pgf,
+      grid~top~ysep/.get=\l_@@_grid_top_ysep_pgf,
+      grid~bottom~ysep/.get=\l_@@_grid_bottom_ysep_pgf,
+      beyond~length/.get=\l_@@_beyond_length_pgf,
+      beyond~x~radius/.get=\l_@@_beyond_x_radius_pgf,
+      minor~tick~interval/.get=\l_@@_minor_tick_interval_year,
+      major~tick~interval/.get=\l_@@_major_tick_interval_year,
+    }
+%    \end{macrocode}
+%   Start the \TikZ\ picture and set up the necessary layers.
+%    \begin{macrocode}
+    \tikzpicture
+    \pgfdeclarelayer{grid}
+    \pgfdeclarelayer{labelbg}
+    \pgfsetlayers{grid,labelbg,main}
+%    \end{macrocode}
+%   Store the line width of the grid and axis, treating them as \qty{0}{\point} if they are disabled.
+%    \begin{macrocode}
+    \bool_if:NTF\l_@@_grid_bool
+      {
+        \@@_set_style_line_width:nn
+          {\l_@@_grid_line_width}
+          {/timechart/grid}
+      }
+      { \pgfmathsetlengthmacro{\l_@@_grid_line_width}{0} }
+    \bool_if:NTF\l_@@_axis_bool
+      {
+        \@@_set_style_line_width:nn
+          {\l_@@_axis_line_width}
+          {/timechart/axis~line}
+        \@@_set_style_line_width:nn
+          {\l_@@_major_tick_line_width}
+          {/timechart/major~tick}
+        \@@_set_style_line_width:nn
+          {\l_@@_minor_tick_line_width}
+          {/timechart/minor~tick}
+      }
+      {
+        \pgfmathsetlengthmacro{\l_@@_axis_line_width}{0}
+        \pgfmathsetlengthmacro{\l_@@_major_tick_line_width}{0}
+        \pgfmathsetlengthmacro{\l_@@_minor_tick_line_width}{0}
+      }
+%    \end{macrocode}
+%   Store the start and finish years (ignoring circa, month, day), and then set up the conversion from years to \(x\)
+%   coordinates. \cs{l_@@_x} is the \(x\)-distance corresponding to one year, and \mcode{yeartox} is the \pkg{pgfmath}
+%   function that does the conversion.
+%    \begin{macrocode}
+    \@@_parse_date:NNn\l_tmpa_bool\l_@@_start_year{#2}
+    \@@_parse_date:NNn\l_tmpa_bool\l_@@_finish_year{#3}
+    \pgfmathsetmacro{\l_@@_start_year}
+      {floor(\l_@@_start_year)}
+    \pgfmathsetmacro{\l_@@_finish_year}
+      {floor(\l_@@_finish_year)}
+    \pgfmathsetmacro{\l_@@_x}
+      {
+        (
+          \l_@@_width_pgf
+          - max(
+            \l_@@_grid_line_width,
+            \l_@@_axis_line_width,
+            \l_@@_major_tick_line_width,
+            \l_@@_minor_tick_line_width
+          )
+        )/(\l_@@_finish_year-\l_@@_start_year)
+      }
+    \pgfkeys{
+      /pgf/declare~function={
+        yeartox(\n)=\l_@@_x*(\n-\l_@@_start_year);
+      },
+    }
+%    \end{macrocode}
+% Calculate the start and finish \(x\) coordinates.
+%    \begin{macrocode}
+    \pgfmathsetmacro{\l_@@_start_x}
+      {yeartox(\l_@@_start_year)}
+    \pgfmathsetmacro{\l_@@_finish_x}
+      {yeartox(\l_@@_finish_year)}
+    \pgfmathsetmacro{\l_@@_start_tolerance_x}{
+      \l_@@_start_x-(\l_@@_tolerance_pgf)
+    }
+    \pgfmathsetmacro{\l_@@_finish_tolerance_x}{
+      \l_@@_finish_x+(\l_@@_tolerance_pgf)
+    }
+    \pgfmathsetmacro{\l_@@_start_beyond_x}{
+      \l_@@_start_x-(\l_@@_beyond_length_pgf)
+    }
+    \pgfmathsetmacro{\l_@@_finish_beyond_x}{
+      \l_@@_finish_x+(\l_@@_beyond_length_pgf)
+    }
+%    \end{macrocode}
+% Set up tracking of current \(y\) coordinate.
+%    \begin{macrocode}
+    \pgfmathsetmacro{\l_@@_current_y}{0}
+    \pgfmathsetmacro{\l_@@_saved_y}{0}
+    \pgfmathsetmacro{\l_@@_auto_reset_minimum_y}{-16000pt}
+    \pgfmathsetmacro{\l_@@_auto_reset_maximum_y}{16000pt}
+%    \end{macrocode}
+% Calculate some years used in loops.
+%    \begin{macrocode}
+    \pgfmathsetmacro{\l_@@_start_plus_year}{
+      \l_@@_start_year+\l_@@_minor_tick_interval_year
+    }
+    \pgfmathsetmacro{\l_@@_start_plusplus_year}{
+      \l_@@_start_year+(2*\l_@@_minor_tick_interval_year)
+    }
+    \pgfmathsetmacro{\l_@@_end_minus_year}{
+      \l_@@_finish_year-\l_@@_minor_tick_interval_year
+    }
+%    \end{macrocode}
+%   Begin a group and make available the user commands \cs{timechart}\ldots. (The group will be ended by
+%   \cs{@@_main_end_user:}.)
+%    \begin{macrocode}
+    \group_begin:
+    \cs_set_eq:NN\timechartinterval\@@_interval_user:Ommm
+    \cs_set_eq:NN\timecharttext\@@_text_user:Omm
+    \cs_set_eq:NN\timechartspace\@@_space_user:O
+    \cs_set_eq:NN\timechartsety\@@_set_y_user:m
+    \cs_set_eq:NN\timechartsavey\@@_save_y_user:
+    \cs_set_eq:NN\timechartresety\@@_reset_y_user:
+    \cs_set_eq:NN\timechartsetyminimumautoreset
+      \@@_set_y_minimum_auto_reset_user:m
+    \cs_set_eq:NN\timechartsetymaximumautoreset
+      \@@_set_y_maximum_auto_reset_user:m
+    \cs_set_eq:NN\timechartstepy\@@_step_y_user:O
+    \cs_set_eq:NN\timechartfinish\@@_main_end_user:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_main_end:}
+%   Make sure the chart is complete and end the \TikZ\ picture. \cs{@@_main_end_user:} ends the group begun by
+%   \cs{@@_main_begin:nnn}, so whether the user has \emph{not} called it (as \cs{timechartfinish}) is equivalent to it
+%   being equal to \cs{timechartfinish}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_main_end:
+  {
+    \cs_if_eq:NNT\timechartfinish\@@_main_end_user:
+      { \@@_main_end_user: }
+    \endtikzpicture
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_main_end_user:}
+%   End the group begun by \cs{@@_main_begin:nnn}, draw the axis and grid, and set the bounding box. This macro is made
+%   available as \cs{timechartfinish} inside the \env{timechart} environment.
+%    \begin{macrocode}
+\cs_new:Npn\@@_main_end_user:
+  {
+%    \end{macrocode}
+%   The aim here is to set the bounding box (1) to fit horizontally the axis \emph{not} including labels and the grid
+%   and (2) to fit vertically the axis including labels and the grid . All the `horizonatal' data is already known, and
+%   the `vertical' data is determined by the \emph{current} bounding box. So extract the `vertical' data and then reset
+%   the bounding box.
+%    \begin{macrocode}
+    \pgfextracty{\l_@@_tmpa_dim}
+      { \pgfpointanchor{current~bounding~box}{south} }
+    \pgfextracty{\l_@@_tmpb_dim}
+      { \pgfpointanchor{current~bounding~box}{north} }
+    \pgfresetboundingbox
+%    \end{macrocode}
+%   If the timechart is empty, then the extracted \(y\) coordinates of `north' and `south' anchors of the bounding box
+%   will be \qty{-16000}{\point} and \qty{16000}{\point} respectively. Test for this and treat them as both having \(y\)
+%   coordinate \qty{0}{\point} in this case.
+%    \begin{macrocode}
+    \dim_compare:nNnTF{\l_@@_tmpa_dim}>{\l_@@_tmpb_dim}
+      {
+        \pgfmathsetmacro{\l_@@_content_bottom_y}{0pt}
+        \pgfmathsetmacro{\l_@@_content_top_y}{0pt}
+      }
+      {
+        \pgfmathsetmacro{\l_@@_content_bottom_y}
+          {\l_@@_tmpa_dim}
+        \pgfmathsetmacro{\l_@@_content_top_y}
+          {\l_@@_tmpb_dim}
+      }
+%    \end{macrocode}
+%   Now draw the grid and axis if necessary and set the bounding box if not.
+%    \begin{macrocode}
+    \bool_if:NTF{\l_@@_grid_bool}
+      {
+        \@@_grid_draw:
+        \pgfmathsetmacro{\l_@@_axis_y}
+          {
+            \l_@@_content_top_y
+            + \l_@@_grid_top_ysep_pgf
+            + \pgfkeysvalueof{/timechart/axis~ysep}
+          }
+      }
+      {
+        \@@_nogrid_bounding_box_set:
+        \pgfmathsetmacro{\l_@@_axis_y}
+          {
+            \l_@@_content_top_y
+            +\pgfkeysvalueof{/timechart/axis~ysep}
+          }
+      }
+    \bool_if:NT{\l_@@_axis_bool}
+      { \@@_axis_draw: }
+%    \end{macrocode}
+%   Finally, end the group begun by \cs{@@_main_begin:nnn}.
+%    \begin{macrocode}
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Grid drawing}
+%
+% \begin{macro}{\@@_grid_draw:}
+%   Draw the grid of the chart, assuming that the \(y\) coordinates of the top and bottom of the content have
+%   been calculated and stored in \cs{l_@@_content_top_y} and \cs{l_@@_content_bottom_y}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_grid_draw:
+  {
+    \pgfmathsetmacro{\l_@@_grid_bottom_y}{
+      \l_@@_content_bottom_y-\l_@@_grid_bottom_ysep_pgf
+    }
+    \pgfmathsetmacro{\l_@@_grid_top_y}{
+      \l_@@_content_top_y+\l_@@_grid_top_ysep_pgf
+    }
+    \pgfonlayer{ grid }
+    \scope[/timechart/grid]
+    \foreach \year in {
+      \l_@@_start_plus_year,
+      \l_@@_start_plusplus_year,
+      ...,
+      \l_@@_end_minus_year
+    } {
+      \group_begin:
+%    \end{macrocode}
+%   Only draw gridlines at major ticks.
+%    \begin{macrocode}
+      \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+        { Mod(\year,\l_@@_major_tick_interval_year)==0 }
+      \bool_if:NT\l_@@_tmpa_bool
+        {
+          \pgftransformshift{ \pgfpoint{yeartox(\year)}{0} }
+          \pgfpathmoveto{ \pgfpoint{0}{\l_@@_grid_top_y} }
+          \pgfpathlineto{ \pgfpoint{0}{\l_@@_grid_bottom_y} }
+          \pgfusepath{ draw }
+        }
+      \group_end:
+    }
+%    \end{macrocode}
+%   Define and draw the grid node.
+%    \begin{macrocode}
+    \@@_make_rectangle_node:nnnn
+      { \pgfpoint{\l_@@_start_x}{\l_@@_grid_bottom_y} }
+      { \pgfpoint{\l_@@_finish_x}{\l_@@_grid_top_y} }
+      { grid }
+      { \c_true_bool }
+    \endscope
+    \endpgfonlayer
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Axis drawing}
+%
+% \begin{macro}{\@@_axis_draw:}
+%   Draw the axis, with large/small ticks and labels on appropriate years, assuming that the \(y\) coordinate has been
+%   calculated and stored in \cs{l_@@_axis_y}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_axis_draw:
+  {
+    \group_begin:
+    \pgfkeys{
+      /timechart/minor~tick~length/.get=\@@_minor_tick_length_pgf,
+      /timechart/major~tick~length/.get=\@@_major_tick_length_pgf,
+    }
+%    \end{macrocode}
+% Shift to the \(y\) coordinate of the axis line.
+%    \begin{macrocode}
+    \pgftransformshift{ \pgfpoint{0}{\l_@@_axis_y} }
+%    \end{macrocode}
+% Work out the first and last years which will have a major tick (since these are marked with the era).
+%    \begin{macrocode}
+    \pgfmathsetmacro{\@@_start_major_tick_year}
+      {
+        \l_@@_start_year
+        -Mod(
+          \l_@@_start_year,
+          \l_@@_major_tick_interval_year
+        )
+      }
+    \pgfmathsetmacro{\@@_start_major_tick_year}
+      {
+        ifthenelse(
+          \@@_start_major_tick_year<\l_@@_start_year,
+          \@@_start_major_tick_year
+            +\l_@@_major_tick_interval_year,
+          \@@_start_major_tick_year
+        )
+      }
+    \pgfmathsetmacro{\@@_finish_major_tick_year}
+      {
+        \l_@@_finish_year
+        -Mod(
+          \l_@@_finish_year,
+          \l_@@_major_tick_interval_year
+        )
+      }
+%    \end{macrocode}
+% Loop over years and draw the appropriate ticks.
+%    \begin{macrocode}
+    \foreach \year in {
+      \l_@@_start_year,
+      \l_@@_start_plus_year,
+      ...,
+      \l_@@_finish_year
+    } {
+      \pgfmathsetmacro{\x}{yeartox(\year)}
+      \@@_pgfmathsetbool:nn
+        {\l_@@_tmpa_bool}
+        { Mod(\year,\l_@@_major_tick_interval_year)==0 }
+      \bool_if:NTF\l_@@_tmpa_bool
+        { \@@_axis_draw_labelled_major_tick:NN\x\year }
+        { \@@_axis_draw_minor_tick:N\x }
+    }
+    \@@_draw_axis_line
+%    \end{macrocode}
+% Define the axis node.
+%    \begin{macrocode}
+    \pgfextracty{\l_@@_tmpa_dim}
+      { \pgfpointanchor{current~bounding~box}{north} }
+    \@@_make_rectangle_node:nnnn
+      { \pgfpoint{\l_@@_start_x}{0} }
+      { \pgfpoint{\l_@@_finish_x}{\l_@@_tmpa_dim} }
+      { axis }
+      { \c_false_bool }
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% All the remaining axis-related macros (which begin \cs{@@_axis_draw_}) assume that a transformation has been applied
+% so that the axis line is at \(y=0\).
+%
+% \begin{macro}{\@@_axis_draw_minor_tick:N}
+%  Draw an unlabelled tick at \(x\) coordinate \param{1}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_axis_draw_minor_tick:N #1
+  {
+    \scope[/timechart/minor~tick]
+    \pgfpathmoveto{ \pgfpoint{#1}{0} }
+    \pgfpathlineto{ \pgfpoint{#1}{\@@_minor_tick_length_pgf} }
+    \pgfusepath{draw}
+    \endscope
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_axis_draw_labelled_major_tick:NN}
+%   Draw a labelled major tick at \(x\) coordinate \param{1}, with label for year \param{2}, using the special epoch
+%   marker if the year is 0, and showing the era if and only if the year is for the first or last major tick. This macro
+%   assumes that \cs{@@_start_major_tick_year} and \cs{@@_finish_major_tick_year} have been calculated.
+%    \begin{macrocode}
+\cs_new:Npn\@@_axis_draw_labelled_major_tick:NN #1#2
+  {
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{#2==0}
+    \bool_if:NTF \l_@@_tmpa_bool
+      { \@@_axis_draw_zero_tick:N #1 }
+      {
+        \@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
+          { #2==\@@_start_major_tick_year }
+        \@@_pgfmathsetbool:nn{\l_@@_tmpc_bool}
+          { #2==\@@_finish_major_tick_year }
+        \bool_set:Nn\l_@@_tmpd_bool
+          { \l_@@_tmpb_bool || \l_@@_tmpc_bool }
+        \@@_axis_draw_major_tick:N #1
+        \@@_axis_draw_year_label:nnnnnn
+          { #1 }
+          { #2 }
+          { \l_@@_tmpd_bool }
+          { mid~west }
+          { 0 }
+          { \@@_major_tick_length_pgf+1mm }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_axis_draw_major_tick:N}
+%  Draw a major tick at \(x\) coordinate \param{1}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_axis_draw_major_tick:N #1
+  {
+    \scope[/timechart/major~tick]
+    \pgfpathmoveto{ \pgfpoint{#1}{0} }
+    \pgfpathlineto{ \pgfpoint{#1}{\@@_major_tick_length_pgf} }
+    \pgfusepath{draw}
+    \endscope
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_axis_draw_zero_tick:N}
+%  Draw a special (labelled) tick for year zero at \(x=\param{1}\).
+%    \begin{macrocode}
+\cs_new:Npn\@@_axis_draw_zero_tick:N #1
+  {
+    \group_begin:
+    \pgftransformshift{ \pgfpoint{#1}{0} }
+%    \end{macrocode}
+%   The mark is a cross made up of four arcs and the miter joins between them. The parameter \cs{r} is the arc radius.
+%   The parameter \cs{a} is how many degrees should be trimmed from the start/end of a quarter-circle to form each arc.
+%   Thus the length of the miter is dependent on \cs{a}.
+%    \begin{macrocode}
+    \pgfmathsetmacro{\a}{5}
+    \pgfmathsetlengthmacro{\r}{1mm}
+    \pgfmathsetlengthmacro{\t}{\r*(cos(\a)-cos(90-\a))/(1-cos(90-\a))}
+%    \end{macrocode}
+%   The drawing process is: move to the start of the tick, draw the tick, draw the four arcs, then draw a small part of
+%   the tick again. The last step is not mathematically necessary for a smooth join, but ensures that the join
+%   \emph{appears} smooth.
+%    \begin{macrocode}
+    \scope[/timechart/major~tick,line~join=miter]
+    \pgfpathmoveto{\pgfpointorigin}
+    \pgfpathlineto{\pgfpoint{0}{\@@_major_tick_length_pgf}}
+    \pgfpatharc{0}{90-\a}{\t~and~\r}
+    \pgfpatharc{270+\a}{360-\a}{\r}
+    \pgfpatharc{180+\a}{270-\a}{\r}
+    \pgfpatharc{90+\a}{180-\a}{\t~and~\r}
+    \pgfpathlineto{\pgfpoint{0}{\@@_major_tick_length_pgf-1pt}}
+    \pgfusepath{draw}
+    \endscope
+%    \end{macrocode}
+%   There is no year 0, so label the zero mark with the 1 before and 1 after the epoch.
+%    \begin{macrocode}
+    \@@_axis_draw_year_label:nnnnnn
+      { 0 }
+      { -1 }
+      { \c_true_bool }
+      { base~west }
+      { -.5mm }
+      { 5.5mm }
+    \@@_axis_draw_year_label:nnnnnn
+      { 0 }
+      { 1 }
+      { \c_true_bool }
+      { north~west }
+      { .5mm }
+      { 5.5mm }
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_axis_draw_line}
+%   Draw the axis line itself.
+%    \begin{macrocode}
+\cs_new:Npn\@@_draw_axis_line
+  {
+    \scope[/timechart/axis~line]
+    \pgfpathmoveto{ \pgfpoint{\l_@@_start_x}{0} }
+    \pgfpathlineto{ \pgfpoint{\l_@@_finish_x}{0} }
+    \pgfusepath{draw}
+    \endscope
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_axis_draw_year_label:nnnnnn}
+%  Draw a year label.
+%   \begin{arguments}
+%     \item \(x\) coordinate.
+%     \item Year for label.
+%     \item Boolean literal indicating whether the era should be shown.
+%     \item Anchor for node.
+%     \item \(x\) offset (dimension).
+%     \item \(y\) offset (dimension).
+%   \end{arguments}
+%    \begin{macrocode}
+\cs_new:Npn\@@_axis_draw_year_label:nnnnnn #1#2#3#4#5#6
+  {
+    \group_begin:
+    \pgftransformshift{ \pgfpoint{#1+#5}{#6} }
+    \pgfmathtruncatemacro{\absyear}{ abs(#2) }
+    \scope[/timechart/major~tick~label]
+    \bool_if:NTF #3
+      {
+        \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{#2<0}
+        \bool_if:NTF\l_@@_tmpa_bool
+          { \cs_set_eq:NN\@@_make_year:n\timechartmakebeforeyear }
+          { \cs_set_eq:NN\@@_make_year:n\timechartmakeafteryear  }
+        \@@_hsmash_pgfnode:nnnnn
+          {rectangle}
+          {#4}
+          {\@@_make_year:n{\absyear}}
+          {}
+          {}
+      }
+      { \pgfnode{rectangle}{#4}{\absyear}{}{} }
+    \endscope
+    \group_end:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\timechartmakebeforeyear,\timechartmakeafteryear}
+%   User-redefineable macros to format a year as before or after the epoch.
+%    \begin{macrocode}
+\cs_new:Npn\timechartmakebeforeyear #1
+  {
+    #1\nobreakspace\textsc{bce}
+  }
+\cs_new:Npn\timechartmakeafteryear #1
+  {
+    #1\nobreakspace\textsc{ce}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Bounding box}
+%
+% \begin{macro}{\@@_nogrid_bounding_box_set:}
+% Set the bounding box when no grid is being drawn.
+%    \begin{macrocode}
+\cs_new:Npn\@@_nogrid_bounding_box_set:
+  {
+    \pgfpathmoveto
+      { \pgfpoint{\l_@@_start_x}{\l_@@_content_bottom_y} }
+    \pgfpathmoveto
+      { \pgfpoint{\l_@@_finish_x}{\l_@@_content_top_y} }
+    \pgfusepath{discard}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Positioning}
+%
+% \begin{macro}{\@@_set_y_user:m}
+%   Set current \(y\) coordinate to \param{1}. This macro will be made available as \cs{timechartsety} in the
+%   \env{timechart} environment.
+%    \begin{macrocode}
+\cs_new:Npn\@@_set_y_user:m #1
+  {
+    \pgfmathsetmacro{\l_@@_current_y}{#1}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_save_y_user:}
+%   Save the current \(y\) coordinate. This macro will be made available as \cs{timechartsavey} in the
+%   \env{timechart} environment.
+%    \begin{macrocode}
+\cs_new:Npn\@@_save_y_user:
+  {
+    \pgfmathsetmacro{\l_@@_saved_y}{\l_@@_current_y}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_reset_y_user:}
+%   Set the current \(y\) coordinate to the last saved coordinate. This macro will be made available as
+%   \cs{timechartsresety} in the \env{timechart} environment.
+%    \begin{macrocode}
+\cs_new:Npn\@@_reset_y_user:
+  {
+    \pgfmathsetmacro{\l_@@_current_y}{\l_@@_saved_y}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_y_minimum_auto_reset_user:m}
+%   Set a \(y\) coordinate below which \cs{@@_step_y_user:} will automatically reset the currrent \(y\) coordinate to
+%   the last saved \(y\) coordinate. This macro will be made available as \cs{timechartssetyminimumautoreset} in the
+%   \env{timechart} environment.
+%    \begin{macrocode}
+\cs_new:Npn\@@_set_y_minimum_auto_reset_user:m #1
+  {
+    \pgfmathsetmacro{\l_@@_auto_reset_minimum_y}{#1}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_set_y_maximum_auto_reset_user:m}
+%   Set a \(y\) coordinate above which \cs{@@_step_y_user:} will automatically reset the currrent \(y\) coordinate to
+%   the last saved \(y\) coordinate. This macro will be made available as \cs{timechartssetymaximumautoreset} in the
+%   \env{timechart} environment.
+%    \begin{macrocode}
+\cs_new:Npn\@@_set_y_maximum_auto_reset_user:m #1
+  {
+    \pgfmathsetmacro{\l_@@_auto_reset_maximum_y}{#1}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_step_y_user:O}
+%   Increment the current \(y\) coordinate by \param{1} times the length specified in \key{/timechart/ystep}. This
+%   macro will be made available as \cs{timechartstepy} in the \env{timechart} environment.
+%    \begin{macrocode}
+\NewDocumentCommand{\@@_step_y_user:O}{ O{1} }
+  {
+    \pgfmathsetmacro{\l_@@_current_y}
+      {\l_@@_current_y+#1*\l_@@_ystep_pgf}
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+      {
+        or(
+          \l_@@_current_y<\l_@@_auto_reset_minimum_y,
+          \l_@@_current_y>\l_@@_auto_reset_maximum_y
+        )
+      }
+    \bool_if:nT{\l_@@_tmpa_bool}
+      { \pgfmathsetmacro{\l_@@_current_y}{\l_@@_saved_y)} }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Bounds checking}
+%
+% \begin{macro}{\@@_if_x_in_bounds:nT}%
+%   Check if \(x\) coordinate \param{1} is (strictly) within the bounds of the chart; if so, execute \param{2}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_if_x_in_bounds:nT #1#2
+  {
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
+      and(
+        #1>=\l_@@_start_x,
+        #1<=\l_@@_finish_x
+      )
+    }
+    \bool_if:NT\l_@@_tmpa_bool
+      {#2}
+  }
+
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_x_in_tolerance_bounds_x:nT}%
+%   Check if \(x\) coordinate \param{1} is within the specified tolerance of the bounds of the chart; if so, execute
+%   \param{2}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_if_x_in_tolerance_bounds:nT #1#2
+  {
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
+      and(
+        #1>=\l_@@_start_tolerance_x,
+        #1<=\l_@@_finish_tolerance_x
+      )
+    }
+    \bool_if:NT\l_@@_tmpa_bool{#2}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_if_x_range_intersect_tolerance_bounds_x:nnT}%
+%   Check if the range between \(x\) coordinates \param{1} and \param{2} intersects the range of the bounds of the chart
+%   plus the specified tolerance; if so, execute \param{3}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_if_x_range_intersect_tolerance_bounds:nnT #1#2#3
+  {
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}{
+      or(
+        or(
+          and(
+            #2>=\l_@@_start_tolerance_x,
+            #2<=\l_@@_finish_tolerance_x
+          ),
+          and(
+            #1>=\l_@@_start_tolerance_x,
+            #1<=\l_@@_finish_tolerance_x
+          )
+        ),
+        and(
+          #1<\l_@@_start_tolerance_x,
+          #2>\l_@@_finish_tolerance_x
+        )
+      )
+    }
+    \bool_if:NT\l_@@_tmpa_bool
+      {#3}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Date and date range parsing}
+%
+% \begin{macro}{\@@_parse_date_or_daterange:NNNNNn}
+%   Parse the text in \param{6}, which should represent a date or date range, into parameters \param{1}--\param{5}.
+%   \begin{arguments}
+%     \item range indicator boolean variable.
+%     \item minimum circa indicator boolean variable.
+%     \item minimum variable.
+%     \item maximum circa indicator boolean variable.
+%     \item maximum variable.
+%     \item text to parse.
+%   \end{arguments}
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_date_or_daterange:NNNNNn #1#2#3#4#5#6
+{
+  \bool_set:Nn #1 {\@@_is_nondaterange_p:w #6/\q_stop}
+  \bool_set_inverse:N #1
+  \bool_if:nTF #1
+    { \@@_parse_range:w #2#3#4#5\q_mark #6\q_stop }
+    {
+      \@@_parse_date:NNn #2#3{#6}
+      \bool_set_eq:NN #4#2
+      \pgfmathsetmacro{#5}{#3}
+    }
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_is_nondaterange_p:w}
+%   To be called in the form \cs{@@_is_nondaterange_p:w}\meta{text}\texttt{/}\cs{q_stop}. Return boolean true if and
+%   only if \meta{text} (known to be either a date or date range) contains a range marker.
+%    \begin{macrocode}
+\cs_new:Npn\@@_is_nondaterange_p:w #1/#2\q_stop
+{
+  \tl_if_empty_p:n{#2}
+}
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@@_parse_range:w}
+%   To be called in the form
+%   \cs{@@_parse_range:w}\meta{cmin}\meta{min}\meta{cmax}\meta{max}\cs{q_mark}\meta{text}\cs{q_stop}. Parse \meta{text}
+%   (known to represent a date range) into minimum circa indicator boolean variable \meta{cmin}, minimum variable
+%   \meta{min}, maximum circa indicator boolean variable \meta{cmax}, maximum variable \meta{max}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_range:w #1#2#3#4\q_mark #5/#6\q_stop
+{
+  \_@@_parse_date:NNn #1#2{#5}
+  \_@@_parse_date:NNn #3#4{#6}
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_date:NNn}
+%   Parse text (known to represent a date) into the supplied variables. Parameters \param{1} and \param{2} are the
+%   variables for (respectively) circa indicator boolean and date, and \param{3} is the text to be parsed:
+%   \begin{arguments}
+%     \item circa indicator boolean variable.
+%     \item date variable.
+%     \item text to parse.
+%   \end{arguments}
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_date:NNn #1#2#3
+{
+  \bool_set:Nn #1 { \@@_is_circa_p:w #3c\q_stop }
+  \bool_if:NTF #1
+    { \@@_parse_circa_date:w #2\q_mark #3\q_stop }
+    { \@@_parse_noncirca_date:Nn #2{#3} }
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_is_circa_p:w}
+%   To be called in the form \cs{@@_is_circa_p:w}\meta{text}\texttt{c}\cs{q_stop}. Return boolean true if and only if
+%   \meta{text} (known to be either a date or a date with a circa indicator) has a circa indicator.
+%    \begin{macrocode}
+\cs_new:Npn\@@_is_circa_p:w #1c#2\q_stop
+{
+  \tl_if_empty_p:n{#1}
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_circa_date:w}
+%   To be called in the form \cs{@@_parse_circa_date:w}\meta{var}\cs{q_mark}\meta{text}\cs{q_stop}. Parse \meta{text}
+%   (known to represent a circa date) into the supplied variable. \param{1} is the variable for the date and \param{2}
+%   is the text to be parsed.
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_circa_date:w #1\q_mark c#2\q_stop
+{
+  \@@_parse_noncirca_date:Nn #1{#2}
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_noncirca_date:w}
+%   To be called in the form \cs{@@_parse_noncirca_date:w}\meta{var}\cs{q_mark}\meta{text}\break\cs{q_stop}. Parse
+%   \meta{text} (known to represent a non-circa date) into the supplied variable. \param{1} is the variable for the date
+%   and \param{2} is the text to be parsed.
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_noncirca_date:Nn #1#2
+{
+  \bool_if:nTF { \@@_is_before_p:w #2-\q_stop }
+    { \@@_parse_before_date:w #1\q_mark #2\q_stop }
+    { \@@_parse_signed_date:w #1\q_mark #2-0-0\q_stop }
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_is_before_p:w}
+%   To be called in the form \cs{@@_is_before_p:w}\meta{text}\texttt{-}\cs{q_stop}. Return boolean true if and only if
+%   \meta{text} (known to be a date without a circa indicator) begins with a \texttt{-}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_is_before_p:w #1-#2\q_stop
+{
+  \tl_if_empty_p:n{#1}
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_before_date:w}
+%   To be called in the form \cs{@@_parse_before_date:w}\meta{var}\cs{q_mark}\meta{text}\cs{q_stop}. Parse \meta{text}
+%   (known to represent a date with a leading \texttt{-}) into the supplied variable. \param{1} is the variable for the
+%   date and \param{2} is the text to be parsed.
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_before_date:w #1\q_mark-#2\q_stop
+{
+  \@@_parse_signed_date:w #1-\q_mark #2-0-0\q_stop
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% Now comes that actual parsing of an ISO-format date \texttt{YYYY-MM-DD}. The following macros serve as lookup tables
+% for the number of days in the \(n\)-th month and the number of days in the year up to the start of the \(n\)-th month.
+%    \begin{macrocode}
+\cs_new:cpn{c_@@_year_days_pgf}{365}
+\cs_new:cpn{c_@@_month_days_1_pgf}{31}
+\cs_new:cpn{c_@@_month_days_2_pgf}{28}
+\cs_new:cpn{c_@@_month_days_3_pgf}{31}
+\cs_new:cpn{c_@@_month_days_4_pgf}{30}
+\cs_new:cpn{c_@@_month_days_5_pgf}{31}
+\cs_new:cpn{c_@@_month_days_6_pgf}{30}
+\cs_new:cpn{c_@@_month_days_7_pgf}{31}
+\cs_new:cpn{c_@@_month_days_8_pgf}{31}
+\cs_new:cpn{c_@@_month_days_9_pgf}{30}
+\cs_new:cpn{c_@@_month_days_10_pgf}{31}
+\cs_new:cpn{c_@@_month_days_11_pgf}{30}
+\cs_new:cpn{c_@@_month_days_12_pgf}{31}
+\cs_new:cpn{c_@@_cumulative_days_1_pgf}{0}
+\cs_new:cpn{c_@@_cumulative_days_2_pgf}{31}
+\cs_new:cpn{c_@@_cumulative_days_3_pgf}{59}
+\cs_new:cpn{c_@@_cumulative_days_4_pgf}{90}
+\cs_new:cpn{c_@@_cumulative_days_5_pgf}{120}
+\cs_new:cpn{c_@@_cumulative_days_6_pgf}{151}
+\cs_new:cpn{c_@@_cumulative_days_7_pgf}{181}
+\cs_new:cpn{c_@@_cumulative_days_8_pgf}{212}
+\cs_new:cpn{c_@@_cumulative_days_9_pgf}{243}
+\cs_new:cpn{c_@@_cumulative_days_10_pgf}{273}
+\cs_new:cpn{c_@@_cumulative_days_11_pgf}{304}
+\cs_new:cpn{c_@@_cumulative_days_12_pgf}{334}
+%    \end{macrocode}
+%
+% \begin{macro}{\@@_parse_signed_date:w}
+%   To be called in the form \cs{@@_parse_positive_date:w}\meta{var}\meta{sign}\cs{q_mark}\break
+%   \meta{text}\texttt{-0-0}\cs{q_stop}. Parse \meta{text} (known to represent a non-circa date) into the supplied
+%   variable. \param{1} is the variable for the date and \param{2} is possibly \texttt{-}.
+%
+%   There is a trick in the parsing:
+%   \begin{enumerate}
+%       \item If \meta{text} has the form \meta{year}\texttt{-}\meta{month}\texttt{-}\meta{day}, then parameters
+%             \param{3}, \param{4}, and \param{5} will be, respectively, \meta{year}, \meta{month}, and
+%             \meta{day}\texttt{-0-0}. Thus \param{5} will be evaulated by \pkg{pgfmath} to \meta{day}.
+%       \item If \meta{text} has the form \meta{year}\texttt{-}\meta{month}, then parameters \param{3}, \param{4}, and
+%             \param{5} will be, respectively, \meta{year}, \meta{month}, and \texttt{0-0}. Thus \param{5} will be
+%             evaulated by \pkg{pgfmath} to \(0\).
+%       \item If \meta{text} is simply \meta{year}, then parameters \param{3}, \param{4}, and \param{5} will be,
+%             respectively, \meta{year}, \texttt{0}, and \texttt{0}.
+%     \end{enumerate}
+%    \begin{macrocode}
+\cs_new:Npn\@@_parse_signed_date:w #1#2\q_mark #3-#4-#5\q_stop
+{
+  \pgfmathtruncatemacro{\@@_parsed_year_pgf}{#2#3}
+  \pgfmathtruncatemacro{\@@_parsed_month_pgf}{#4}
+  \pgfmathtruncatemacro{\@@_parsed_day_pgf}{#5}
+  \@@_pgfmathsetbool:nn{\l_tmpa_bool}{
+    or(
+      \@@_parsed_month_pgf < 1,
+      \@@_parsed_month_pgf > 12,
+    )
+  }
+  \bool_if:NTF\l_tmpa_bool
+  {
+%    \end{macrocode}
+%   \textit{Case: no valid month is given.} Use only the year.
+%    \begin{macrocode}
+    \pgfmathsetmacro{#1}{#2#3}
+  }
+  {
+%    \end{macrocode}
+%   \textit{Case: a valid month is given.} Get the number of days in the year, in the month, and in the year up to the
+%   month. Then check if the year is a leap year and, if so, make the appropriate adjustments.
+%    \begin{macrocode}
+    \cs_set_eq:NN\l_@@_year_days_pgf\c_@@_year_days_pgf
+    \cs_set_eq:Nc\l_@@_month_days_pgf
+      { c_@@_month_days_\@@_parsed_month_pgf _pgf }
+    \cs_set_eq:Nc\l_@@_cumulative_days_pgf
+      { c_@@_cumulative_days_\@@_parsed_month_pgf _pgf }
+    \@@_pgfmathsetbool:nn{\l_tmpa_bool}{
+      or(
+        Mod(\@@_parsed_year_pgf,400) == 0,
+        and(
+          Mod(\@@_parsed_year_pgf,4) == 0,
+          Mod(\@@_parsed_year_pgf,100) != 0
+        )
+      )
+    }
+    \bool_if:NT\l_tmpa_bool
+      {
+        \pgfmathsetmacro{\l_@@_year_days_pgf}
+          { \l_@@_year_days_pgf+1 }
+        \@@_pgfmathsetbool:nn{\l_tmpb_bool}
+          { \@@_parsed_month == 1 }
+        \bool_if:NF\l_tmpb_bool
+          {
+            \@@_pgfmathsetbool:nn{\l_tmpb_bool}
+              { \@@_parsed_month == 2 }
+            \bool_if:NF\l_tmpb_bool
+              {
+                \pgfmathsetmacro{\l_@@_month_days_pgf}
+                  { \l_@@_month_days_pgf + 1 }
+              }
+              {
+                \pgfmathsetmacro{\l_@@_cumulative_days_pgf}
+                  { \l_@@_cumulative_days_pgf + 1 }
+              }
+          }
+      }
+    \@@_pgfmathsetbool:nn{\l_tmpa_bool}{
+      or(
+        \@@_parsed_day_pgf < 1,
+        \@@_parsed_day_pgf > \l_@@_month_days_pgf,
+      )
+    }
+    \bool_if:NTF\l_tmpa_bool
+      {
+%    \end{macrocode}
+%   \textit{Sub-case: no valid day is given.} Use only the year and month.
+%    \begin{macrocode}
+       \pgfmathsetmacro{#1}
+         {
+           #2#3
+           + \l_@@_cumulative_days_pgf/\l_@@_year_days_pgf
+         }
+      }
+      {
+%    \end{macrocode}
+%   \textit{Sub-case: a valid day is given.} Use the year, month, and day.
+%    \begin{macrocode}
+       \pgfmathsetmacro{#1}
+         {
+           #2#3
+           + (
+               \l_@@_cumulative_days_pgf
+               + \@@_parsed_day_pgf
+             )/\l_@@_year_days_pgf
+         }
+      }
+  }
+}
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Interval drawing}
+%
+% \subsubsection{Preliminaries}
+%
+% \begin{macro}{
+%   \l_@@_start_is_range_bool,
+%   \l_@@_startmin_circa_bool,
+%   \l_@@_startmax_circa_bool,
+%   \l_@@_finish_is_range_bool,
+%   \l_@@_finishmin_circa_bool,
+%   \l_@@_finishmax_circa_bool,
+% }
+%   These boolean variables will be used to hold parsed data for the start and finish of an interval: whether it is a
+%   range, whether the beginning of that range is qualified by `circa', and whether the end of that range is qualified
+%   by `circa'.
+%    \begin{macrocode}
+\bool_new:N\l_@@_start_is_range_bool
+\bool_new:N\l_@@_startmin_circa_bool
+\bool_new:N\l_@@_startmax_circa_bool
+\bool_new:N\l_@@_finish_is_range_bool
+\bool_new:N\l_@@_finishmin_circa_bool
+\bool_new:N\l_@@_finishmax_circa_bool
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Error message definition}
+%
+%    \begin{macrocode}
+\msg_new:nnn{timechart}{interval_dates_invalid}
+  { Invalid~interval~dates:~#1~to~#2 }
+%    \end{macrocode}
+%
+%
+%
+% \subsubsection{Main macros}
+%
+% \begin{macro}{\@@_interval_user:Ommm}
+%   Draw an interval. This macro will be made available as \cs{timechartinterval} inside the \env{timechart}
+%   environment.
+%   \begin{arguments}
+%     \item PGF keys under \key{/timechart/} to apply.
+%     \item Start year.
+%     \item Finish year.
+%     \item Label.
+%   \end{arguments}
+%    \begin{macrocode}
+\NewDocumentCommand{\@@_interval_user:Ommm}{ O{} m m m }
+  {
+    \group_begin:
+%    \end{macrocode}
+%   Parse the start and finish dates or date ranges.
+%    \begin{macrocode}
+    \@@_parse_date_or_daterange:NNNNNn
+      \l_@@_start_is_range_bool
+      \l_@@_startmin_circa_bool\l_@@_startmin_year
+      \l_@@_startmax_circa_bool\l_@@_startmax_year
+      {#2}
+    \@@_parse_date_or_daterange:NNNNNn
+      \l_@@_finish_is_range_bool
+      \l_@@_finishmin_circa_bool\l_@@_finishmin_year
+      \l_@@_finishmax_circa_bool\l_@@_finishmax_year
+      {#3}
+%    \end{macrocode}
+%   Check the results of parsing and only proceed if they are valid.
+%    \begin{macrocode}
+    \@@_pgfmathsetbool:nn{\l_tmpa_bool}{
+      and(
+        \l_@@_startmin_year <= \l_@@_startmax_year,
+        and(
+          \l_@@_startmax_year <= \l_@@_finishmin_year,
+          \l_@@_finishmin_year <= \l_@@_finishmax_year
+        )
+      )
+    }
+    \bool_if:NTF\l_tmpa_bool
+      {
+        \@@_interval_checked:nn{#1}{#4}
+        \group_end:
+        \bool_if:NT\l_@@_autostep_bool
+          { \@@_step_y_user:O }
+      }
+      {
+        \msg_error:nnnn{timechart}{interval_dates_invalid}{#2}{#3}
+        \group_end:
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_checked:nn}
+%   Draw an interval using the parsed and checked years or year ranges.
+%   \begin{arguments}
+%     \item PGF keys under \key{/timechart/} to apply.
+%     \item Label.
+%   \end{arguments}
+%    \begin{macrocode}
+\cs_new:Npn \@@_interval_checked:nn #1#2
+  {
+%    \end{macrocode}
+%   Process keys supplied locally and retrieve the only value needed at this stage.
+%    \begin{macrocode}
+    \pgfqkeys{/timechart}{
+      #1,
+      circa~uncertainty/.get=\l_@@_circa_uncertainty_year
+    }
+%    \end{macrocode}
+%   Do the minimum amount of calculation necessary to check whether any part of interval is visible.
+%    \begin{macrocode}
+    \bool_if:NTF\l_@@_startmin_circa_bool
+      {
+        \pgfmathsetmacro{\l_@@_start_extreme_x}
+          { yeartox(\l_@@_startmin_year
+            - \l_@@_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l_@@_start_extreme_x}
+          { yeartox(\l_@@_startmin_year) }
+      }
+    \bool_if:NTF\l_@@_finishmax_circa_bool
+      {
+        \pgfmathsetmacro{\l_@@_finish_extreme_x}
+          { yeartox(\l_@@_finishmax_year
+            + \l_@@_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l_@@_finish_extreme_x}
+          { yeartox(\l_@@_finishmax_year) }
+      }
+%    \end{macrocode}
+%   Draw the interval if some part of it is visible.
+%    \begin{macrocode}
+    \@@_if_x_range_intersect_tolerance_bounds:nnT
+      {\l_@@_start_extreme_x}{\l_@@_finish_extreme_x}
+      { \@@_draw_visible_interval:nn{#1}{#2} }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{@@_draw_visible_interval:nn}
+%   Draw an interval of which some part is known to be visible.
+%   \begin{arguments}
+% \item PGF keys
+% \item Label
+%   \end{arguments}
+%    \begin{macrocode}
+\cs_new:Npn\@@_draw_visible_interval:nn #1#2
+  {
+%    \end{macrocode}
+%   Retrieve PGF key values.
+%    \begin{macrocode}
+    \pgfqkeys{/timechart}{
+      ref/.get=\l_@@_ref_text,
+      mark/.get=\l_@@_mark_text,
+      interval~minimum~width/.get=\l_@@_minimum_width_pgf,
+      interval~bar~color/.get=\l_@@_bar_color,
+      interval~bar~thickness/.get=\l_@@_bar_thickness_pgf,
+      interval~mark~color/.get=\l_@@_mark_color,
+      interval~label~baseline/.get=\l_@@_text_baseline_pgf,
+      interval~label~node~name/.get=\l_@@_interval_label_node_name,
+    }
+%    \end{macrocode}
+%   Do the remaining calculations.
+%    \begin{macrocode}
+    \pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
+      {.5*\l_@@_bar_thickness_pgf}
+    \cs_set:Npn\l_@@_label_text{#2}
+    \bool_if:NTF\l_@@_startmax_circa_bool
+      {
+        \pgfmathsetmacro{\l_@@_start_definite_x}
+          { yeartox(\l_@@_startmax_year
+            + \l_@@_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l_@@_start_definite_x}
+          { yeartox(\l_@@_startmax_year) }
+      }
+    \bool_if:NTF\l_@@_finishmin_circa_bool
+      {
+        \pgfmathsetmacro{\l_@@_finish_definite_x}
+          { yeartox(\l_@@_finishmin_year
+            - \l_@@_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l_@@_finish_definite_x}
+          { yeartox(\l_@@_finishmin_year) }
+      }
+%    \end{macrocode}
+%   It is possible that circa indicators have made \cs{l_@@_start_definite_x} greater than \cs{l_@@_finish_definite_x}.
+%   Check for this; if so, set them both to their average.
+%    \begin{macrocode}
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+      {
+        \l_@@_start_definite_x > \l_@@_finish_definite_x
+      }
+    \bool_if:NT\l_@@_tmpa_bool
+      {
+        \pgfmathsetmacro{\l_@@_start_definite_x}
+          {
+            .5*(
+              \l_@@_start_definite_x
+              + \l_@@_finish_definite_x
+            )
+          }
+        \pgfmathsetmacro{\l_@@_finish_definite_x}
+          { \l_@@_start_definite_x }
+      }
+%    \end{macrocode}
+%   Calculate whether it is necessary to make an adjustment to ensure that the minimum width requirement is satisfied,
+%   and store in \cs{l_@@_tmpa_bool}.
+%    \begin{macrocode}
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+      {
+        (\l_@@_finish_extreme_x-\l_@@_start_extreme_x)
+        < \l_@@_minimum_width_pgf
+      }
+%    \end{macrocode}
+%   Calculate whether it is necessary to make an adjustment to prevent a rendering glitch when there are two fadings and
+%   a zero-width (or very small) definite part, and store in \cs{l_@@_tmpb_bool}. Note the quick test for both ranges
+%   being fadings.
+%    \begin{macrocode}
+    \int_if_zero:nTF
+      {
+        \l_@@_start_range_type_int
+        + \l_@@_finish_range_type_int
+      }
+      {
+        \@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
+          {
+            (
+              \l_@@_finish_definite_x
+              - \l_@@_start_definite_x
+            )
+            < \l_@@_minimum_width_pgf
+          }
+      }
+      { \bool_set_false:N\l_@@_tmpb_bool }
+%    \end{macrocode}
+%   Make the adjustment if necessary.
+%    \begin{macrocode}
+    \bool_if:nT{
+      \l_@@_tmpa_bool || \l_@@_tmpb_bool
+    }{
+      \pgfmathsetmacro{\l_@@_width_adjust}
+        { .5*\l_@@_minimum_width_pgf }
+      \pgfmathsetmacro{\l_@@_start_definite_x}
+        { \l_@@_start_definite_x-\l_@@_width_adjust }
+      \pgfmathsetmacro{\l_@@_finish_definite_x}
+        { \l_@@_finish_definite_x+\l_@@_width_adjust }
+      \pgfmathsetmacro{\l_@@_start_extreme_x}
+        {
+          min(
+            \l_@@_start_extreme_x,
+            \l_@@_start_definite_x
+          )
+        }
+      \pgfmathsetmacro{\l_@@_finish_extreme_x}
+        {
+          max(
+            \l_@@_finish_extreme_x,
+            \l_@@_finish_definite_x
+          )
+        }
+    }
+    \pgfmathsetmacro{\l_@@_start_solid_x}
+      { \l_@@_start_definite_x }
+    \pgfmathsetmacro{\l_@@_finish_solid_x}
+      { \l_@@_finish_definite_x }
+%    \end{macrocode}
+%   All the data needed to draw the interval are now ready. Shift to the correct vertical coordinate and open a scope for
+%   drawing.
+%    \begin{macrocode}
+    \pgftransformshift{ \pgfpoint{0}{\l_@@_current_y} }
+    \pgfscope
+%    \end{macrocode}
+%   First, do the necessary clipping if the interval extends beyond the specified tolerance from the chart, then process
+%   the ranges, then draw the solid part of the bar, then do the labelling, then define the node for the bar. Note that
+%   ranges wth the `slant' style function by adding a new clipping path and extending the solid part, so that there is
+%   only \emph{one} solid rectangle drawn.
+%    \begin{macrocode}
+    \@@_interval_beyond_clip:
+    \int_case:nn {\l_@@_start_range_type_int}
+      {
+        {0}{ \@@_interval_start_range_fade: }
+        {1}{ \@@_interval_start_range_slant: }
+      }
+    \int_case:nn {\l_@@_finish_range_type_int}
+      {
+        {0}{ \@@_interval_finish_range_fade: }
+        {1}{ \@@_interval_finish_range_slant: }
+      }
+    \@@_interval_draw_solid:
+    \@@_interval_mark:
+    \@@_interval_define_bar_node:
+    \endpgfscope
+    \@@_interval_label:
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Clipping}
+%
+% \begin{macro}{\@@_interval_beyond_clip:}
+%   If the interval bar extends beyond the specified tolerance from the chart, clip it appropriately. To avoid repeated
+%   computation, use \cs{l_@@_tmpa_bool} and \cs{l_@@_tmpb_bool} to store whether it is necessary to clip on the left
+%   and right (respectively). If both are false, there is no need for any clipping.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_beyond_clip:
+  {
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+      {\l_@@_start_extreme_x<=\l_@@_start_tolerance_x}
+    \@@_pgfmathsetbool:nn{\l_@@_tmpb_bool}
+      {\l_@@_finish_extreme_x>=\l_@@_finish_tolerance_x}
+    \bool_if:nT{ \l_@@_tmpa_bool || \l_@@_tmpb_bool }
+      { \@@_interval_beyond_clip_aux: }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_beyond_clip_aux:}
+%   This macro does the actual clipping. The clipping path starts at the north-east and proceeds clockwise.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_beyond_clip_aux:
+  {
+    \pgfinterruptboundingbox
+    \bool_if:NTF\l_@@_tmpb_bool
+      {
+        \pgfpathmoveto{
+          \pgfpoint
+            {\l_@@_finish_beyond_x}
+            {\l_@@_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_finish_beyond_x}
+            {\l_@@_bar_half_thickness_pgf}
+        }
+        \pgfpatharc
+          {90}
+          {270}
+          {\l_@@_beyond_x_radius_pgf
+            ~and~\l_@@_bar_half_thickness_pgf}
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_finish_beyond_x}
+            {-\l_@@_bar_thickness_pgf}
+        }
+      }
+      {
+        \pgfpathmoveto{
+          \pgfpoint
+            {\l_@@_right_nonclip_x}
+            {\l_@@_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_right_nonclip_x}
+            {-\l_@@_bar_thickness_pgf}
+        }
+      }
+    \bool_if:NTF\l_@@_tmpa_bool
+      {
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_start_beyond_x}
+            {-\l_@@_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_start_beyond_x}
+            {-\l_@@_bar_half_thickness_pgf}
+        }
+        \pgfpatharc
+          {-90}
+          {90}
+          {\l_@@_beyond_x_radius_pgf
+            ~and~\l_@@_bar_half_thickness_pgf}
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_start_beyond_x}
+            {\l_@@_bar_thickness_pgf}
+        }
+      }
+      {
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_left_nonclip_x}
+            {-\l_@@_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_left_nonclip_x}
+            {\l_@@_bar_thickness_pgf}
+        }
+      }
+    \pgfpathclose
+    \pgfusepath{clip}
+    \endpgfinterruptboundingbox
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Fading in/out}
+%
+% Set up the PGF `in' fading.
+%    \begin{macrocode}
+\pgfdeclarehorizontalshading{@@_fade_in_shading}{4bp}{
+   color(0bp)=(transparent!100);
+   color(1bp)=(transparent!100);
+   color(3bp)=(transparent!0);
+   color(4bp)=(transparent!0)
+}
+\pgfdeclarefading
+  {@@_fade_in}
+  {\pgfuseshading{@@_fade_in_shading}}
+%    \end{macrocode}
+%
+% \begin{macro}{\@@_interval_start_range_fade:}
+%   Draw fading to indicate a start range. Because some PDF renderers may otherwise leave a gap between the fade and
+%   solid part, compute \cs{l_@@_fade_extra_pgf} and draw this amount of overlap with the solid part. Because of the
+%   definition of the `in' fading, \cs{l_@@_fade_extra_pgf} must not exceed half of the fade width. And the overlap
+%   should not exceed the actual length of the solid part.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_start_range_fade:
+  {
+    \pgfmathsetlengthmacro{\l_@@_fade_width_pgf}
+      { \l_@@_start_solid_x-\l_@@_start_extreme_x }
+    \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+      { \l_@@_fade_width_pgf
+        > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+    \bool_if:NT \l_@@_tmpa_bool
+      {
+        \@@_if_x_range_intersect_tolerance_bounds:nnT
+          {\l_@@_start_extreme_x}{\l_@@_start_solid_x}
+          {
+            \pgfmathsetmacro{\l_@@_fade_extra_pgf}
+            {
+              min(
+                .49*\l_@@_fade_width_pgf,
+                \l_@@_finish_solid_x-\l_@@_start_solid_x
+              )
+            }
+            \pgfscope
+            \pgfpathrectanglecorners{
+              \pgfpoint
+                {\l_@@_start_extreme_x}
+                {-\l_@@_bar_half_thickness_pgf}
+            }{
+              \pgfpoint
+                {\l_@@_start_solid_x+\l_@@_fade_extra_pgf}
+                {\l_@@_bar_half_thickness_pgf}
+            }
+            \pgfgettransform{\@@_transform_current}
+            \pgfsetfading{@@_fade_in}{
+              \pgfsettransform{\@@_transform_current}
+              \pgftransformshift{
+                \pgfpoint
+                  {
+                    .5*\l_@@_start_extreme_x
+                    +.5*\l_@@_start_solid_x
+                  }
+                  {0}
+              }
+              \pgftransformxscale{
+                (\l_@@_start_solid_x-\l_@@_start_extreme_x)
+                /2bp
+              }
+              \pgftransformyscale{\l_@@_bar_thickness_pgf/4bp}
+            }
+            \pgfsetfillcolor{\l_@@_bar_color}
+            \pgfusepath{fill}
+            \endpgfscope
+          }
+    }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% Set up the PGF `out' fading.
+%    \begin{macrocode}
+\pgfdeclarehorizontalshading{@@_fade_out_shading}{4bp}{
+    color(0bp)=(transparent!0);
+   color(1bp)=(transparent!0);
+   color(3bp)=(transparent!100);
+  color(4bp)=(transparent!100)
+}
+\pgfdeclarefading
+  {@@_fade_out}
+  {\pgfuseshading{@@_fade_out_shading}}
+%    \end{macrocode}
+%
+% \begin{macro}{\@@_interval_finish_range_fade:}
+%   Draw fading to indicate a finish range. As in \cs{@@_interval_start_range_fade:}, a small overlap is computed.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_finish_range_fade:
+  {
+    \pgfmathsetlengthmacro{\l_@@_fade_width_pgf}
+      { \l_@@_finish_extreme_x-\l_@@_finish_solid_x }
+      \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+      { \l_@@_fade_width_pgf
+        > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+    \bool_if:NT \l_@@_tmpa_bool
+      {
+        \@@_if_x_range_intersect_tolerance_bounds:nnT
+          {\l_@@_finish_solid_x}{\l_@@_finish_extreme_x}
+          {
+            \pgfmathsetmacro{\l_@@_fade_extra_pgf}
+            {
+              min(
+                .49*\l_@@_fade_width_pgf,
+                \l_@@_finish_solid_x-\l_@@_start_solid_x
+              )
+            }
+            \pgfscope
+            \pgfpathrectanglecorners{
+              \pgfpoint
+                {\l_@@_finish_solid_x-\l_@@_fade_extra_pgf}
+                {-\l_@@_bar_half_thickness_pgf}
+            }{
+              \pgfpoint
+                {\l_@@_finish_extreme_x}
+                {\l_@@_bar_half_thickness_pgf}
+            }
+            \pgfgettransform{\@@_transform_current}
+            \pgfsetfading{@@_fade_out}{
+              \pgfsettransform{\@@_transform_current}
+              \pgftransformshift{
+                \pgfpoint{
+                  .5*\l_@@_finish_solid_x
+                  +.5*\l_@@_finish_extreme_x
+                }
+                {0}
+              }
+              \pgftransformxscale{
+                (\l_@@_finish_extreme_x-\l_@@_finish_solid_x)
+                /2bp
+              }
+              \pgftransformyscale{\l_@@_bar_thickness_pgf/4bp}
+            }
+            \pgfsetfillcolor{\l_@@_bar_color}
+            \pgfusepath{fill}
+            \endpgfscope
+          }
+    }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Slant in/out}
+%
+% \begin{macro}{\@@_interval_start_range_slant:}
+%   Clip and modify \cs{l_@@_start_solid_x} to draw a slanting shape to indicate the start range.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_start_range_slant:
+  {
+    \@@_if_equal:nnF
+      {\l_@@_start_extreme_x}{\l_@@_start_solid_x}
+      {
+        \@@_if_x_range_intersect_tolerance_bounds:nnT
+          {\l_@@_start_extreme_x}{\l_@@_start_solid_x}
+          {
+            \pgfinterruptboundingbox
+            \pgfpathmoveto{
+              \pgfpoint
+                {\l_@@_start_extreme_x}
+                {-\l_@@_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_start_solid_x}
+                {\l_@@_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_start_solid_x}
+                {\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_right_nonclip_x}
+                {\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_right_nonclip_x}
+                {-\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_start_extreme_x}
+                {-\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathclose
+            \pgfusepath{clip}
+            \endpgfinterruptboundingbox
+            \pgfmathsetmacro{\l_@@_start_solid_x}
+              {\l_@@_start_extreme_x}
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_finish_range_slant:}
+%   Clip and modify \cs{l_@@_finish_solid_x} to draw a slanting shape to indicate the finish range.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_finish_range_slant:
+  {
+    \@@_if_equal:nnF
+      {\l_@@_finish_solid_x}{\l_@@_finish_extreme_x}
+      {
+        \@@_if_x_range_intersect_tolerance_bounds:nnT
+          {\l_@@_finish_solid_x}{\l_@@_finish_extreme_x}
+          {
+            \pgfinterruptboundingbox
+            \pgfpathmoveto{
+              \pgfpoint
+                {\l_@@_finish_solid_x}
+                {-\l_@@_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_finish_extreme_x}
+                {\l_@@_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_finish_extreme_x}
+                {\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_left_nonclip_x}
+                {\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_left_nonclip_x}
+                {-\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l_@@_finish_solid_x}
+                {-\l_@@_bar_thickness_pgf}
+            }
+            \pgfpathclose
+            \pgfusepath{clip}
+            \endpgfinterruptboundingbox
+            \pgfmathsetmacro{\l_@@_finish_solid_x}
+              {\l_@@_finish_extreme_x}
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Solid bar}
+%
+% \begin{macro}{\@@_interval_draw_solid:}
+%   Draw the solid part of an interval.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_draw_solid:
+  {
+    \@@_if_x_range_intersect_tolerance_bounds:nnT
+      {\l_@@_start_solid_x}
+      {\l_@@_finish_solid_x}
+      {
+        \pgfpathrectanglecorners{
+          \pgfpoint
+            {\l_@@_start_solid_x}
+            {-\l_@@_bar_half_thickness_pgf}
+        }{
+          \pgfpoint
+            {\l_@@_finish_solid_x}
+            {\l_@@_bar_half_thickness_pgf}
+        }
+        \pgfsetfillcolor{\l_@@_bar_color}
+        \pgfusepath{fill}
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Marks}
+%
+%    \begin{macrocode}
+\msg_new:nnn{timechart}{interval_mark_outside}
+  { Attempt~to~mark~outside~interval~at~date~#1 }
+%    \end{macrocode}
+%
+% \begin{macro}{\@@_interval_mark:}
+%   Draw marks on an interval.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_mark:
+  {
+    \pgfscope
+    \pgfsetstrokecolor{\l_@@_mark_color}
+    \foreach \year in \l_@@_mark_text
+      {
+        \pgfmathsetmacro{\l_@@_mark_x}{yeartox(\year)}
+        \@@_pgfmathsetbool:nn{\l_@@_tmpa_bool}
+          {
+            or (
+              \l_@@_mark_x < \l_@@_start_extreme_x,
+              \l_@@_mark_x > \l_@@_finish_extreme_x
+            )
+          }
+        \bool_if:NT\l_@@_tmpa_bool
+          { \msg_error:nne{timechart}{interval_mark_outside}{\year} }
+        \pgfpathmoveto{
+          \pgfpoint
+            {\l_@@_mark_x}
+            {-\l_@@_bar_half_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l_@@_mark_x}
+            {\l_@@_bar_half_thickness_pgf}
+        }
+        \pgfusepath{draw}
+      }
+    \endpgfscope
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Bar node}
+%
+% \begin{macro}{\@@_interval_define_bar_node:}
+%   Define a node with into which the bar fits exactly.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_define_bar_node:
+  {
+    \@@_make_rectangle_node:nnnn
+      {
+        \pgfpoint
+          {\l_@@_start_extreme_x}
+          {-\l_@@_bar_half_thickness_pgf}
+      }{
+        \pgfpoint
+          {\l_@@_finish_extreme_x}
+          {\l_@@_bar_half_thickness_pgf}
+      }
+      {\pgfkeysvalueof{/timechart/interval~bar~node~name}}
+      {\c_false_bool}
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsubsection{Label}
+%
+% \begin{macro}{\@@_interval_label:}
+%   Place the label for the item.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_label:
+  {
+    \str_if_empty:NF \l_@@_label_text
+      {
+        \pgfinterruptboundingbox
+        \int_case:nn {\l_@@_label_pos_int}
+        {
+          {0}{ \@@_interval_label_left: }
+          {1}{ \@@_interval_label_center: }
+          {2}{ \@@_interval_label_right: }
+        }
+        \endpgfinterruptboundingbox
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_label_left:}
+%   Place the label on the left of the interval.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_label_left:
+  {
+    \@@_if_x_in_bounds:nT{\l_@@_start_extreme_x}
+      {
+        \group_begin:
+        \pgftransformshift{
+          \pgfpoint
+            {\l_@@_start_extreme_x}
+            {\l_@@_text_baseline_pgf}
+        }
+        \node[/timechart/interval~label,anchor=base~east]
+          (\l_@@_interval_label_node_name)
+          at (0,0)
+          {
+            \@@_make_ref:NN
+              \l_@@_ref_text
+              \l_@@_label_text
+          };
+        \group_end:
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_label_right:}
+%   Place the label on the right of the interval.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_label_right:
+  {
+    \@@_if_x_in_bounds:nT{\l_@@_finish_extreme_x}
+      {
+        \group_begin:
+        \pgftransformshift{
+          \pgfpoint
+            {\l_@@_finish_extreme_x}
+            {\l_@@_text_baseline_pgf}
+        }
+        \node[/timechart/interval~label,anchor=base~west]
+          (\l_@@_interval_label_node_name)
+          at (0,0)
+          {
+            \@@_make_ref:NN
+              \l_@@_ref_text
+              \l_@@_label_text
+          };
+        \group_end:
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_interval_label_center:}
+%   Place the label at the center of the interval.
+%    \begin{macrocode}
+\cs_new:Npn\@@_interval_label_center:
+  {
+    \pgfmathsetlengthmacro{\l_@@_label_anchor_x}
+      {
+        .5*max(\l_@@_start_definite_x,\l_@@_start_x)
+        + .5*min(\l_@@_finish_definite_x,\l_@@_finish_x)
+      }
+%    \end{macrocode}
+%   First draw the `background label' on the layer below the bar.
+%    \begin{macrocode}
+    \group_begin:
+    \pgftransformshift{
+      \pgfpoint
+        {\l_@@_label_anchor_x}
+        {\l_@@_text_baseline_pgf}
+    }
+    \pgfonlayer{labelbg}
+    \node[
+      /timechart/interval~label~centered~background,
+      anchor=base
+    ]
+      at (0,0)
+      { \l_@@_label_text };
+    \endpgfonlayer
+    \group_end:
+%    \end{macrocode}
+%   Then draw the label on top of the bar, clipping it to the bar outline.
+%    \begin{macrocode}
+    \pgfscope
+    \pgfpathrectanglecorners{
+      \pgfpoint
+        {\l_@@_start_extreme_x}
+        {-\l_@@_bar_half_thickness_pgf}
+    }{
+      \pgfpoint
+        {\l_@@_finish_extreme_x}
+        {\l_@@_bar_half_thickness_pgf}
+    }
+    \pgfusepath{clip}
+    \group_begin:
+    \pgftransformshift{
+      \pgfpoint
+        {\l_@@_label_anchor_x}
+        {\l_@@_text_baseline_pgf}
+    }
+    \node[
+    /timechart/interval~label~centered,
+    anchor=base
+    ]
+      (\l_@@_interval_label_node_name)
+      at (0,0)
+      {
+        \@@_make_ref:NN
+        \l_@@_ref_text
+        \l_@@_label_text
+      };
+    \group_end:
+    \endpgfscope
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Text}
+%
+% \begin{macro}{\@@_text_user:Omm}
+%   Place text. This macro will be made available as \cs{timecharttext} inside the \env{timechart} environment.
+%   \begin{arguments}
+%     \item PGF keys under \key{/timechart/} to apply.
+%     \item Year at which to place text.
+%     \item Text.
+%   \end{arguments}
+%    \begin{macrocode}
+\NewDocumentCommand{\@@_text_user:Omm}{ O{} m m }
+  {
+    \str_if_empty:nF{#3}{
+      \group_begin:
+      \pgfmathsetmacro{\l_@@_text_x}{yeartox(#2)}
+      \@@_if_x_in_tolerance_bounds:nT{\l_@@_text_x}
+        {
+%    \end{macrocode}
+%   Process keys supplied locally and retrieve needed keys.
+%    \begin{macrocode}
+          \pgfqkeys{/timechart}{
+            #1,
+            ref/.get=\l_@@_ref_text,
+            text~node~name/.get=\l_@@_node_name_text,
+            text~baseline/.get=\l_@@_text_baseline_pgf,
+          }
+%    \end{macrocode}
+%    Shift to the correct vertical coordinate and place the text.
+%    \begin{macrocode}
+          \pgftransformshift{
+            \pgfpoint{0}{\l_@@_current_y}
+          }
+          \pgfinterruptboundingbox
+          \group_begin:
+          \pgftransformshift{
+            \pgfpoint{\l_@@_text_x}{\l_@@_text_baseline_pgf}
+          }
+          \cs_set:Npn\l_@@_text{#3}
+          \int_case:nn {\l_@@_text_pos_int}
+          {
+            {0}{ \cs_set:Npn\l_@@_node_anchor_text{base~east} }
+            {1}{ \cs_set:Npn\l_@@_node_anchor_text{base} }
+            {2}{ \cs_set:Npn\l_@@_node_anchor_text{base~west} }
+          }
+          \node[/timechart/text,anchor=\l_@@_node_anchor_text]
+            (\l_@@_node_name_text)
+            at (0,0)
+            {
+              \@@_make_ref:NN
+              \l_@@_ref_text
+              \l_@@_text
+            };
+          \group_end:
+          \endpgfinterruptboundingbox
+        }
+      \group_end:
+    }
+%    \end{macrocode}
+%   Since the text itself does not affect the bounding box, create a space (which will handle the automatic step).
+%    \begin{macrocode}
+    \@@_space_user:O[#1]
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Space}
+%
+% \begin{macro}{\@@_space_user:O}
+%   Create a vertical space as if there were an interval at the current coordinate. This macro will be made available as
+%   \cs{timechartspace} inside the \env{timechart} environment.
+%    \begin{macrocode}
+\NewDocumentCommand{\@@_space_user:O}{ O{} }
+  {
+    \group_begin:
+%    \end{macrocode}
+%   Process keys supplied locally and retreive the one needed value.
+
+%    \begin{macrocode}
+    \pgfqkeys{/timechart}{
+      #1,
+      interval~bar~thickness/.get=\l_@@_bar_thickness_pgf,
+    }
+    \pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
+      { .5*\l_@@_bar_thickness_pgf }
+%    \end{macrocode}
+%    Shift to the correct vertical coordinate and create the space.
+%    \begin{macrocode}
+    \pgftransformshift{
+      \pgfpoint{0}{\l_@@_current_y}
+    }
+    \pgfpathmoveto{
+      \pgfpoint{0}{-\l_@@_bar_half_thickness_pgf}
+    }
+    \pgfpathmoveto{
+      \pgfpoint{0}{\l_@@_bar_half_thickness_pgf}
+    }
+    \pgfusepath{discard}
+    \group_end:
+    \bool_if:NT\l_@@_autostep_bool{
+      \@@_step_y_user:O
+    }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+% \subsection{Legends}
+%
+% \begin{macro}{\timechartlegenditem}
+%   Draw a bar suitable for use in a legend, applying style in \param{1}.
+%    \begin{macrocode}
+\NewDocumentCommand{\timechartlegenditem}{ O{} }
+  {
+    \@@_legend_aux:nn{#1}{
+      \pgfmathsetlengthmacro{\l_@@_start_solid_x}{0}
+      \pgfmathsetlengthmacro{\l_@@_finish_solid_x}
+        {\l_@@_legenditem_width_pgf}
+      \@@_interval_draw_solid:
+    }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\timechartlegendstartrange,\timechartlegendfinishrange}
+%   Draw a bar with start/finish range, suitable for use in a legend, applying style in \param{1}.
+%    \begin{macrocode}
+\NewDocumentCommand{\timechartlegendstartrange}{ O{} }
+  {
+    \@@_legend_aux:nn{#1}{
+      \pgfmathsetlengthmacro{\l_@@_start_extreme_x}{0}
+      \pgfmathsetlengthmacro{\l_@@_start_solid_x}
+        {\pgfkeysvalueof{/timechart/legend~item~range~width}}
+      \pgfmathsetlengthmacro{\l_@@_finish_solid_x}
+        {\l_@@_legenditem_width_pgf}
+      \int_case:nn {\l_@@_start_range_type_int}
+        {
+          {0}{ \@@_interval_start_range_fade: }
+          {1}{ \@@_interval_start_range_slant: }
+        }
+      \@@_interval_draw_solid:
+    }
+  }
+\NewDocumentCommand{\timechartlegendfinishrange}{ O{} }
+  {
+    \@@_legend_aux:nn{#1}{
+      \pgfmathsetlengthmacro{\l_@@_start_solid_x}{0}
+      \pgfmathsetlengthmacro{\l_@@_finish_solid_x}
+        {
+          \l_@@_legenditem_width_pgf
+          -\pgfkeysvalueof{/timechart/legend~item~range~width}
+        }
+      \pgfmathsetlengthmacro{\l_@@_finish_extreme_x}
+        {\l_@@_legenditem_width_pgf}
+      \int_case:nn {\l_@@_finish_range_type_int}
+        {
+          {0}{ \@@_interval_finish_range_fade: }
+          {1}{ \@@_interval_finish_range_slant: }
+        }
+      \@@_interval_draw_solid:
+    }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_legend_aux:nn}
+%   Auxiliary command for legend items. Draw a \TikZ\ picture, applying PGF keys \param{1} under \key{/timechart/}
+%   and using \TikZ\ code \param{2}.
+%    \begin{macrocode}
+\cs_new:Npn\@@_legend_aux:nn #1#2
+  {
+    \tikzpicture
+%    \end{macrocode}
+%   Process supplied PGF keys and retrieve only those necessary.
+%    \begin{macrocode}
+    \pgfkeys{
+      /timechart/.cd,
+      #1,
+      interval~bar~thickness/.get=\l_@@_bar_thickness_pgf,
+      interval~bar~color/.get=\l_@@_bar_color,
+      interval~minimum~width/.get=\l_@@_minimum_width_pgf,
+      beyond~length/.get=\l_@@_beyond_length_pgf,
+      legend~item~width/.get=\l_@@_legenditem_width_pgf,
+    }
+    \pgfmathsetlengthmacro{\l_@@_bar_half_thickness_pgf}
+      {.5*\l_@@_bar_thickness_pgf}
+    \pgfmathsetmacro{\l_@@_start_x}{0}
+    \pgfmathsetmacro{\l_@@_finish_x}
+      {\l_@@_legenditem_width_pgf}
+    \pgfmathsetlengthmacro{\l_@@_start_beyond_x}
+      {\l_@@_start_x-\l_@@_beyond_length_pgf}
+    \pgfmathsetlengthmacro{\l_@@_finish_beyond_x}
+      {\l_@@_finish_x+\l_@@_beyond_length_pgf}
+    \pgfmathsetmacro{\l_@@_current_y}{0}
+%    \end{macrocode}
+%   Ensure that the legend is `visible' from the perspective of the drawing macros.
+%    \begin{macrocode}
+    \pgfmathsetmacro{\l_@@_start_tolerance_x}
+      {\l_@@_start_x-10mm}
+    \pgfmathsetmacro{\l_@@_finish_tolerance_x}
+      {\l_@@_finish_x+10mm}
+    #2
+%    \end{macrocode}
+%   Make sure that the legend has the required bounding box.
+%    \begin{macrocode}
+    \pgfresetboundingbox
+    \pgfmoveto{
+      \pgfpoint{0}{-\l_@@_bar_half_thickness_pgf}
+    }
+    \pgfmoveto{
+      \pgfpoint
+        {\l_@@_legenditem_width_pgf}
+        {\l_@@_bar_half_thickness_pgf}
+    }
+    \endtikzpicture%
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%
+%
+%    \begin{macrocode}
+%</package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex


Property changes on: trunk/Master/texmf-dist/source/latex/timechart/timechart.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/source/latex/timechart/timechart.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/timechart/timechart.ins	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/timechart/timechart.ins	2025-02-15 21:28:35 UTC (rev 74010)
@@ -0,0 +1,38 @@
+%%
+%% Copyright (C) 2025 Alan J. Cain
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public Licence, either
+%% version 1.3 of this licence or (at your option) any later
+%% version. The latest version of this licence is in:
+%%
+%%    http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%%
+\input l3docstrip.tex
+\askforoverwritefalse
+\nopostamble
+
+\preamble
+
+This is a generated file.
+
+Copyright (C) 2025 Alan J. Cain
+
+This file may be distributed and/or modified under the
+conditions of the LaTeX Project Public Licence, either
+version 1.3 of this licence or (at your option) any later
+version. The latest version of this licence is in:
+
+http://www.latex-project.org/lppl.txt
+
+and version 1.3c or later is part of all distributions of
+LaTeX version 2008-05-04 or later.
+
+\endpreamble
+
+\generate{\file{timechart.sty}{\from{timechart.dtx}{package}}}
+
+\endbatchfile

Added: trunk/Master/texmf-dist/tex/latex/timechart/timechart.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/timechart/timechart.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/timechart/timechart.sty	2025-02-15 21:28:35 UTC (rev 74010)
@@ -0,0 +1,1615 @@
+%%
+%% This is file `timechart.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% timechart.dtx  (with options: `package')
+%% 
+%% This is a generated file.
+%% 
+%% Copyright (C) 2025 Alan J. Cain
+%% 
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public Licence, either
+%% version 1.3 of this licence or (at your option) any later
+%% version. The latest version of this licence is in:
+%% 
+%% http://www.latex-project.org/lppl.txt
+%% 
+%% and version 1.3c or later is part of all distributions of
+%% LaTeX version 2008-05-04 or later.
+%% 
+\NeedsTeXFormat{LaTeX2e}[2020-02-02]
+\ProvidesExplPackage{timechart}{2025-02-15}{0.51}
+  {Typesetting chronological charts}
+\RequirePackage{tikz}
+\bool_new:N\l__timechart_tmpa_bool
+\bool_new:N\l__timechart_tmpb_bool
+\bool_new:N\l__timechart_tmpc_bool
+\bool_new:N\l__timechart_tmpd_bool
+\cs_set_eq:NN\l__timechart_tmpa_dim\l_tmpa_dim
+\cs_set_eq:NN\l__timechart_tmpb_dim\l_tmpb_dim
+\dim_new:N\l__timechart_tmpc_dim
+\dim_new:N\l__timechart_tmpd_dim
+\cs_new:Npn\__timechart_make_ref:NN #1#2
+  {
+    \str_if_empty:NTF #1
+      { #2 }
+      { \hyperref[#1]{#2} }
+  }
+\cs_new:Npn\__timechart_pgfmathsetbool:nn #1#2
+  {
+    \pgfmathsetmacro{#1}{ifthenelse(#2,"\c_true_bool","\c_false_bool")}
+  }
+\cs_new:Npn\__timechart_if_equal:nnF #1#2#3
+  {
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{#1==#2}
+    \bool_if:NF\l__timechart_tmpa_bool{#3}
+  }
+\cs_new:Npn\__timechart_pgfextractxy:nnn #1#2#3
+  {
+    \pgf at process{#3}
+    #1=\pgf at x\relax
+    #2=\pgf at y\relax
+  }
+\cs_new:Npn\__timechart_hsmash_pgfnode:nnnnn #1#2#3#4#5
+  {
+    \pgfinterruptboundingbox
+    \pgfnode{#1}{#2}{#3}{#4}{#5}
+    \pgfcoordinate
+      {__timechart_tmpa_coord}
+      {\pgfpointanchor{current~bounding~box}{south}}
+    \pgfcoordinate
+      {__timechart_tmpb_coord}
+      {\pgfpointanchor{current~bounding~box}{north}}
+    \endpgfinterruptboundingbox
+    \pgfextractx
+      {\l__timechart_tmpa_dim}
+      {\pgfpointanchor{__timechart_tmpa_coord}{center}}
+    \pgfextractx
+      {\l__timechart_tmpb_dim}
+      {\pgfpointanchor{__timechart_tmpb_coord}{center}}
+    \pgfpathmoveto{\pgfpoint{\l__timechart_tmpa_dim}{0}}
+    \pgfpathmoveto{\pgfpoint{\l__timechart_tmpb_dim}{0}}
+    \pgfusepath{discard}
+  }
+\cs_new:Npn\__timechart_make_rectangle_node:nnnn #1#2#3#4
+  {
+    \group_begin:
+    \__timechart_pgfextractxy:nnn
+      {\l__timechart_tmpa_dim}{\l__timechart_tmpb_dim}{#1}
+    \__timechart_pgfextractxy:nnn
+      {\l__timechart_tmpc_dim}{\l__timechart_tmpd_dim}{#2}
+    \pgftransformshift{#1}
+    \pgfset{
+      minimum~width=\l__timechart_tmpc_dim-\l__timechart_tmpa_dim,
+      minimum~height=\l__timechart_tmpd_dim-\l__timechart_tmpb_dim,
+      inner~sep=0,
+      outer~sep=0,
+    }
+    \bool_if:NTF #4
+      { \pgfnode{rectangle}{south~west}{}{#3}{\pgfusepath{draw}} }
+      { \pgfnode{rectangle}{south~west}{}{#3}{\pgfusepath{discard}} }
+    \group_end:
+  }
+\pgfmathsetmacro{\l__timechart_left_nonclip_x}{-16000pt}
+\pgfmathsetmacro{\l__timechart_right_nonclip_x}{16000pt}
+\cs_new:Npn\__timechart_set_style_line_width:nn #1#2
+  {
+    \begingroup
+    \tikzset{#2}
+    \pgfmathsetlengthmacro{#1}{\pgflinewidth}
+    \pgfmathsmuggle #1
+    \endgroup
+  }
+\pgfkeys{
+  /timechart/.cd,
+  width/.initial=\textwidth,
+  tolerance/.initial=5pt,
+  beyond~length/.initial=5pt,
+  beyond~x~radius/.initial=4pt,
+  ystep/.initial=-10pt,
+  minor~tick~interval/.initial=10,
+  major~tick~interval/.initial=50,
+  no~grid/.code = { \bool_set_false:N\l__timechart_grid_bool },
+  grid~top~ysep/.initial={3pt},
+  grid~bottom~ysep/.initial={3pt},
+  grid/.style={},
+  no~axis/.code = { \bool_set_false:N\l__timechart_axis_bool },
+  axis~line/.style={
+    line~cap=rect,
+  },
+  axis~ysep/.initial=3pt,
+  minor~tick/.style={},
+  minor~tick~length/.initial=1.5mm,
+  major~tick/.style={},
+  major~tick~length/.initial=3mm,
+  major~tick~label/.style={
+    inner~sep=0,
+    outer~sep=0,
+    anchor=mid~west,
+    rotate=90,
+  },
+  no~autostep/.code = { \bool_set_false:Nz\l__timechart_autostep_bool },
+  ref/.initial={},
+  mark/.initial={},
+  marks/.forward~to=/timechart/mark,
+  circa~uncertainty/.initial=3,
+  interval~minimum~width/.initial=1pt,
+  interval~bar~color/.initial=black,
+  interval~bar~thickness/.initial=8pt,
+  interval~bar~node~name/.initial = {bar~node},
+  interval~mark~color/.initial=gray,
+  interval~label/.style={},
+  interval~label~centered/.style={/timechart/interval~label,text=white},
+  interval~label~centered~background/.style={/timechart/interval~label},
+  interval~label~baseline/.initial=-3pt,
+  interval~label~pos/.is~choice,
+  interval~label~pos/left/.code
+    = { \int_set:Nn\l__timechart_label_pos_int{0} },
+  interval~label~pos/center/.code
+    = { \int_set:Nn\l__timechart_label_pos_int{1} },
+  interval~label~pos/right/.code
+    = { \int_set:Nn\l__timechart_label_pos_int{2} },
+  interval~label~node~name/.initial = {label~node},
+  start~range/.is~choice,
+  start~range/fade/.code
+    = { \int_set:Nn\l__timechart_start_range_type_int{0} },
+  start~range/slant/.code
+    = { \int_set:Nn\l__timechart_start_range_type_int{1} },
+  finish~range/.is~choice,
+  finish~range/fade/.code
+    = { \int_set:Nn\l__timechart_finish_range_type_int{0} },
+  finish~range/slant/.code
+    = { \int_set:Nn\l__timechart_finish_range_type_int{1} },
+  fade~minimum~width/.initial = 0pt,
+  text~node~name/.initial = {text~node},
+  text/.style={},
+  text~baseline/.initial=-3pt,
+  text~pos/.is~choice,
+  text~pos/left/.code = { \int_set:Nn\l__timechart_text_pos_int{0} },
+  text~pos/center/.code = { \int_set:Nn\l__timechart_text_pos_int{1} },
+  text~pos/right/.code = { \int_set:Nn\l__timechart_text_pos_int{2} },
+  legend~item~width/.initial=9mm,
+  legend~item~range~width/.initial=3mm,
+  left/.code = {
+    \int_set:Nn\l__timechart_label_pos_int{0}
+    \int_set:Nn\l__timechart_text_pos_int{0}
+  },
+  center/.code = {
+    \int_set:Nn\l__timechart_label_pos_int{1}
+    \int_set:Nn\l__timechart_text_pos_int{1}
+  },
+  right/.code = {
+    \int_set:Nn\l__timechart_label_pos_int{2}
+    \int_set:Nn\l__timechart_text_pos_int{2}
+  },
+}
+\bool_new:N\l__timechart_grid_bool
+\bool_set_true:N\l__timechart_grid_bool
+\bool_new:N\l__timechart_axis_bool
+\bool_set_true:N\l__timechart_axis_bool
+\bool_new:N\l__timechart_autostep_bool
+\bool_set_true:N\l__timechart_autostep_bool
+\int_new:N \l__timechart_label_pos_int
+\int_new:N \l__timechart_text_pos_int
+\int_new:N \l__timechart_start_range_type_int
+\int_new:N \l__timechart_finish_range_type_int
+\NewDocumentEnvironment{timechart}{ O{} m m }
+  { \__timechart_main_begin:nnn{#1}{#2}{#3} }
+  { \__timechart_main_end: }
+\cs_new:Npn \__timechart_main_begin:nnn #1#2#3
+  {
+    \pgfkeys{
+      /timechart/.cd,
+      #1,
+      width/.get=\l__timechart_width_pgf,
+      tolerance/.get=\l__timechart_tolerance_pgf,
+      ystep/.get=\l__timechart_ystep_pgf,
+      grid~top~ysep/.get=\l__timechart_grid_top_ysep_pgf,
+      grid~bottom~ysep/.get=\l__timechart_grid_bottom_ysep_pgf,
+      beyond~length/.get=\l__timechart_beyond_length_pgf,
+      beyond~x~radius/.get=\l__timechart_beyond_x_radius_pgf,
+      minor~tick~interval/.get=\l__timechart_minor_tick_interval_year,
+      major~tick~interval/.get=\l__timechart_major_tick_interval_year,
+    }
+    \tikzpicture
+    \pgfdeclarelayer{grid}
+    \pgfdeclarelayer{labelbg}
+    \pgfsetlayers{grid,labelbg,main}
+    \bool_if:NTF\l__timechart_grid_bool
+      {
+        \__timechart_set_style_line_width:nn
+          {\l__timechart_grid_line_width}
+          {/timechart/grid}
+      }
+      { \pgfmathsetlengthmacro{\l__timechart_grid_line_width}{0} }
+    \bool_if:NTF\l__timechart_axis_bool
+      {
+        \__timechart_set_style_line_width:nn
+          {\l__timechart_axis_line_width}
+          {/timechart/axis~line}
+        \__timechart_set_style_line_width:nn
+          {\l__timechart_major_tick_line_width}
+          {/timechart/major~tick}
+        \__timechart_set_style_line_width:nn
+          {\l__timechart_minor_tick_line_width}
+          {/timechart/minor~tick}
+      }
+      {
+        \pgfmathsetlengthmacro{\l__timechart_axis_line_width}{0}
+        \pgfmathsetlengthmacro{\l__timechart_major_tick_line_width}{0}
+        \pgfmathsetlengthmacro{\l__timechart_minor_tick_line_width}{0}
+      }
+    \__timechart_parse_date:NNn\l_tmpa_bool\l__timechart_start_year{#2}
+    \__timechart_parse_date:NNn\l_tmpa_bool\l__timechart_finish_year{#3}
+    \pgfmathsetmacro{\l__timechart_start_year}
+      {floor(\l__timechart_start_year)}
+    \pgfmathsetmacro{\l__timechart_finish_year}
+      {floor(\l__timechart_finish_year)}
+    \pgfmathsetmacro{\l__timechart_x}
+      {
+        (
+          \l__timechart_width_pgf
+          - max(
+            \l__timechart_grid_line_width,
+            \l__timechart_axis_line_width,
+            \l__timechart_major_tick_line_width,
+            \l__timechart_minor_tick_line_width
+          )
+        )/(\l__timechart_finish_year-\l__timechart_start_year)
+      }
+    \pgfkeys{
+      /pgf/declare~function={
+        yeartox(\n)=\l__timechart_x*(\n-\l__timechart_start_year);
+      },
+    }
+    \pgfmathsetmacro{\l__timechart_start_x}
+      {yeartox(\l__timechart_start_year)}
+    \pgfmathsetmacro{\l__timechart_finish_x}
+      {yeartox(\l__timechart_finish_year)}
+    \pgfmathsetmacro{\l__timechart_start_tolerance_x}{
+      \l__timechart_start_x-(\l__timechart_tolerance_pgf)
+    }
+    \pgfmathsetmacro{\l__timechart_finish_tolerance_x}{
+      \l__timechart_finish_x+(\l__timechart_tolerance_pgf)
+    }
+    \pgfmathsetmacro{\l__timechart_start_beyond_x}{
+      \l__timechart_start_x-(\l__timechart_beyond_length_pgf)
+    }
+    \pgfmathsetmacro{\l__timechart_finish_beyond_x}{
+      \l__timechart_finish_x+(\l__timechart_beyond_length_pgf)
+    }
+    \pgfmathsetmacro{\l__timechart_current_y}{0}
+    \pgfmathsetmacro{\l__timechart_saved_y}{0}
+    \pgfmathsetmacro{\l__timechart_auto_reset_minimum_y}{-16000pt}
+    \pgfmathsetmacro{\l__timechart_auto_reset_maximum_y}{16000pt}
+    \pgfmathsetmacro{\l__timechart_start_plus_year}{
+      \l__timechart_start_year+\l__timechart_minor_tick_interval_year
+    }
+    \pgfmathsetmacro{\l__timechart_start_plusplus_year}{
+      \l__timechart_start_year+(2*\l__timechart_minor_tick_interval_year)
+    }
+    \pgfmathsetmacro{\l__timechart_end_minus_year}{
+      \l__timechart_finish_year-\l__timechart_minor_tick_interval_year
+    }
+    \group_begin:
+    \cs_set_eq:NN\timechartinterval\__timechart_interval_user:Ommm
+    \cs_set_eq:NN\timecharttext\__timechart_text_user:Omm
+    \cs_set_eq:NN\timechartspace\__timechart_space_user:O
+    \cs_set_eq:NN\timechartsety\__timechart_set_y_user:m
+    \cs_set_eq:NN\timechartsavey\__timechart_save_y_user:
+    \cs_set_eq:NN\timechartresety\__timechart_reset_y_user:
+    \cs_set_eq:NN\timechartsetyminimumautoreset
+      \__timechart_set_y_minimum_auto_reset_user:m
+    \cs_set_eq:NN\timechartsetymaximumautoreset
+      \__timechart_set_y_maximum_auto_reset_user:m
+    \cs_set_eq:NN\timechartstepy\__timechart_step_y_user:O
+    \cs_set_eq:NN\timechartfinish\__timechart_main_end_user:
+  }
+\cs_new:Npn\__timechart_main_end:
+  {
+    \cs_if_eq:NNT\timechartfinish\__timechart_main_end_user:
+      { \__timechart_main_end_user: }
+    \endtikzpicture
+  }
+\cs_new:Npn\__timechart_main_end_user:
+  {
+    \pgfextracty{\l__timechart_tmpa_dim}
+      { \pgfpointanchor{current~bounding~box}{south} }
+    \pgfextracty{\l__timechart_tmpb_dim}
+      { \pgfpointanchor{current~bounding~box}{north} }
+    \pgfresetboundingbox
+    \dim_compare:nNnTF{\l__timechart_tmpa_dim}>{\l__timechart_tmpb_dim}
+      {
+        \pgfmathsetmacro{\l__timechart_content_bottom_y}{0pt}
+        \pgfmathsetmacro{\l__timechart_content_top_y}{0pt}
+      }
+      {
+        \pgfmathsetmacro{\l__timechart_content_bottom_y}
+          {\l__timechart_tmpa_dim}
+        \pgfmathsetmacro{\l__timechart_content_top_y}
+          {\l__timechart_tmpb_dim}
+      }
+    \bool_if:NTF{\l__timechart_grid_bool}
+      {
+        \__timechart_grid_draw:
+        \pgfmathsetmacro{\l__timechart_axis_y}
+          {
+            \l__timechart_content_top_y
+            + \l__timechart_grid_top_ysep_pgf
+            + \pgfkeysvalueof{/timechart/axis~ysep}
+          }
+      }
+      {
+        \__timechart_nogrid_bounding_box_set:
+        \pgfmathsetmacro{\l__timechart_axis_y}
+          {
+            \l__timechart_content_top_y
+            +\pgfkeysvalueof{/timechart/axis~ysep}
+          }
+      }
+    \bool_if:NT{\l__timechart_axis_bool}
+      { \__timechart_axis_draw: }
+    \group_end:
+  }
+\cs_new:Npn\__timechart_grid_draw:
+  {
+    \pgfmathsetmacro{\l__timechart_grid_bottom_y}{
+      \l__timechart_content_bottom_y-\l__timechart_grid_bottom_ysep_pgf
+    }
+    \pgfmathsetmacro{\l__timechart_grid_top_y}{
+      \l__timechart_content_top_y+\l__timechart_grid_top_ysep_pgf
+    }
+    \pgfonlayer{ grid }
+    \scope[/timechart/grid]
+    \foreach \year in {
+      \l__timechart_start_plus_year,
+      \l__timechart_start_plusplus_year,
+      ...,
+      \l__timechart_end_minus_year
+    } {
+      \group_begin:
+      \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+        { Mod(\year,\l__timechart_major_tick_interval_year)==0 }
+      \bool_if:NT\l__timechart_tmpa_bool
+        {
+          \pgftransformshift{ \pgfpoint{yeartox(\year)}{0} }
+          \pgfpathmoveto{ \pgfpoint{0}{\l__timechart_grid_top_y} }
+          \pgfpathlineto{ \pgfpoint{0}{\l__timechart_grid_bottom_y} }
+          \pgfusepath{ draw }
+        }
+      \group_end:
+    }
+    \__timechart_make_rectangle_node:nnnn
+      { \pgfpoint{\l__timechart_start_x}{\l__timechart_grid_bottom_y} }
+      { \pgfpoint{\l__timechart_finish_x}{\l__timechart_grid_top_y} }
+      { grid }
+      { \c_true_bool }
+    \endscope
+    \endpgfonlayer
+  }
+\cs_new:Npn\__timechart_axis_draw:
+  {
+    \group_begin:
+    \pgfkeys{
+      /timechart/minor~tick~length/.get=\__timechart_minor_tick_length_pgf,
+      /timechart/major~tick~length/.get=\__timechart_major_tick_length_pgf,
+    }
+    \pgftransformshift{ \pgfpoint{0}{\l__timechart_axis_y} }
+    \pgfmathsetmacro{\__timechart_start_major_tick_year}
+      {
+        \l__timechart_start_year
+        -Mod(
+          \l__timechart_start_year,
+          \l__timechart_major_tick_interval_year
+        )
+      }
+    \pgfmathsetmacro{\__timechart_start_major_tick_year}
+      {
+        ifthenelse(
+          \__timechart_start_major_tick_year<\l__timechart_start_year,
+          \__timechart_start_major_tick_year
+            +\l__timechart_major_tick_interval_year,
+          \__timechart_start_major_tick_year
+        )
+      }
+    \pgfmathsetmacro{\__timechart_finish_major_tick_year}
+      {
+        \l__timechart_finish_year
+        -Mod(
+          \l__timechart_finish_year,
+          \l__timechart_major_tick_interval_year
+        )
+      }
+    \foreach \year in {
+      \l__timechart_start_year,
+      \l__timechart_start_plus_year,
+      ...,
+      \l__timechart_finish_year
+    } {
+      \pgfmathsetmacro{\x}{yeartox(\year)}
+      \__timechart_pgfmathsetbool:nn
+        {\l__timechart_tmpa_bool}
+        { Mod(\year,\l__timechart_major_tick_interval_year)==0 }
+      \bool_if:NTF\l__timechart_tmpa_bool
+        { \__timechart_axis_draw_labelled_major_tick:NN\x\year }
+        { \__timechart_axis_draw_minor_tick:N\x }
+    }
+    \__timechart_draw_axis_line
+    \pgfextracty{\l__timechart_tmpa_dim}
+      { \pgfpointanchor{current~bounding~box}{north} }
+    \__timechart_make_rectangle_node:nnnn
+      { \pgfpoint{\l__timechart_start_x}{0} }
+      { \pgfpoint{\l__timechart_finish_x}{\l__timechart_tmpa_dim} }
+      { axis }
+      { \c_false_bool }
+    \group_end:
+  }
+\cs_new:Npn\__timechart_axis_draw_minor_tick:N #1
+  {
+    \scope[/timechart/minor~tick]
+    \pgfpathmoveto{ \pgfpoint{#1}{0} }
+    \pgfpathlineto{ \pgfpoint{#1}{\__timechart_minor_tick_length_pgf} }
+    \pgfusepath{draw}
+    \endscope
+  }
+\cs_new:Npn\__timechart_axis_draw_labelled_major_tick:NN #1#2
+  {
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{#2==0}
+    \bool_if:NTF \l__timechart_tmpa_bool
+      { \__timechart_axis_draw_zero_tick:N #1 }
+      {
+        \__timechart_pgfmathsetbool:nn{\l__timechart_tmpb_bool}
+          { #2==\__timechart_start_major_tick_year }
+        \__timechart_pgfmathsetbool:nn{\l__timechart_tmpc_bool}
+          { #2==\__timechart_finish_major_tick_year }
+        \bool_set:Nn\l__timechart_tmpd_bool
+          { \l__timechart_tmpb_bool || \l__timechart_tmpc_bool }
+        \__timechart_axis_draw_major_tick:N #1
+        \__timechart_axis_draw_year_label:nnnnnn
+          { #1 }
+          { #2 }
+          { \l__timechart_tmpd_bool }
+          { mid~west }
+          { 0 }
+          { \__timechart_major_tick_length_pgf+1mm }
+      }
+  }
+\cs_new:Npn\__timechart_axis_draw_major_tick:N #1
+  {
+    \scope[/timechart/major~tick]
+    \pgfpathmoveto{ \pgfpoint{#1}{0} }
+    \pgfpathlineto{ \pgfpoint{#1}{\__timechart_major_tick_length_pgf} }
+    \pgfusepath{draw}
+    \endscope
+  }
+\cs_new:Npn\__timechart_axis_draw_zero_tick:N #1
+  {
+    \group_begin:
+    \pgftransformshift{ \pgfpoint{#1}{0} }
+    \pgfmathsetmacro{\a}{5}
+    \pgfmathsetlengthmacro{\r}{1mm}
+    \pgfmathsetlengthmacro{\t}{\r*(cos(\a)-cos(90-\a))/(1-cos(90-\a))}
+    \scope[/timechart/major~tick,line~join=miter]
+    \pgfpathmoveto{\pgfpointorigin}
+    \pgfpathlineto{\pgfpoint{0}{\__timechart_major_tick_length_pgf}}
+    \pgfpatharc{0}{90-\a}{\t~and~\r}
+    \pgfpatharc{270+\a}{360-\a}{\r}
+    \pgfpatharc{180+\a}{270-\a}{\r}
+    \pgfpatharc{90+\a}{180-\a}{\t~and~\r}
+    \pgfpathlineto{\pgfpoint{0}{\__timechart_major_tick_length_pgf-1pt}}
+    \pgfusepath{draw}
+    \endscope
+    \__timechart_axis_draw_year_label:nnnnnn
+      { 0 }
+      { -1 }
+      { \c_true_bool }
+      { base~west }
+      { -.5mm }
+      { 5.5mm }
+    \__timechart_axis_draw_year_label:nnnnnn
+      { 0 }
+      { 1 }
+      { \c_true_bool }
+      { north~west }
+      { .5mm }
+      { 5.5mm }
+    \group_end:
+  }
+\cs_new:Npn\__timechart_draw_axis_line
+  {
+    \scope[/timechart/axis~line]
+    \pgfpathmoveto{ \pgfpoint{\l__timechart_start_x}{0} }
+    \pgfpathlineto{ \pgfpoint{\l__timechart_finish_x}{0} }
+    \pgfusepath{draw}
+    \endscope
+  }
+\cs_new:Npn\__timechart_axis_draw_year_label:nnnnnn #1#2#3#4#5#6
+  {
+    \group_begin:
+    \pgftransformshift{ \pgfpoint{#1+#5}{#6} }
+    \pgfmathtruncatemacro{\absyear}{ abs(#2) }
+    \scope[/timechart/major~tick~label]
+    \bool_if:NTF #3
+      {
+        \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{#2<0}
+        \bool_if:NTF\l__timechart_tmpa_bool
+          { \cs_set_eq:NN\__timechart_make_year:n\timechartmakebeforeyear }
+          { \cs_set_eq:NN\__timechart_make_year:n\timechartmakeafteryear  }
+        \__timechart_hsmash_pgfnode:nnnnn
+          {rectangle}
+          {#4}
+          {\__timechart_make_year:n{\absyear}}
+          {}
+          {}
+      }
+      { \pgfnode{rectangle}{#4}{\absyear}{}{} }
+    \endscope
+    \group_end:
+  }
+\cs_new:Npn\timechartmakebeforeyear #1
+  {
+    #1\nobreakspace\textsc{bce}
+  }
+\cs_new:Npn\timechartmakeafteryear #1
+  {
+    #1\nobreakspace\textsc{ce}
+  }
+\cs_new:Npn\__timechart_nogrid_bounding_box_set:
+  {
+    \pgfpathmoveto
+      { \pgfpoint{\l__timechart_start_x}{\l__timechart_content_bottom_y} }
+    \pgfpathmoveto
+      { \pgfpoint{\l__timechart_finish_x}{\l__timechart_content_top_y} }
+    \pgfusepath{discard}
+  }
+\cs_new:Npn\__timechart_set_y_user:m #1
+  {
+    \pgfmathsetmacro{\l__timechart_current_y}{#1}
+  }
+\cs_new:Npn\__timechart_save_y_user:
+  {
+    \pgfmathsetmacro{\l__timechart_saved_y}{\l__timechart_current_y}
+  }
+\cs_new:Npn\__timechart_reset_y_user:
+  {
+    \pgfmathsetmacro{\l__timechart_current_y}{\l__timechart_saved_y}
+  }
+\cs_new:Npn\__timechart_set_y_minimum_auto_reset_user:m #1
+  {
+    \pgfmathsetmacro{\l__timechart_auto_reset_minimum_y}{#1}
+  }
+\cs_new:Npn\__timechart_set_y_maximum_auto_reset_user:m #1
+  {
+    \pgfmathsetmacro{\l__timechart_auto_reset_maximum_y}{#1}
+  }
+\NewDocumentCommand{\__timechart_step_y_user:O}{ O{1} }
+  {
+    \pgfmathsetmacro{\l__timechart_current_y}
+      {\l__timechart_current_y+#1*\l__timechart_ystep_pgf}
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+      {
+        or(
+          \l__timechart_current_y<\l__timechart_auto_reset_minimum_y,
+          \l__timechart_current_y>\l__timechart_auto_reset_maximum_y
+        )
+      }
+    \bool_if:nT{\l__timechart_tmpa_bool}
+      { \pgfmathsetmacro{\l__timechart_current_y}{\l__timechart_saved_y)} }
+  }
+\cs_new:Npn\__timechart_if_x_in_bounds:nT #1#2
+  {
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{
+      and(
+        #1>=\l__timechart_start_x,
+        #1<=\l__timechart_finish_x
+      )
+    }
+    \bool_if:NT\l__timechart_tmpa_bool
+      {#2}
+  }
+
+\cs_new:Npn\__timechart_if_x_in_tolerance_bounds:nT #1#2
+  {
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{
+      and(
+        #1>=\l__timechart_start_tolerance_x,
+        #1<=\l__timechart_finish_tolerance_x
+      )
+    }
+    \bool_if:NT\l__timechart_tmpa_bool{#2}
+  }
+\cs_new:Npn\__timechart_if_x_range_intersect_tolerance_bounds:nnT #1#2#3
+  {
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}{
+      or(
+        or(
+          and(
+            #2>=\l__timechart_start_tolerance_x,
+            #2<=\l__timechart_finish_tolerance_x
+          ),
+          and(
+            #1>=\l__timechart_start_tolerance_x,
+            #1<=\l__timechart_finish_tolerance_x
+          )
+        ),
+        and(
+          #1<\l__timechart_start_tolerance_x,
+          #2>\l__timechart_finish_tolerance_x
+        )
+      )
+    }
+    \bool_if:NT\l__timechart_tmpa_bool
+      {#3}
+  }
+\cs_new:Npn\__timechart_parse_date_or_daterange:NNNNNn #1#2#3#4#5#6
+{
+  \bool_set:Nn #1 {\__timechart_is_nondaterange_p:w #6/\q_stop}
+  \bool_set_inverse:N #1
+  \bool_if:nTF #1
+    { \__timechart_parse_range:w #2#3#4#5\q_mark #6\q_stop }
+    {
+      \__timechart_parse_date:NNn #2#3{#6}
+      \bool_set_eq:NN #4#2
+      \pgfmathsetmacro{#5}{#3}
+    }
+}
+\cs_new:Npn\__timechart_is_nondaterange_p:w #1/#2\q_stop
+{
+  \tl_if_empty_p:n{#2}
+}
+\cs_new:Npn\__timechart_parse_range:w #1#2#3#4\q_mark #5/#6\q_stop
+{
+  \__timechart_parse_date:NNn #1#2{#5}
+  \__timechart_parse_date:NNn #3#4{#6}
+}
+\cs_new:Npn\__timechart_parse_date:NNn #1#2#3
+{
+  \bool_set:Nn #1 { \__timechart_is_circa_p:w #3c\q_stop }
+  \bool_if:NTF #1
+    { \__timechart_parse_circa_date:w #2\q_mark #3\q_stop }
+    { \__timechart_parse_noncirca_date:Nn #2{#3} }
+}
+\cs_new:Npn\__timechart_is_circa_p:w #1c#2\q_stop
+{
+  \tl_if_empty_p:n{#1}
+}
+\cs_new:Npn\__timechart_parse_circa_date:w #1\q_mark c#2\q_stop
+{
+  \__timechart_parse_noncirca_date:Nn #1{#2}
+}
+\cs_new:Npn\__timechart_parse_noncirca_date:Nn #1#2
+{
+  \bool_if:nTF { \__timechart_is_before_p:w #2-\q_stop }
+    { \__timechart_parse_before_date:w #1\q_mark #2\q_stop }
+    { \__timechart_parse_signed_date:w #1\q_mark #2-0-0\q_stop }
+}
+\cs_new:Npn\__timechart_is_before_p:w #1-#2\q_stop
+{
+  \tl_if_empty_p:n{#1}
+}
+\cs_new:Npn\__timechart_parse_before_date:w #1\q_mark-#2\q_stop
+{
+  \__timechart_parse_signed_date:w #1-\q_mark #2-0-0\q_stop
+}
+\cs_new:cpn{c__timechart_year_days_pgf}{365}
+\cs_new:cpn{c__timechart_month_days_1_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_2_pgf}{28}
+\cs_new:cpn{c__timechart_month_days_3_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_4_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_5_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_6_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_7_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_8_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_9_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_10_pgf}{31}
+\cs_new:cpn{c__timechart_month_days_11_pgf}{30}
+\cs_new:cpn{c__timechart_month_days_12_pgf}{31}
+\cs_new:cpn{c__timechart_cumulative_days_1_pgf}{0}
+\cs_new:cpn{c__timechart_cumulative_days_2_pgf}{31}
+\cs_new:cpn{c__timechart_cumulative_days_3_pgf}{59}
+\cs_new:cpn{c__timechart_cumulative_days_4_pgf}{90}
+\cs_new:cpn{c__timechart_cumulative_days_5_pgf}{120}
+\cs_new:cpn{c__timechart_cumulative_days_6_pgf}{151}
+\cs_new:cpn{c__timechart_cumulative_days_7_pgf}{181}
+\cs_new:cpn{c__timechart_cumulative_days_8_pgf}{212}
+\cs_new:cpn{c__timechart_cumulative_days_9_pgf}{243}
+\cs_new:cpn{c__timechart_cumulative_days_10_pgf}{273}
+\cs_new:cpn{c__timechart_cumulative_days_11_pgf}{304}
+\cs_new:cpn{c__timechart_cumulative_days_12_pgf}{334}
+\cs_new:Npn\__timechart_parse_signed_date:w #1#2\q_mark #3-#4-#5\q_stop
+{
+  \pgfmathtruncatemacro{\__timechart_parsed_year_pgf}{#2#3}
+  \pgfmathtruncatemacro{\__timechart_parsed_month_pgf}{#4}
+  \pgfmathtruncatemacro{\__timechart_parsed_day_pgf}{#5}
+  \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+    or(
+      \__timechart_parsed_month_pgf < 1,
+      \__timechart_parsed_month_pgf > 12,
+    )
+  }
+  \bool_if:NTF\l_tmpa_bool
+  {
+    \pgfmathsetmacro{#1}{#2#3}
+  }
+  {
+    \cs_set_eq:NN\l__timechart_year_days_pgf\c__timechart_year_days_pgf
+    \cs_set_eq:Nc\l__timechart_month_days_pgf
+      { c__timechart_month_days_\__timechart_parsed_month_pgf _pgf }
+    \cs_set_eq:Nc\l__timechart_cumulative_days_pgf
+      { c__timechart_cumulative_days_\__timechart_parsed_month_pgf _pgf }
+    \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+      or(
+        Mod(\__timechart_parsed_year_pgf,400) == 0,
+        and(
+          Mod(\__timechart_parsed_year_pgf,4) == 0,
+          Mod(\__timechart_parsed_year_pgf,100) != 0
+        )
+      )
+    }
+    \bool_if:NT\l_tmpa_bool
+      {
+        \pgfmathsetmacro{\l__timechart_year_days_pgf}
+          { \l__timechart_year_days_pgf+1 }
+        \__timechart_pgfmathsetbool:nn{\l_tmpb_bool}
+          { \__timechart_parsed_month == 1 }
+        \bool_if:NF\l_tmpb_bool
+          {
+            \__timechart_pgfmathsetbool:nn{\l_tmpb_bool}
+              { \__timechart_parsed_month == 2 }
+            \bool_if:NF\l_tmpb_bool
+              {
+                \pgfmathsetmacro{\l__timechart_month_days_pgf}
+                  { \l__timechart_month_days_pgf + 1 }
+              }
+              {
+                \pgfmathsetmacro{\l__timechart_cumulative_days_pgf}
+                  { \l__timechart_cumulative_days_pgf + 1 }
+              }
+          }
+      }
+    \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+      or(
+        \__timechart_parsed_day_pgf < 1,
+        \__timechart_parsed_day_pgf > \l__timechart_month_days_pgf,
+      )
+    }
+    \bool_if:NTF\l_tmpa_bool
+      {
+       \pgfmathsetmacro{#1}
+         {
+           #2#3
+           + \l__timechart_cumulative_days_pgf/\l__timechart_year_days_pgf
+         }
+      }
+      {
+       \pgfmathsetmacro{#1}
+         {
+           #2#3
+           + (
+               \l__timechart_cumulative_days_pgf
+               + \__timechart_parsed_day_pgf
+             )/\l__timechart_year_days_pgf
+         }
+      }
+  }
+}
+\bool_new:N\l__timechart_start_is_range_bool
+\bool_new:N\l__timechart_startmin_circa_bool
+\bool_new:N\l__timechart_startmax_circa_bool
+\bool_new:N\l__timechart_finish_is_range_bool
+\bool_new:N\l__timechart_finishmin_circa_bool
+\bool_new:N\l__timechart_finishmax_circa_bool
+\msg_new:nnn{timechart}{interval_dates_invalid}
+  { Invalid~interval~dates:~#1~to~#2 }
+\NewDocumentCommand{\__timechart_interval_user:Ommm}{ O{} m m m }
+  {
+    \group_begin:
+    \__timechart_parse_date_or_daterange:NNNNNn
+      \l__timechart_start_is_range_bool
+      \l__timechart_startmin_circa_bool\l__timechart_startmin_year
+      \l__timechart_startmax_circa_bool\l__timechart_startmax_year
+      {#2}
+    \__timechart_parse_date_or_daterange:NNNNNn
+      \l__timechart_finish_is_range_bool
+      \l__timechart_finishmin_circa_bool\l__timechart_finishmin_year
+      \l__timechart_finishmax_circa_bool\l__timechart_finishmax_year
+      {#3}
+    \__timechart_pgfmathsetbool:nn{\l_tmpa_bool}{
+      and(
+        \l__timechart_startmin_year <= \l__timechart_startmax_year,
+        and(
+          \l__timechart_startmax_year <= \l__timechart_finishmin_year,
+          \l__timechart_finishmin_year <= \l__timechart_finishmax_year
+        )
+      )
+    }
+    \bool_if:NTF\l_tmpa_bool
+      {
+        \__timechart_interval_checked:nn{#1}{#4}
+        \group_end:
+        \bool_if:NT\l__timechart_autostep_bool
+          { \__timechart_step_y_user:O }
+      }
+      {
+        \msg_error:nnnn{timechart}{interval_dates_invalid}{#2}{#3}
+        \group_end:
+      }
+  }
+\cs_new:Npn \__timechart_interval_checked:nn #1#2
+  {
+    \pgfqkeys{/timechart}{
+      #1,
+      circa~uncertainty/.get=\l__timechart_circa_uncertainty_year
+    }
+    \bool_if:NTF\l__timechart_startmin_circa_bool
+      {
+        \pgfmathsetmacro{\l__timechart_start_extreme_x}
+          { yeartox(\l__timechart_startmin_year
+            - \l__timechart_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l__timechart_start_extreme_x}
+          { yeartox(\l__timechart_startmin_year) }
+      }
+    \bool_if:NTF\l__timechart_finishmax_circa_bool
+      {
+        \pgfmathsetmacro{\l__timechart_finish_extreme_x}
+          { yeartox(\l__timechart_finishmax_year
+            + \l__timechart_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l__timechart_finish_extreme_x}
+          { yeartox(\l__timechart_finishmax_year) }
+      }
+    \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+      {\l__timechart_start_extreme_x}{\l__timechart_finish_extreme_x}
+      { \__timechart_draw_visible_interval:nn{#1}{#2} }
+  }
+\cs_new:Npn\__timechart_draw_visible_interval:nn #1#2
+  {
+    \pgfqkeys{/timechart}{
+      ref/.get=\l__timechart_ref_text,
+      mark/.get=\l__timechart_mark_text,
+      interval~minimum~width/.get=\l__timechart_minimum_width_pgf,
+      interval~bar~color/.get=\l__timechart_bar_color,
+      interval~bar~thickness/.get=\l__timechart_bar_thickness_pgf,
+      interval~mark~color/.get=\l__timechart_mark_color,
+      interval~label~baseline/.get=\l__timechart_text_baseline_pgf,
+      interval~label~node~name/.get=\l__timechart_interval_label_node_name,
+    }
+    \pgfmathsetlengthmacro{\l__timechart_bar_half_thickness_pgf}
+      {.5*\l__timechart_bar_thickness_pgf}
+    \cs_set:Npn\l__timechart_label_text{#2}
+    \bool_if:NTF\l__timechart_startmax_circa_bool
+      {
+        \pgfmathsetmacro{\l__timechart_start_definite_x}
+          { yeartox(\l__timechart_startmax_year
+            + \l__timechart_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l__timechart_start_definite_x}
+          { yeartox(\l__timechart_startmax_year) }
+      }
+    \bool_if:NTF\l__timechart_finishmin_circa_bool
+      {
+        \pgfmathsetmacro{\l__timechart_finish_definite_x}
+          { yeartox(\l__timechart_finishmin_year
+            - \l__timechart_circa_uncertainty_year) }
+      }
+      {
+        \pgfmathsetmacro{\l__timechart_finish_definite_x}
+          { yeartox(\l__timechart_finishmin_year) }
+      }
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+      {
+        \l__timechart_start_definite_x > \l__timechart_finish_definite_x
+      }
+    \bool_if:NT\l__timechart_tmpa_bool
+      {
+        \pgfmathsetmacro{\l__timechart_start_definite_x}
+          {
+            .5*(
+              \l__timechart_start_definite_x
+              + \l__timechart_finish_definite_x
+            )
+          }
+        \pgfmathsetmacro{\l__timechart_finish_definite_x}
+          { \l__timechart_start_definite_x }
+      }
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+      {
+        (\l__timechart_finish_extreme_x-\l__timechart_start_extreme_x)
+        < \l__timechart_minimum_width_pgf
+      }
+    \int_if_zero:nTF
+      {
+        \l__timechart_start_range_type_int
+        + \l__timechart_finish_range_type_int
+      }
+      {
+        \__timechart_pgfmathsetbool:nn{\l__timechart_tmpb_bool}
+          {
+            (
+              \l__timechart_finish_definite_x
+              - \l__timechart_start_definite_x
+            )
+            < \l__timechart_minimum_width_pgf
+          }
+      }
+      { \bool_set_false:N\l__timechart_tmpb_bool }
+    \bool_if:nT{
+      \l__timechart_tmpa_bool || \l__timechart_tmpb_bool
+    }{
+      \pgfmathsetmacro{\l__timechart_width_adjust}
+        { .5*\l__timechart_minimum_width_pgf }
+      \pgfmathsetmacro{\l__timechart_start_definite_x}
+        { \l__timechart_start_definite_x-\l__timechart_width_adjust }
+      \pgfmathsetmacro{\l__timechart_finish_definite_x}
+        { \l__timechart_finish_definite_x+\l__timechart_width_adjust }
+      \pgfmathsetmacro{\l__timechart_start_extreme_x}
+        {
+          min(
+            \l__timechart_start_extreme_x,
+            \l__timechart_start_definite_x
+          )
+        }
+      \pgfmathsetmacro{\l__timechart_finish_extreme_x}
+        {
+          max(
+            \l__timechart_finish_extreme_x,
+            \l__timechart_finish_definite_x
+          )
+        }
+    }
+    \pgfmathsetmacro{\l__timechart_start_solid_x}
+      { \l__timechart_start_definite_x }
+    \pgfmathsetmacro{\l__timechart_finish_solid_x}
+      { \l__timechart_finish_definite_x }
+    \pgftransformshift{ \pgfpoint{0}{\l__timechart_current_y} }
+    \pgfscope
+    \__timechart_interval_beyond_clip:
+    \int_case:nn {\l__timechart_start_range_type_int}
+      {
+        {0}{ \__timechart_interval_start_range_fade: }
+        {1}{ \__timechart_interval_start_range_slant: }
+      }
+    \int_case:nn {\l__timechart_finish_range_type_int}
+      {
+        {0}{ \__timechart_interval_finish_range_fade: }
+        {1}{ \__timechart_interval_finish_range_slant: }
+      }
+    \__timechart_interval_draw_solid:
+    \__timechart_interval_mark:
+    \__timechart_interval_define_bar_node:
+    \endpgfscope
+    \__timechart_interval_label:
+  }
+\cs_new:Npn\__timechart_interval_beyond_clip:
+  {
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+      {\l__timechart_start_extreme_x<=\l__timechart_start_tolerance_x}
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpb_bool}
+      {\l__timechart_finish_extreme_x>=\l__timechart_finish_tolerance_x}
+    \bool_if:nT{ \l__timechart_tmpa_bool || \l__timechart_tmpb_bool }
+      { \__timechart_interval_beyond_clip_aux: }
+  }
+\cs_new:Npn\__timechart_interval_beyond_clip_aux:
+  {
+    \pgfinterruptboundingbox
+    \bool_if:NTF\l__timechart_tmpb_bool
+      {
+        \pgfpathmoveto{
+          \pgfpoint
+            {\l__timechart_finish_beyond_x}
+            {\l__timechart_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_finish_beyond_x}
+            {\l__timechart_bar_half_thickness_pgf}
+        }
+        \pgfpatharc
+          {90}
+          {270}
+          {\l__timechart_beyond_x_radius_pgf
+            ~and~\l__timechart_bar_half_thickness_pgf}
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_finish_beyond_x}
+            {-\l__timechart_bar_thickness_pgf}
+        }
+      }
+      {
+        \pgfpathmoveto{
+          \pgfpoint
+            {\l__timechart_right_nonclip_x}
+            {\l__timechart_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_right_nonclip_x}
+            {-\l__timechart_bar_thickness_pgf}
+        }
+      }
+    \bool_if:NTF\l__timechart_tmpa_bool
+      {
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_start_beyond_x}
+            {-\l__timechart_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_start_beyond_x}
+            {-\l__timechart_bar_half_thickness_pgf}
+        }
+        \pgfpatharc
+          {-90}
+          {90}
+          {\l__timechart_beyond_x_radius_pgf
+            ~and~\l__timechart_bar_half_thickness_pgf}
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_start_beyond_x}
+            {\l__timechart_bar_thickness_pgf}
+        }
+      }
+      {
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_left_nonclip_x}
+            {-\l__timechart_bar_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_left_nonclip_x}
+            {\l__timechart_bar_thickness_pgf}
+        }
+      }
+    \pgfpathclose
+    \pgfusepath{clip}
+    \endpgfinterruptboundingbox
+  }
+\pgfdeclarehorizontalshading{__timechart_fade_in_shading}{4bp}{
+   color(0bp)=(transparent!100);
+   color(1bp)=(transparent!100);
+   color(3bp)=(transparent!0);
+   color(4bp)=(transparent!0)
+}
+\pgfdeclarefading
+  {__timechart_fade_in}
+  {\pgfuseshading{__timechart_fade_in_shading}}
+\cs_new:Npn\__timechart_interval_start_range_fade:
+  {
+    \pgfmathsetlengthmacro{\l__timechart_fade_width_pgf}
+      { \l__timechart_start_solid_x-\l__timechart_start_extreme_x }
+    \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+      { \l__timechart_fade_width_pgf
+        > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+    \bool_if:NT \l__timechart_tmpa_bool
+      {
+        \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+          {\l__timechart_start_extreme_x}{\l__timechart_start_solid_x}
+          {
+            \pgfmathsetmacro{\l__timechart_fade_extra_pgf}
+            {
+              min(
+                .49*\l__timechart_fade_width_pgf,
+                \l__timechart_finish_solid_x-\l__timechart_start_solid_x
+              )
+            }
+            \pgfscope
+            \pgfpathrectanglecorners{
+              \pgfpoint
+                {\l__timechart_start_extreme_x}
+                {-\l__timechart_bar_half_thickness_pgf}
+            }{
+              \pgfpoint
+                {\l__timechart_start_solid_x+\l__timechart_fade_extra_pgf}
+                {\l__timechart_bar_half_thickness_pgf}
+            }
+            \pgfgettransform{\__timechart_transform_current}
+            \pgfsetfading{__timechart_fade_in}{
+              \pgfsettransform{\__timechart_transform_current}
+              \pgftransformshift{
+                \pgfpoint
+                  {
+                    .5*\l__timechart_start_extreme_x
+                    +.5*\l__timechart_start_solid_x
+                  }
+                  {0}
+              }
+              \pgftransformxscale{
+                (\l__timechart_start_solid_x-\l__timechart_start_extreme_x)
+                /2bp
+              }
+              \pgftransformyscale{\l__timechart_bar_thickness_pgf/4bp}
+            }
+            \pgfsetfillcolor{\l__timechart_bar_color}
+            \pgfusepath{fill}
+            \endpgfscope
+          }
+    }
+  }
+\pgfdeclarehorizontalshading{__timechart_fade_out_shading}{4bp}{
+    color(0bp)=(transparent!0);
+   color(1bp)=(transparent!0);
+   color(3bp)=(transparent!100);
+  color(4bp)=(transparent!100)
+}
+\pgfdeclarefading
+  {__timechart_fade_out}
+  {\pgfuseshading{__timechart_fade_out_shading}}
+\cs_new:Npn\__timechart_interval_finish_range_fade:
+  {
+    \pgfmathsetlengthmacro{\l__timechart_fade_width_pgf}
+      { \l__timechart_finish_extreme_x-\l__timechart_finish_solid_x }
+      \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+      { \l__timechart_fade_width_pgf
+        > \pgfkeysvalueof{/timechart/fade~minimum~width} }
+    \bool_if:NT \l__timechart_tmpa_bool
+      {
+        \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+          {\l__timechart_finish_solid_x}{\l__timechart_finish_extreme_x}
+          {
+            \pgfmathsetmacro{\l__timechart_fade_extra_pgf}
+            {
+              min(
+                .49*\l__timechart_fade_width_pgf,
+                \l__timechart_finish_solid_x-\l__timechart_start_solid_x
+              )
+            }
+            \pgfscope
+            \pgfpathrectanglecorners{
+              \pgfpoint
+                {\l__timechart_finish_solid_x-\l__timechart_fade_extra_pgf}
+                {-\l__timechart_bar_half_thickness_pgf}
+            }{
+              \pgfpoint
+                {\l__timechart_finish_extreme_x}
+                {\l__timechart_bar_half_thickness_pgf}
+            }
+            \pgfgettransform{\__timechart_transform_current}
+            \pgfsetfading{__timechart_fade_out}{
+              \pgfsettransform{\__timechart_transform_current}
+              \pgftransformshift{
+                \pgfpoint{
+                  .5*\l__timechart_finish_solid_x
+                  +.5*\l__timechart_finish_extreme_x
+                }
+                {0}
+              }
+              \pgftransformxscale{
+                (\l__timechart_finish_extreme_x-\l__timechart_finish_solid_x)
+                /2bp
+              }
+              \pgftransformyscale{\l__timechart_bar_thickness_pgf/4bp}
+            }
+            \pgfsetfillcolor{\l__timechart_bar_color}
+            \pgfusepath{fill}
+            \endpgfscope
+          }
+    }
+  }
+\cs_new:Npn\__timechart_interval_start_range_slant:
+  {
+    \__timechart_if_equal:nnF
+      {\l__timechart_start_extreme_x}{\l__timechart_start_solid_x}
+      {
+        \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+          {\l__timechart_start_extreme_x}{\l__timechart_start_solid_x}
+          {
+            \pgfinterruptboundingbox
+            \pgfpathmoveto{
+              \pgfpoint
+                {\l__timechart_start_extreme_x}
+                {-\l__timechart_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_start_solid_x}
+                {\l__timechart_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_start_solid_x}
+                {\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_right_nonclip_x}
+                {\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_right_nonclip_x}
+                {-\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_start_extreme_x}
+                {-\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathclose
+            \pgfusepath{clip}
+            \endpgfinterruptboundingbox
+            \pgfmathsetmacro{\l__timechart_start_solid_x}
+              {\l__timechart_start_extreme_x}
+          }
+      }
+  }
+\cs_new:Npn\__timechart_interval_finish_range_slant:
+  {
+    \__timechart_if_equal:nnF
+      {\l__timechart_finish_solid_x}{\l__timechart_finish_extreme_x}
+      {
+        \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+          {\l__timechart_finish_solid_x}{\l__timechart_finish_extreme_x}
+          {
+            \pgfinterruptboundingbox
+            \pgfpathmoveto{
+              \pgfpoint
+                {\l__timechart_finish_solid_x}
+                {-\l__timechart_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_finish_extreme_x}
+                {\l__timechart_bar_half_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_finish_extreme_x}
+                {\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_left_nonclip_x}
+                {\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_left_nonclip_x}
+                {-\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathlineto{
+              \pgfpoint
+                {\l__timechart_finish_solid_x}
+                {-\l__timechart_bar_thickness_pgf}
+            }
+            \pgfpathclose
+            \pgfusepath{clip}
+            \endpgfinterruptboundingbox
+            \pgfmathsetmacro{\l__timechart_finish_solid_x}
+              {\l__timechart_finish_extreme_x}
+          }
+      }
+  }
+\cs_new:Npn\__timechart_interval_draw_solid:
+  {
+    \__timechart_if_x_range_intersect_tolerance_bounds:nnT
+      {\l__timechart_start_solid_x}
+      {\l__timechart_finish_solid_x}
+      {
+        \pgfpathrectanglecorners{
+          \pgfpoint
+            {\l__timechart_start_solid_x}
+            {-\l__timechart_bar_half_thickness_pgf}
+        }{
+          \pgfpoint
+            {\l__timechart_finish_solid_x}
+            {\l__timechart_bar_half_thickness_pgf}
+        }
+        \pgfsetfillcolor{\l__timechart_bar_color}
+        \pgfusepath{fill}
+      }
+  }
+\msg_new:nnn{timechart}{interval_mark_outside}
+  { Attempt~to~mark~outside~interval~at~date~#1 }
+\cs_new:Npn\__timechart_interval_mark:
+  {
+    \pgfscope
+    \pgfsetstrokecolor{\l__timechart_mark_color}
+    \foreach \year in \l__timechart_mark_text
+      {
+        \pgfmathsetmacro{\l__timechart_mark_x}{yeartox(\year)}
+        \__timechart_pgfmathsetbool:nn{\l__timechart_tmpa_bool}
+          {
+            or (
+              \l__timechart_mark_x < \l__timechart_start_extreme_x,
+              \l__timechart_mark_x > \l__timechart_finish_extreme_x
+            )
+          }
+        \bool_if:NT\l__timechart_tmpa_bool
+          { \msg_error:nne{timechart}{interval_mark_outside}{\year} }
+        \pgfpathmoveto{
+          \pgfpoint
+            {\l__timechart_mark_x}
+            {-\l__timechart_bar_half_thickness_pgf}
+        }
+        \pgfpathlineto{
+          \pgfpoint
+            {\l__timechart_mark_x}
+            {\l__timechart_bar_half_thickness_pgf}
+        }
+        \pgfusepath{draw}
+      }
+    \endpgfscope
+  }
+\cs_new:Npn\__timechart_interval_define_bar_node:
+  {
+    \__timechart_make_rectangle_node:nnnn
+      {
+        \pgfpoint
+          {\l__timechart_start_extreme_x}
+          {-\l__timechart_bar_half_thickness_pgf}
+      }{
+        \pgfpoint
+          {\l__timechart_finish_extreme_x}
+          {\l__timechart_bar_half_thickness_pgf}
+      }
+      {\pgfkeysvalueof{/timechart/interval~bar~node~name}}
+      {\c_false_bool}
+  }
+\cs_new:Npn\__timechart_interval_label:
+  {
+    \str_if_empty:NF \l__timechart_label_text
+      {
+        \pgfinterruptboundingbox
+        \int_case:nn {\l__timechart_label_pos_int}
+        {
+          {0}{ \__timechart_interval_label_left: }
+          {1}{ \__timechart_interval_label_center: }
+          {2}{ \__timechart_interval_label_right: }
+        }
+        \endpgfinterruptboundingbox
+      }
+  }
+\cs_new:Npn\__timechart_interval_label_left:
+  {
+    \__timechart_if_x_in_bounds:nT{\l__timechart_start_extreme_x}
+      {
+        \group_begin:
+        \pgftransformshift{
+          \pgfpoint
+            {\l__timechart_start_extreme_x}
+            {\l__timechart_text_baseline_pgf}
+        }
+        \node[/timechart/interval~label,anchor=base~east]
+          (\l__timechart_interval_label_node_name)
+          at (0,0)
+          {
+            \__timechart_make_ref:NN
+              \l__timechart_ref_text
+              \l__timechart_label_text
+          };
+        \group_end:
+      }
+  }
+\cs_new:Npn\__timechart_interval_label_right:
+  {
+    \__timechart_if_x_in_bounds:nT{\l__timechart_finish_extreme_x}
+      {
+        \group_begin:
+        \pgftransformshift{
+          \pgfpoint
+            {\l__timechart_finish_extreme_x}
+            {\l__timechart_text_baseline_pgf}
+        }
+        \node[/timechart/interval~label,anchor=base~west]
+          (\l__timechart_interval_label_node_name)
+          at (0,0)
+          {
+            \__timechart_make_ref:NN
+              \l__timechart_ref_text
+              \l__timechart_label_text
+          };
+        \group_end:
+      }
+  }
+\cs_new:Npn\__timechart_interval_label_center:
+  {
+    \pgfmathsetlengthmacro{\l__timechart_label_anchor_x}
+      {
+        .5*max(\l__timechart_start_definite_x,\l__timechart_start_x)
+        + .5*min(\l__timechart_finish_definite_x,\l__timechart_finish_x)
+      }
+    \group_begin:
+    \pgftransformshift{
+      \pgfpoint
+        {\l__timechart_label_anchor_x}
+        {\l__timechart_text_baseline_pgf}
+    }
+    \pgfonlayer{labelbg}
+    \node[
+      /timechart/interval~label~centered~background,
+      anchor=base
+    ]
+      at (0,0)
+      { \l__timechart_label_text };
+    \endpgfonlayer
+    \group_end:
+    \pgfscope
+    \pgfpathrectanglecorners{
+      \pgfpoint
+        {\l__timechart_start_extreme_x}
+        {-\l__timechart_bar_half_thickness_pgf}
+    }{
+      \pgfpoint
+        {\l__timechart_finish_extreme_x}
+        {\l__timechart_bar_half_thickness_pgf}
+    }
+    \pgfusepath{clip}
+    \group_begin:
+    \pgftransformshift{
+      \pgfpoint
+        {\l__timechart_label_anchor_x}
+        {\l__timechart_text_baseline_pgf}
+    }
+    \node[
+    /timechart/interval~label~centered,
+    anchor=base
+    ]
+      (\l__timechart_interval_label_node_name)
+      at (0,0)
+      {
+        \__timechart_make_ref:NN
+        \l__timechart_ref_text
+        \l__timechart_label_text
+      };
+    \group_end:
+    \endpgfscope
+  }
+\NewDocumentCommand{\__timechart_text_user:Omm}{ O{} m m }
+  {
+    \str_if_empty:nF{#3}{
+      \group_begin:
+      \pgfmathsetmacro{\l__timechart_text_x}{yeartox(#2)}
+      \__timechart_if_x_in_tolerance_bounds:nT{\l__timechart_text_x}
+        {
+          \pgfqkeys{/timechart}{
+            #1,
+            ref/.get=\l__timechart_ref_text,
+            text~node~name/.get=\l__timechart_node_name_text,
+            text~baseline/.get=\l__timechart_text_baseline_pgf,
+          }
+          \pgftransformshift{
+            \pgfpoint{0}{\l__timechart_current_y}
+          }
+          \pgfinterruptboundingbox
+          \group_begin:
+          \pgftransformshift{
+            \pgfpoint{\l__timechart_text_x}{\l__timechart_text_baseline_pgf}
+          }
+          \cs_set:Npn\l__timechart_text{#3}
+          \int_case:nn {\l__timechart_text_pos_int}
+          {
+            {0}{ \cs_set:Npn\l__timechart_node_anchor_text{base~east} }
+            {1}{ \cs_set:Npn\l__timechart_node_anchor_text{base} }
+            {2}{ \cs_set:Npn\l__timechart_node_anchor_text{base~west} }
+          }
+          \node[/timechart/text,anchor=\l__timechart_node_anchor_text]
+            (\l__timechart_node_name_text)
+            at (0,0)
+            {
+              \__timechart_make_ref:NN
+              \l__timechart_ref_text
+              \l__timechart_text
+            };
+          \group_end:
+          \endpgfinterruptboundingbox
+        }
+      \group_end:
+    }
+    \__timechart_space_user:O[#1]
+  }
+\NewDocumentCommand{\__timechart_space_user:O}{ O{} }
+  {
+    \group_begin:
+
+    \pgfqkeys{/timechart}{
+      #1,
+      interval~bar~thickness/.get=\l__timechart_bar_thickness_pgf,
+    }
+    \pgfmathsetlengthmacro{\l__timechart_bar_half_thickness_pgf}
+      { .5*\l__timechart_bar_thickness_pgf }
+    \pgftransformshift{
+      \pgfpoint{0}{\l__timechart_current_y}
+    }
+    \pgfpathmoveto{
+      \pgfpoint{0}{-\l__timechart_bar_half_thickness_pgf}
+    }
+    \pgfpathmoveto{
+      \pgfpoint{0}{\l__timechart_bar_half_thickness_pgf}
+    }
+    \pgfusepath{discard}
+    \group_end:
+    \bool_if:NT\l__timechart_autostep_bool{
+      \__timechart_step_y_user:O
+    }
+  }
+\NewDocumentCommand{\timechartlegenditem}{ O{} }
+  {
+    \__timechart_legend_aux:nn{#1}{
+      \pgfmathsetlengthmacro{\l__timechart_start_solid_x}{0}
+      \pgfmathsetlengthmacro{\l__timechart_finish_solid_x}
+        {\l__timechart_legenditem_width_pgf}
+      \__timechart_interval_draw_solid:
+    }
+  }
+\NewDocumentCommand{\timechartlegendstartrange}{ O{} }
+  {
+    \__timechart_legend_aux:nn{#1}{
+      \pgfmathsetlengthmacro{\l__timechart_start_extreme_x}{0}
+      \pgfmathsetlengthmacro{\l__timechart_start_solid_x}
+        {\pgfkeysvalueof{/timechart/legend~item~range~width}}
+      \pgfmathsetlengthmacro{\l__timechart_finish_solid_x}
+        {\l__timechart_legenditem_width_pgf}
+      \int_case:nn {\l__timechart_start_range_type_int}
+        {
+          {0}{ \__timechart_interval_start_range_fade: }
+          {1}{ \__timechart_interval_start_range_slant: }
+        }
+      \__timechart_interval_draw_solid:
+    }
+  }
+\NewDocumentCommand{\timechartlegendfinishrange}{ O{} }
+  {
+    \__timechart_legend_aux:nn{#1}{
+      \pgfmathsetlengthmacro{\l__timechart_start_solid_x}{0}
+      \pgfmathsetlengthmacro{\l__timechart_finish_solid_x}
+        {
+          \l__timechart_legenditem_width_pgf
+          -\pgfkeysvalueof{/timechart/legend~item~range~width}
+        }
+      \pgfmathsetlengthmacro{\l__timechart_finish_extreme_x}
+        {\l__timechart_legenditem_width_pgf}
+      \int_case:nn {\l__timechart_finish_range_type_int}
+        {
+          {0}{ \__timechart_interval_finish_range_fade: }
+          {1}{ \__timechart_interval_finish_range_slant: }
+        }
+      \__timechart_interval_draw_solid:
+    }
+  }
+\cs_new:Npn\__timechart_legend_aux:nn #1#2
+  {
+    \tikzpicture
+    \pgfkeys{
+      /timechart/.cd,
+      #1,
+      interval~bar~thickness/.get=\l__timechart_bar_thickness_pgf,
+      interval~bar~color/.get=\l__timechart_bar_color,
+      interval~minimum~width/.get=\l__timechart_minimum_width_pgf,
+      beyond~length/.get=\l__timechart_beyond_length_pgf,
+      legend~item~width/.get=\l__timechart_legenditem_width_pgf,
+    }
+    \pgfmathsetlengthmacro{\l__timechart_bar_half_thickness_pgf}
+      {.5*\l__timechart_bar_thickness_pgf}
+    \pgfmathsetmacro{\l__timechart_start_x}{0}
+    \pgfmathsetmacro{\l__timechart_finish_x}
+      {\l__timechart_legenditem_width_pgf}
+    \pgfmathsetlengthmacro{\l__timechart_start_beyond_x}
+      {\l__timechart_start_x-\l__timechart_beyond_length_pgf}
+    \pgfmathsetlengthmacro{\l__timechart_finish_beyond_x}
+      {\l__timechart_finish_x+\l__timechart_beyond_length_pgf}
+    \pgfmathsetmacro{\l__timechart_current_y}{0}
+    \pgfmathsetmacro{\l__timechart_start_tolerance_x}
+      {\l__timechart_start_x-10mm}
+    \pgfmathsetmacro{\l__timechart_finish_tolerance_x}
+      {\l__timechart_finish_x+10mm}
+    #2
+    \pgfresetboundingbox
+    \pgfmoveto{
+      \pgfpoint{0}{-\l__timechart_bar_half_thickness_pgf}
+    }
+    \pgfmoveto{
+      \pgfpoint
+        {\l__timechart_legenditem_width_pgf}
+        {\l__timechart_bar_half_thickness_pgf}
+    }
+    \endtikzpicture%
+  }


Property changes on: trunk/Master/texmf-dist/tex/latex/timechart/timechart.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2025-02-15 21:26:13 UTC (rev 74009)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2025-02-15 21:28:35 UTC (rev 74010)
@@ -878,7 +878,7 @@
     tikzpackets tikzpagenodes tikzpeople tikzpfeile tikzpingus tikzposter
     tikzquads tikzquests tikzscale tikzsymbols
     tikztosvg tikzviolinplots tile-graphic tilings
-    timbreicmc timeop times timetable timing-diagrams
+    timbreicmc timechart timeop times timetable timing-diagrams
     tinos tipa tipa-de tipauni tipfr
     tiscreen titlecaps titlefoot titlepages titlepic titleref titlesec titling
     tkz-base tkz-berge tkz-bernoulli tkz-doc tkz-elements tkz-euclide

Modified: trunk/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc	2025-02-15 21:26:13 UTC (rev 74009)
+++ trunk/Master/tlpkg/tlpsrc/collection-pictures.tlpsrc	2025-02-15 21:28:35 UTC (rev 74010)
@@ -240,6 +240,7 @@
 depend tikzviolinplots
 depend tile-graphic
 depend tilings
+depend timechart
 depend timing-diagrams
 depend tipfr
 depend tkz-base

Added: trunk/Master/tlpkg/tlpsrc/timechart.tlpsrc
===================================================================


More information about the tex-live-commits mailing list.