使用 datetime2 或其他包验证日期

使用 datetime2 或其他包验证日期

可以使用该包验证英文日期吗datetime2?如果不行,还有其他包/方法可以做到这一点吗?

  • 有效参数:2023-06-14,,2023-09-24...

  • 无效参数:2023-06-XX,,2023-09-32...

理想情况下,我希望按以下方式对无效参数进行条件化:

\IfJulianDate{<date>}{<true code>}{<false code>}

答案1

PGFCalendar 序列基本上是这样的:

\pgfcalendardatetojulian{<date>}{\<count>}
\pgfcalendarjuliantodate{\<count>}{\Year}{\Month}{\Day}

然后针对您的输入(您需要在s 处以某种方式拆分)测试 、 。请注意,\Year需要\Month是单个标记计数,而不是 LaTeX 计数器,甚至不是宏。L3 临时“整数”是 1。\Day-\<count>\count0\l_tmpa_int

在下面的代码中,我使用 L3Regex 为典型--日期格式为整数,这意味着 0003-000012-000000 将与其匹配。

但是,负数年份与正则表达式不匹配。两者都不是2023-09-last2023-09-19+3哪个都是有效的 PGFCalendar 日期。\A(开始) 和\Z(结束) 确保只有一个日期匹配,其他日期都不匹配,因此两者都不是Foo 2023-09-13 Bar2023-09-19 2023-09-20(将是两个日期),这两者都会破坏 PGFCalendar。

\regex_extract_once宏将所有匹配项放入其中,\l_tmpa_seq其中第一个元素是整个匹配项,其他元素是用对表示的捕获组()

代码

\documentclass{article}
\usepackage{pgfcalendar, pgffor}% pgffor just for the .list handler
\ExplSyntaxOn
\regex_new:N \l_mbc_datetest
\regex_set:Nn\l_mbc_datetest { \A (\d+) \- (\d+) \- (\d+) \Z }
\NewDocumentCommand { \IfJulianDate }{ m m m }{
  \regex_extract_once:NnNTF \l_mbc_datetest { #1 } \l_tmpa_seq {
    \pgfcalendardatetojulian{ #1 } { \l_tmpa_int }
    \pgfcalendarjuliantodate { \l_tmpa_int }{ \l_tmp_year_int }
                         { \l_tmp_month_int }{ \l_tmp_day_int }
    \bool_lazy_all:nTF {
      { \int_compare_p:nNn { \seq_item:Nn\l_tmpa_seq{2} } = { \l_tmp_year_int  } }
      { \int_compare_p:nNn { \seq_item:Nn\l_tmpa_seq{3} } = { \l_tmp_month_int } }
      { \int_compare_p:nNn { \seq_item:Nn\l_tmpa_seq{4} } = { \l_tmp_day_int   } }
    }{ #2 }{ #3 }
  }{ % not even proper date format
    #3
  }
}
\ExplSyntaxOff
\begin{document}
\pgfkeys{tester/.code=#1 is \IfJulianDate{#1}{a real}{not a proper} date\par,
         tester/.list={
           2023-06-14, 2023-09-24, 2023-06-XX, 2023-09-32,
           2023-02-29, 2023-09-19 2023-09-20, -0001-12-24}}
\end{document}

输出

2023-06-14 是实际日期
2023-09-24 是实际日期
2023-06-XX 不是正确日期
2023-09-32 不是正确日期
2023-02-29 不是正确日期
2023-09-19 2023-09-20 不是正确日期
-0001-12-24 不是正确日期

答案2

这是“纯”代码的初稿LaTeX3:错误消息未实现,因为它只是一个 PoC。我的代码应该是可分解的。欢迎任何建议...

编辑:使用条件

\documentclass{article}

% Source for easy testing via pgffor:
%     + https://tex.stackexchange.com/a/696444/6880
\usepackage{pgffor}

\ExplSyntaxOn

\seq_new:N \g_mbc_month_size
\seq_set_from_clist:Nn \g_mbc_month_size {%
  0,  % Not used.
  31, % January
  0,  % February: this special value will help us to find bugs...
  31, % March
  30, % April
  31, % May
  30, % June
  31, % July
  31, % August
  30, % September
  31, % October
  30, % November
  31 % December
}

% The rule defining a leap year A is as follows:
%
%    + If A % 4 != 0, the year is not a leap year.
%
%    + If A % 4 = 0 , the year is a leap year unless 
%      A % 100 = 0 and A % 400 != 0. 
\prg_set_conditional:Npnn \if_leap_year:N #1 { p , T , TF } {
  \int_compare:nTF { 
    \int_mod:nn #1 { 4 } = 0
  }{
    \int_compare:nTF {
      \int_mod:nn #1 { 100 } = 0
    }{
      \int_compare:nTF {
        \int_mod:nn #1 { 400 } = 0
      }{
        \prg_return_true:
      }{
        \prg_return_false:
      }
    }{
      \prg_return_true:
    }
  }{
    \prg_return_false:
  }
}

\regex_new:N \g_mbc_date_format_rgx
\regex_set:Nn\g_mbc_date_format_rgx { \A (\d+) \- (\d+) \- (\d+) \Z }

\str_new:N \l_mbc_date_year_str
\str_new:N \l_mbc_date_month_str
\str_new:N \l_mbc_date_day_str

\int_new:N \l_mbc_date_year_int
\int_new:N \l_mbc_date_month_int
\int_new:N \l_mbc_date_day_int

\NewDocumentCommand { \ValidateJulianDate }{ m }{
  \regex_extract_once:NnNTF \g_mbc_date_format_rgx { #1 } \l_tmpa_seq {
% Integer values found.
    \seq_pop_right:NN \l_tmpa_seq \l_mbc_date_day_str
    \seq_pop_right:NN \l_tmpa_seq \l_mbc_date_month_str
    \seq_pop_right:NN \l_tmpa_seq \l_mbc_date_year_str
    
    \int_set:Nn \l_mbc_date_day_int   \l_mbc_date_day_str
    \int_set:Nn \l_mbc_date_month_int \l_mbc_date_month_str
    \int_set:Nn \l_mbc_date_year_int  \l_mbc_date_year_str
 
% 1 <= month <= 12
    \int_compare:nTF { 1 <= \l_mbc_date_month_int <= 12 }{
% February special setting.
      \if_int_compare:w \l_mbc_date_month_int = 2
        \if_leap_year:NTF \l_mbc_date_year_int {
          \seq_set_item:Nnn \g_mbc_month_size 2 { 29 }
        }{
          \seq_set_item:Nnn \g_mbc_month_size 2 { 28 }
        }
      \fi:

% Good day.
      \int_compare:nTF {
        1 <= \l_mbc_date_day_int 
          <= \seq_item:Nn \g_mbc_month_size 
                          { \int_use:N \l_mbc_date_month_int }
      }{
        OK
% Bad day.
      }{
        KO (day)
      }

 % NOT(1 <= month <= 12).
    }{
      KO (month)
    }

 % Syntax error
  }{
    KO (syntax)
  }
}

\ExplSyntaxOff


\begin{document}

\section{OK}

\pgfkeys{tester/.code=\ValidateJulianDate{#1}{:} #1\par\medskip,
         tester/.list={
           2023-06-14, 
           2023-09-24, 
           2023-02-28,
           2024-02-29,
           400-02-29
         }
}


\section{KO -- Invalid day}

\pgfkeys{tester/.code=\ValidateJulianDate{#1}{:} #1\par\medskip,
         tester/.list={
           300-02-29,
           2023-02-29,
           2024-02-30,
           2023-09-00,
           2023-09-32
         }
}


\section{KO -- Invalid month}

\pgfkeys{tester/.code=\ValidateJulianDate{#1}{:} #1\par\medskip,
         tester/.list={
           2023-19-32,
           2023-00-29
         }
}


\section{KO -- Syntax error}

\pgfkeys{tester/.code=\ValidateJulianDate{#1}{:} #1\par\medskip,
         tester/.list={
           2023-06-XX,  
           2023-09-19 2023-09-20, 
           -0001-12-24
         }
}

\end{document}

输出

1 OK
OK: 2023-06-14 
OK: 2023-09-24 
OK: 2023-02-28 
OK: 2024-02-29 
OK: 400-02-29

2 KO – Invalid day
KO(day): 300-02-29 
KO(day): 2023-02-29 
KO(day): 2024-02-30 
KO(day): 2023-09-00 
KO(day): 2023-09-32

3 KO – Invalid month
KO(month): 2023-19-32 
KO(month): 2023-00-29

4 KO – Syntax error
KO(syntax): 2023-06-XX
KO(syntax): 2023-09-19 2023-09-20 
KO(syntax): -0001-12-24

相关内容