L3 equivalent to ifcase
You can use the primitive \if_case:w
as you did, yes, but a correct-er way would be to use \int_case:nn
. Here's an implementation with a clear separation of document-level and code-level interfaces, and some syntactic sugar to change the date format:
\documentclass{book}
\usepackage{xparse}
\usepackage{nth}
\ExplSyntaxOn
% Document level
\NewDocumentCommand \shccustomdate { } { \shc_date: }
\NewDocumentCommand \shcdateformat { m } { \shc_set_date_format:n {#1} }
\NewExpandableDocumentCommand \monthname { m } { \shc_month_name:n {#1} }
% Code level
\cs_new_protected:Npn \shc_date:
{
\__shc_print_date:xxx
{ \int_use:N \c_sys_day_int }
{ \int_use:N \c_sys_month_int }
{ \int_use:N \c_sys_year_int }
}
\cs_new_protected:Npn \shc_set_date_format:n #1
{ \cs_set_protected:Npn \__shc_print_date:nnn ##1 ##2 ##3 {#1} }
\cs_generate_variant:Nn \__shc_print_date:nnn { xxx }
\cs_new:Npn \shc_month_name:n #1
{
\int_case:nn {#1}
{
{ 1 } { January }
{ 2 } { February }
{ 3 } { March }
{ 4 } { April }
{ 5 } { May }
{ 6 } { June }
{ 7 } { July }
{ 8 } { August }
{ 9 } { September }
{ 10 } { October }
{ 11 } { November }
{ 12 } { December }
}
}
% Default format
\cs_new_protected:Npn \__shc_print_date:nnn #1 #2 #3 { \monthname{#2},~#3 }
\ExplSyntaxOff
\begin{document}
\verb|\shcdateformat{\monthname{#2}, #3}|:
\shccustomdate
\bigskip
\verb|\shcdateformat{\monthname{#2} \nth{#1}, #3}|:
\shcdateformat{\monthname{#2} \nth{#1}, #3}
\shccustomdate
\end{document}
The code above has two parts. The first one sets the date format with \shc_set_date_format:n
. That function basically defines:
\cs_new_protected:Npn \__shc_print_date:nnn #1 #2 #3
{ <format> }
where <format>
is the argument to \shcdateformat
, and in that argument #1
is the day, #2
is the month, and #3
is the year.
Then the second part, in \shc_date:
, expands \c_sys_day_int
, \c_sys_month_int
(the month is further expanded to its name using \int_case:nn
) and \c_sys_year_int
, and passes them as arguments to \__shc_print_date:nnn
which does the typesetting.
I'd use \clist_item:Nn
with a constant clist.
\documentclass{article}
%\usepackage{xparse} % not needed for LaTeX 2020-10-01 or later
\ExplSyntaxOn
\NewDocumentCommand{\shccustomdate}{O{english}}
{
\azetina_date_monthname:n { #1 }
\azetina_date_separator:n { #1 }
\azetina_year:
}
\clist_const:Nn \c_azetina_date_months_english_clist
{
January,February,March,April,May,June,July,
August,September,October,November,December
}
\tl_const:Nn \c_azetina_date_separator_english_tl { ,\nobreakspace }
\clist_const:Nn \c_azetina_date_months_italian_clist
{
gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,
agosto,settembre,ottobre,novembre,dicembre
}
\clist_const:Nn \c_azetina_date_separator_italian_tl { \nobreakspace }
\cs_new:Nn \azetina_date_monthname:n
{
\clist_item:cn { c_azetina_date_months_#1_clist } { \c_sys_month_int }
}
\cs_new:Nn \azetina_date_separator:n
{
\tl_use:c { c_azetina_date_separator_#1_tl }
}
\cs_new:Nn \azetina_year:
{
\int_to_arabic:n { \c_sys_year_int }
}
\ExplSyntaxOff
\begin{document}
\shccustomdate
\shccustomdate[italian]
\end{document}
Without multilingual support, this would boil down to
\NewDocumentCommand{\shccustomdate}{}
{
\clist_item:Nn \c_azetina_date_monthname_clist { \c_sys_month_int }
,\nobreakspace
\int_to_arabic:n { \c_sys_year_int }
}
\clist_const:Nn \c_azetina_date_monthname_clist
{
January,February,March,April,May,June,July,
August,September,October,November,December
}
Unless the user tampers with \c_sys_month_int
, this is safe enough, because the constant will necessarily evaluate to an integer in the required range [1–12].
Here is support for different formats to be chosen at runtime.
\documentclass{article}
%\usepackage{xparse} % not needed for LaTeX 2020-10-01 or later
\usepackage{nth}
\ExplSyntaxOn
\NewDocumentCommand{\shccustomdate}{}
{
\azetina_date_custom:nnn { \c_sys_year_int } { \c_sys_month_int } { \c_sys_day_int }
}
\NewDocumentCommand{\shcsetformat}{m}
{
\cs_set:Nn \azetina_date_custom:nnn { #1 }
}
\NewExpandableDocumentCommand{\decimal}{m}
{
\int_to_arabic:n { #1 }
}
\NewExpandableDocumentCommand{\monthname}{m}
{
\clist_item:Nn \c_azetina_date_monthname_clist { #1 }
}
\clist_const:Nn \c_azetina_date_monthname_clist
{
January,February,March,April,May,June,July,
August,September,October,November,December
}
\ExplSyntaxOff
% initialize
\shcsetformat{\monthname{#2},~\decimal{#1}}
\begin{document}
\shccustomdate
\shcsetformat{\monthname{#2}~\nth{#3}, \decimal{#1}}
\shccustomdate
\end{document}
In \shcsetformat
, #1
refers to the year, #2
to the month and #3
to the day, according to ISO conventions. Note that, as the setting of the format is done outside \ExplSyntaxOn
-\ExplSyntaxOff
, the tie ~
means “no-break space”.