Date(time) ranges using `datetime2`
I don't know what the datetime2 package can do but I was curious to see what you could do using pgfkeys to format dates in a uniform way.
This provides some code for inputting dates and a uniform way of adjusting the formatting of the displayed date. There is also a \DateRange
that, I think, does what you want in a way that depends on the current "date format".
The code below produces:
The last two lines are "date ranges" with different formats.
Here's the code:
\documentclass{article}
\usepackage{pgfkeys}
\usepackage{pgfmath}% for calculating yy from yyyy
\usepackage{siunitx}% we use the \num command for dd and mm format in the
\newif\ifPrintYear\PrintYeartrue% controls if year is printed
\newif\ifPrintMonth\PrintMonthtrue% controls if month is printed
\pgfkeys{/mydate/.is family, /mydate,
year/.initial=0,
month/.initial=0,
day/.initial=0,
date format/.initial = dmyy,
date range separator/.initial = {-},% used to separate dates in \DateRange
format day d/.code = {\pgfkeysvalueof{/mydate/day}}, % format ways to the day
format day dd/.code = {\num[minimum-integer-digits=2]{\pgfkeysvalueof{/mydate/day}}},
format month/.code n args={3}{% <format month><pre-text><post-text>
\ifPrintMonth#2\pgfkeys{/mydate/format month #1}#3\fi%
},
format month m/.code = {\pgfkeysvalueof{/mydate/month}},
format month mm/.code = {\num[minimum-integer-digits=2]{\pgfkeysvalueof{/mydate/month}}},
format month mmm/.code={%
\expandafter\ifcase\pgfkeysvalueof{/mydate/month}??%
\or Jan%
\or Feb%
\or Mar%
\or Apr%
\or May%
\or Jun%
\or Jul%
\or Aug%
\or Sep%
\or Oct%
\or Nov%
\or Dec%
\else ???%
\fi%
},
format month mmmm/.code={%
\expandafter\ifcase\pgfkeysvalueof{/mydate/month}??%
\or January%
\or February%
\or March%
\or April%
\or May%
\or June%
\or July%
\or August%
\or September%
\or October%
\or November%
\or December%
\else ???%
\fi%
},
format year/.code n args={3}{% <format year><pre-text><post-text>
\ifPrintYear#2\pgfkeys{/mydate/format year #1}#3\fi%
},
format year yy/.code = {%
\pgfmathparse{Mod(\pgfkeysvalueof{/mydate/year},100)}%
\num[minimum-integer-digits=2,zero-decimal-to-integer]{\pgfmathresult}%
},
format year yyyy/.code = {%
\pgfkeysvalueof{/mydate/year}%
},
output/dmyy/.code = {%
\pgfkeys{/mydate/format day d}%
\pgfkeys{/mydate/format month={m}{/}{\relax}}%
\pgfkeys{/mydate/format year={yy}{/}{\relax}}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/dmyyyy/.code = {%
\pgfkeys{/mydate/format day d}%
\pgfkeys{/mydate/format month={m}{/}{\relax}}%
\pgfkeys{/mydate/format year={yyyy}{/}{\relax}}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/ddmmyy/.code = {%
\pgfkeys{/mydate/format day dd}%
\pgfkeys{/mydate/format month={mm}{/}{\relax}}%
\pgfkeys{/mydate/format year={yy}{/}{\relax}}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/ddmmyyyy/.code = {%
\pgfkeys{/mydate/format day dd}%
\pgfkeys{/mydate/format month={mm}{/}{\relax}}%
\pgfkeys{/mydate/format year={yyyy}{/}{\relax}}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/mmmdyyyy/.code = {%
\pgfkeys{/mydate/format month={mmm}{\relax}{ }}%
\pgfkeys{/mydate/format day d}%
\pgfkeys{/mydate/format year={yyyy}{, }{\relax}}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/mmmmdyyyy/.code = {%
\pgfkeys{/mydate/format month={mmmm}{\relax}{ }} %
\pgfkeys{/mydate/format day d}%
\pgfkeys{/mydate/format year={yyyy}{ }{\relax}}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/yyyymd/.code = {%
\pgfkeys{/mydate/format year={yyyy}{\relax}{/}}%
\pgfkeys{/mydate/format month={m}{\relax}{/}}%
\pgfkeys{/mydate/format day d}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/yyyymmdd/.code = {%
\pgfkeys{/mydate/format year={yyyy}{\relax}{/}}%
\pgfkeys{/mydate/format month={mm}{\relax}{/}}%
\pgfkeys{/mydate/format day dd}%
\pgfkeyssetvalue{/mydate/date range separator}{ to }%
},
output/iso/.code = {%
\pgfkeys{/mydate/format year={yyyy}{\relax}{-}}%
\pgfkeys{/mydate/format month={mm}{\relax}{-}}%
\pgfkeys{/mydate/format day dd}%
\pgfkeyssetvalue{/mydate/date range separator}{/}%
},
printdate/.code={\pgfkeys{/mydate/output/\pgfkeysvalueof{/mydate/date format}}}
}
% format date input yyyy-m-d ---- but allow yy-m-d
\pgfkeysdefargs{/mydate/date}{#1-#2-#3}{%
\ifnum#1<100\relax \pgfkeyssetvalue{/mydate/year}{20#1}% assume year is 20XX
\else\pgfkeyssetvalue{/mydate/year}{#1}%
\fi%
\pgfkeyssetvalue{/mydate/month}{#2}%
\pgfkeyssetvalue{/mydate/day}{#3}%
}
\newcommand\DateFormat[1]{\pgfkeys{/mydate/date format=#1}}
\newcommand\Date[1]{\pgfkeys{/mydate, date=#1, printdate}}
\newcommand\DateRange[2]{%
\bgroup% start a group so that PrintYear and PrintMonth changes are local
\Date{#1}%
\xdef\lastYear{\pgfkeysvalueof{/mydate/year}}%
\xdef\lastMonth{\pgfkeysvalueof{/mydate/month}}%
\pgfkeys{/mydate/date=#2}%
\xdef\thisYear{\pgfkeysvalueof{/mydate/year}}%
\xdef\thisMonth{\pgfkeysvalueof{/mydate/month}}%
\ifnum\thisYear=\lastYear\relax%
\PrintYearfalse%
\ifnum\thisMonth=\lastMonth\relax%
\PrintMonthfalse%
\fi
\fi%
\pgfkeysvalueof{/mydate/date range separator}%
\pgfkeys{/mydate/printdate}%
\egroup
}
\begin{document}
\Date{2017-08-28}
\DateFormat{ddmmyy}\Date{2017-08-09}
\DateFormat{iso}\Date{2017-08-09}
\DateFormat{mmmdyyyy}\Date{2017-08-09}
\DateFormat{mmmmdyyyy}\Date{2017-08-09}
\DateFormat{iso}
\DateRange{2017-08-05}{2017-08-10}
\DateRange{2017-08-05}{2017-09-10}
\DateRange{2017-08-05}{2018-09-10}
\DateFormat{mmmdyyyy}
\DateRange{2017-08-05}{2017-08-10}
\DateRange{2017-08-05}{2017-09-10}
\DateRange{2017-08-05}{2018-09-10}
\end{document}
The idea of the code is that the date is inputted in the format yyyy-m-d
using \Date
. At anytime the format of the date can be changed using \DateFormat
. Behind the scenes there is some pgfkeys trickery that calls a particular date format when the printing is really done. The supported formats are all subkeys of the /mydate/output
key and, in turn, these invoke various year, month and day format keys.
There is an additional complication to cater for the date range: the year formats, through /mydate/format year
, all use \ifPrintYear
to see if the year should be printed and to make this work the year formats all accept two arguments, which is the text before and after the year since they also need to be dropped when the year is not printed. Similarly, the months use \ifPrintMonth
. The \DateRange
checks the two years in the date range and if they are equal sets \PrintYearfalse
, with the result that the year for the second date is not printed.