可以使用该包验证英文日期吗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-last
或2023-09-19+3
哪个都是有效的 PGFCalendar 日期。\A
(开始) 和\Z
(结束) 确保只有一个日期匹配,其他日期都不匹配,因此两者都不是Foo 2023-09-13 Bar
或2023-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