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:

enter image description here

\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}

enter image description here

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}

enter image description here

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”.

Tags:

Latex3

Xparse