texlive[61560] Master/texmf-dist: dbshow (10jan22)

commits+karl at tug.org commits+karl at tug.org
Mon Jan 10 22:27:57 CET 2022


Revision: 61560
          http://tug.org/svn/texlive?view=revision&revision=61560
Author:   karl
Date:     2022-01-10 22:27:56 +0100 (Mon, 10 Jan 2022)
Log Message:
-----------
dbshow (10jan22)

Modified Paths:
--------------
    trunk/Master/texmf-dist/doc/latex/dbshow/dbshow-doc.pdf
    trunk/Master/texmf-dist/doc/latex/dbshow/dbshow-doc.tex
    trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty

Modified: trunk/Master/texmf-dist/doc/latex/dbshow/dbshow-doc.pdf
===================================================================
(Binary files differ)

Modified: trunk/Master/texmf-dist/doc/latex/dbshow/dbshow-doc.tex
===================================================================
--- trunk/Master/texmf-dist/doc/latex/dbshow/dbshow-doc.tex	2022-01-10 21:27:44 UTC (rev 61559)
+++ trunk/Master/texmf-dist/doc/latex/dbshow/dbshow-doc.tex	2022-01-10 21:27:56 UTC (rev 61560)
@@ -1,5 +1,7 @@
 \documentclass[full]{l3doc}
-\usepackage[scheme=plain]{ctex}
+\usepackage[scheme=plain, fontset=ubuntu]{ctex}
+\usepackage{multicol}
+\usepackage{adjustbox}
 \usepackage{zhlineskip}
 \usepackage{enumitem}
 \usepackage{indentfirst}
@@ -11,23 +13,10 @@
 \tcbuselibrary{listings, skins, raster, breakable}
 \usepackage{tabularray}
 
-\def\zhdate{2022年1月8日}
-\def\endate{2022/01/08}
-\def\version{v1.2}
+\def\zhdate{2022年1月10日}
+\def\endate{2022/01/10}
+\def\version{v1.3}
 
-\IndexPrologue
-  {
-    \section*{Index}
-    \markboth{Index}{Index}
-    \addcontentsline{toc}{section}{Index}
-    The~italic~numbers~denote~the~pages~where~the~
-    corresponding~entry~is~described,~
-    numbers~underlined~point~to~the~definition,~
-    all~others~indicate~the~places~where~it~is~used.
-  }
-
-\newcommand\tikzmark[1]{\tikz \coordinate[overlay, remember picture] (#1);}
-
 \geometry{
   left=4.5cm,
   right=2cm,
@@ -46,8 +35,39 @@
  }
 }
 
+\IndexPrologue {
+  \part*{Index}
+  \markboth{Index}{Index}
+  \addcontentsline{toc}{part}{Index}
+  The~italic~numbers~denote~the~pages~where~the~
+  corresponding~entry~is~described,~
+  numbers~underlined~point~to~the~definition,~
+  all~others~indicate~the~places~where~it~is~used.
+}
+
+\GlossaryPrologue {
+  \part*{Change~History}
+  {\GlossaryParms\ttfamily\hyphenchar\font=`\-}
+  \markboth{Change~History}{Change~History}
+  \addcontentsline{toc}{part}{Change~History}
+}
+
+\let\subsubitem\subitem
+
 \DoNotIndex{\begin, \end}
 \setlength{\parskip}{\medskipamount}
+
+\newcommand\tikzmark[1]{\tikz \coordinate[overlay, remember picture] (#1);}
+\def\levelchar{?}
+\def\orbar{\textup{\textbar}}
+\def\defaultval#1{\textbf{\textup{#1}}}
+\def\TF{true\orbar false}
+\def\TTF{\defaultval{true}\orbar false}
+\def\TFF{true\orbar\defaultval{false}}
+\def\zhbefore{\textbf{前}}
+\def\zhafter{\textbf{后}}
+\def\enbefore{\textbf{before}~}
+\def\enafter{\textbf{after}~}
 \DeclareDocumentEnvironment { note } { +b } {
   \par\textbf{\textsf{NOTE:~}}#1\par
 } {}
@@ -59,33 +79,56 @@
     top=2cm,
     bottom=2cm
   }
+  \PrintChanges
   \PrintIndex
 }
 
 \ExplSyntaxOn
-\NewDocumentCommand { \strcs } { m } {
-  \texttt{\tl_to_str:n { #1 }}
+\makeatletter
+\cs_new_protected:Nn \dbshow_changes:nnnn {
+  \@bsphack\group_begin:\@sanitize
+  \catcode`\\\z@ \catcode`\ 10 \MakePercentIgnore
+  \exp_args:Nx \glossary {
+    \exp_not:N \textbf{#1}\levelchar
+    \exp_not:N \textit{#2}\c_space_tl
+    \exp_not:N \textbf{#3}\c_colon_str\c_space_tl
+    \exp_not:n { #4 }
+  }
+  \group_end:\@esphack
 }
+\cs_generate_variant:Nn \dbshow_changes:nnnn { xnnn }
 
-\dim_new:N \l__my_syntax_dim
-\box_new:N \g__my_syntax_box
-\NewDocumentEnvironment { Syntax } { s }
-  {
-    \dim_set:Nn \l__my_syntax_dim
-      { \textwidth }
-    \hbox_gset:Nw \g__my_syntax_box
-      \small \ttfamily
-      \begin{minipage}[t]{\l__my_syntax_dim}
-        \raggedright\obeyspaces\obeylines
+\cs_new_protected:Nn \dbshow_changes_what:nnnn {
+  \regex_extract_once:nnNT { doc|macro|bug|option }
+  { #3 } \l_tmpa_seq {
+    \dbshow_changes:xnnn {
+      \str_case_e:nn { \seq_item:Nn \l_tmpa_seq { 1 } } {
+        { doc } { Documentation }
+        { macro } { Macro }
+        { bug } { Bug }
+        { option } {  Option }
+        { logic } {  Logic }
+      }
+    }
+      {#2} {#3} {#4}
   }
-  {
-      \end{minipage}
-    \hbox_gset_end:
-    \IfValueF { #1 } { \smallskip }
-    \box_use_drop:N \g__my_syntax_box
-    \smallskip
+}
+
+\cs_new_protected:Nn \dbshow_changes_how:nnnn {
+  \regex_extract_once:nnNT { Add|Update|Remove } { #3 } \l_tmpa_seq {
+    \dbshow_changes:xnnn { \seq_item:Nn \l_tmpa_seq { 1 } }
+      {#2} {#3} {#4}
   }
+}
 
+% #1 version #2 date #3 type #4 desc
+\DeclareDocumentCommand \changes { m m m m } {
+  \dbshow_changes:nnnn {#1} {#2} {#3} {#4}
+  \dbshow_changes_what:nnnn {#1} {#2} {#3} {#4}
+  \dbshow_changes_how:nnnn {#1} {#2} {#3} {#4}
+}
+\makeatother
+
 \DeclareDocumentEnvironment { Description } { o +b } {
   \hbox_set:Nn \l_tmpa_box { #1 }
   \dim_set:Nn \l_tmpa_dim { \box_wd:N \l_tmpa_box }
@@ -94,36 +137,39 @@
   \end{itemize}
 } {  }
 
-\keys_define:nn { dbshow/doc } {
-  opt .tl_set:N = \l_opt_tl,
-  desc .tl_set:N = \l_desc_tl,
-  init .tl_set:N = \l_init_tl,
-  init .initial:n = init-none,
+\cs_new_protected:Nn \dbshowdoc_function_begin:N {
+  \cs_set_eq:NN \__codedoc_tmp_cs:nN \__codedoc_typeset_function_block:nN
+  \cs_set_protected:Npn \__codedoc_typeset_function_block:nN ##1##2 {
+    \__codedoc_function_label:xN {##1} ##2
+    \hbox_set:Nn \l_tmpa_box {##1}
+    \int_compare:nTF { \str_count:n {##1} <= 22 }
+      {##1} { \adjustbox{width=.7\marginparwidth, height=\box_ht:N \l_tmpa_box}{##1} }
+    #1{##1}
+    \__codedoc_typeset_expandability: \\
+  }
 }
+\cs_new_protected:Nn \dbshowdoc_function_end: {
+  \cs_set_eq:NN \__codedoc_typeset_function_block:nN \__codedoc_tmp_cs:nN
+}
+\DeclareDocumentEnvironment { option } { O{} +v }
+  {
+    \dbshowdoc_function_begin:N \SpecialOptionIndex
+    \__codedoc_function:nnw {#1} {#2}
+  }
+  {
+    \__codedoc_function_end:
+    \dbshowdoc_function_end:
+  }
+\DeclareDocumentEnvironment { environment } { O{} +v }
+  {
+    \dbshowdoc_function_begin:N \SpecialEnvIndex
+    \__codedoc_function:nnw {#1} {#2}
+  }
+  {
+    \__codedoc_function_end:
+    \dbshowdoc_function_end:
+  }
 
-\box_new:N \l__option_box
-\NewDocumentEnvironment { option } { m +b } {
-  \keys_set:nn { dbshow/doc } { #1 }
-  \hbox_set:Nw \l__option_box
-    \small \ttfamily
-    \begin{minipage}[t]{\textwidth}
-      \obeyspaces\obeylines
-      \textcolor{red}{
-        \l_opt_tl
-        \exp_args:Nx\SpecialOptionIndex{\l_opt_tl}
-      }
-      {~}\l_desc_tl
-      \hfill(
-      \tl_if_eq:NnTF \l_init_tl { init-none } { no~value }
-        { initially~\texttt{\l_init_tl} }
-      )
-    \end{minipage}
-  \hbox_gset_end:
-  \box_use_drop:N \l__option_box
-  #2
-  \medskip
-} {  }
-
 \DeclareDocumentCommand \opt { O{} m }
   { \__codedoc_cmd:no {#1} { #2 } }
 
@@ -163,13 +209,23 @@
 和其他数据库宏包比如 \pkg{datatool} 相比,\pkg{dbshow} 更专注于非图表类型的数
 据展示。
 
+\changes{1.2}{2022-01-09}{Add doc}{descripton for expansion}
+\begin{itemize}
+  \item 名字后带有 $\star$ 的命令是可以完全展开的(fully-expandable);
+  \item 名字后带有 \ding{73} 的命令可以有限制地展开(restricted-expandable);
+  \item 名字后不带有特殊字符的命令是不可展开的(non-expandable);
+  \item 名字后带有 $\star$ 的选项不影响相关的代码的是否可展开;
+  \item 名字后带有 \ding{73} 的选项是否影响相关代码的可展开性取决于选项的设置;
+  \item 名字后不带有特殊字符的选项会使与之相关的代码变得不可展开。
+\end{itemize}
+
 \subsection{数据类型}
 
 宏包基于 \pkg{expl3} 的基础类型构建了6种类型:
 \begin{Description}[\texttt{clist}]
   \item[\texttt{date}]
-    基于宏包 \pkg{datetime2} 的日期类型,以iso标准存储,支持大小比较,排序(转
-    换成字符串)。默认值为 \cs{Today}。
+    日期类型,以 |yyyy/mm/dd| 形式存储,支持大小比较,排序(转
+    换成字符串)。默认值为 \cs{dbtoday}。
   \item[\texttt{str}]
     字符串类型,支持正则匹配,英文排序。默认值为空。
   \item[\texttt{tl}]
@@ -182,8 +238,14 @@
     逗号分隔的列表类型。默认值为空列表。
 \end{Description}
 
+\changes{1.3}{2022-01-08}{Remove dependency}{\pkg{datatime2}}
+除了日期类型,所有类型都是 \pkg{expl3} 的内置类型。\pkg{dbshow} 构建了一个简单
+的 |date| 类型,支持转换成整数以及带样式的打印。
+
 \subsection{与 \pkg{datatool} 的区别}
 
+\changes{1.2}{2022-01-07}{Add doc}{add comparison to \pkg{datatool}}
+
 从核心功能上看,\pkg{dbshow} 和 \pkg{datatool} 实现了相同的功能。区别在于
 \pkg{dbshow} 基于 \pkg{expl3} 实现,支持字符串的正则匹配,还支持多级排序。使用
 方式上更倾向于样式与内容分离,所有的样式都可以通过选项提前定义好并且可以复用。
@@ -197,7 +259,7 @@
 \section{接口文档}
 
 \subsection{创建、展示和清空数据库}
-\begin{function}{\dbNewDatabase, \dbNewDatabase*}
+\begin{function}[added=2022-01-05]{\dbNewDatabase, \dbNewDatabase*}
   \begin{syntax}
     \cs{dbNewDatabase} \oarg{base database} \marg{database} \{ \\
     ~~\meta{attr1} = \meta{type spec1}, \\
@@ -226,7 +288,7 @@
   }
     \meta{attr} = \meta{type} &
     将 \meta{attr} 声明为 \meta{type} 类型 \\
-    \meta{attr} = \meta{type}\textbar\meta{default} &
+    \meta{attr} = \meta{type}\orbar\meta{default} &
     将 \meta{attr} 声明为 \meta{type} 类型,并且将默认值设置为 \meta{default}。
     \\
   \end{tblr}
@@ -247,7 +309,7 @@
   }
 \end{verbatim}
 
-\begin{function}{\dbshow}
+\begin{function}[added=2022-01-05]{\dbshow}
   \begin{syntax}
     \cs{dbshow} \marg{style} \marg{database}
   \end{syntax}
@@ -255,18 +317,17 @@
   使用 \meta{style} 样式来展示 \meta{database}。
 \end{function}
 
-\begin{function}{\dbclear}
+\changes{1.2}{2022-01-07}{Add macro}{\cs{dbclear}}
+\begin{function}[added=2022-01-07]{\dbclear}
   \begin{syntax}
     \cs{dbclear} \marg{database}
   \end{syntax}
-
   清空 \meta{database} 里的所有内容。
-
 \end{function}
 
 \subsection{\cs{dbNewStyle} 和样式选项}
 
-\begin{function}{\dbNewStyle}
+\begin{function}[added=2022-01-05]{\dbNewStyle}
   \begin{syntax}
     \cs{dbNewStyle} \oarg{base styles} \marg{style} \marg{database} \marg{opts}
   \end{syntax}
@@ -277,14 +338,25 @@
 
 \subsubsection{通用选项}
 
-\begin{option}{opt=filter, desc={= \meta{filter}}, init=-none-}
+\begin{option}[added=2022-01-05]{filter}
+  \begin{syntax}
+    filter = <filter>
+  \end{syntax}
+
   为当前样式设置由 \cs{dbCombineFilters} 所定义的过滤器
 \end{option}
 
-\begin{option}{opt=raw-filter, desc={= \meta{cond combination}}}
-  用已定义的条件为当前样式设置匿名过滤器。下面两个例子的作用是等同的。
+\begin{option}[added=2022-01-06]{raw-filter}
+  \begin{syntax}
+    raw-filter = <conditional expression>
+  \end{syntax}
+
+  使用条件表达式设置匿名过滤器,这里的条件指通过 \cs{dbNewConditional} 定义的
+  条件。下面代码中两个示例的过滤器具有相同的功能。
 \end{option}
 
+\changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
+
 \begin{verbatim}
   % method 1
   \begin{dbFilters}{db}
@@ -301,10 +373,12 @@
   \dbNewStyle{style}{db}{filter=filter}
 \end{verbatim}
 
-\begin{option}{
-  opt = sort,
-  desc = {= \{ \meta{attr spec1}, \meta{attr spec2}, \ldots{} \}},
-}
+\changes{1.2}{2022-01-08}{Fix bug}{string sorting bug}
+\begin{option}[added=2022-01-05]{sort}
+  \begin{syntax}
+    sort = \{ <attr spec1>, <attr spec2>, \ldots{} \}
+  \end{syntax}
+
   为当前样式设置排序规则。支持根据 |str|,|date|,|int|,|fp| 类型的数据进行排
   序,支持多级排序。\meta{attr} 表示增序,\meta{attr}* 表示降序。下面例子中,
   使用 |sort-style| 展示数据时的顺序为先按 |level| 降序,|level| 相同的再按出
@@ -323,34 +397,74 @@
   }
 \end{verbatim}
 
-\begin{option}{
-  opt = item-code,
-  desc = {= \meta{item code}}
-}
+\begin{option}[added=2022-01-05, rEXP]{item-code}
+  \begin{syntax}
+    item-code = <code>
+  \end{syntax}
+
   该选项用来设置展示数据库中每条记录的代码。你可以使用 \cs{dbuse} 来展示属性的
   值。
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/sep},
-  desc = {= \meta{sep spec}},
-  init = {,~\~}
-}
-\begin{Syntax}
-  \meta{attr}/sep = \meta{separator} \\
-  \meta{attr}/sep = \{ \\
-  ~~\meta{separator between two}, \\
-  ~~\meta{separator between more than two}, \\
-  ~~\meta{separator between final two} \\
-  \}
-\end{Syntax}
+\changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
+\begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+  \begin{syntax}
+    <attr>/sep = <separator> \\
+    <attr>/sep = \{ \\
+    ~~\meta{separator between two}, \\
+    ~~\meta{separator between more than two}, \\
+    ~~\meta{separator between final two} \\
+    \} \\
+    <attr>/sep = \{ \\
+    ~~\meta{separator before year}, \\
+    ~~\meta{separator between year and month}, \\
+    ~~\meta{separator between month and day}, \\
+    ~~\meta{separator after day} \\
+    \} \\
+  \end{syntax}
 
-  该选项只适用于类型为 |clist| 的属性,用来设置列表间元素的间隔。第一个版本接
-  受一个参数,将所有的元素间隔设置为 \meta{separator}。第二个版本接受逗号分隔
-  的三个参数,分别用来设置只有两个元素时的分隔符 \meta{separator between two},
-  超过两个元素时的分隔符 \meta{separator between more than two},和最后两个元
-  素之间的分隔符 \meta{separator between final two}。
+  该选项只适用于类型为 |clist| 或 |date| 的属性,用来设置列表间元素的间隔。参
+  数为一个 \meta{separator} 时,所有元素间的分隔符被设置为 \meta{separator}。
+  \meta{separator before year} 和 \meta{separator after day} 被设置为空。
+\end{option}
 
+  参数为3个元素的逗号分隔的列表时,此选项用来设置列表元素的分隔符,分别用来设
+  置只有两个元素时的分隔符 \meta{separator between two},超过两个元素时的分隔
+  符 \meta{separator between more than two},和最后两个元素之间的分隔符
+  \meta{separator between final two}。对于类型为 |clist| 的属性,设置此选项时
+  如果参数列表数量不是1或者3会触发报错。
+
+\begin{verbatim}
+  % clist-attr is an attribute of database db
+  % suppose the val of clist-attr is { 1, 2, 3 }
+  \dbNewStyle{clist-sep}{db}{
+    clist-attr/sep = { ,~ },                % print 1, 2, 3
+    clist-attr/sep = { {,~}, {,~}, {and~} } % print 1, 2 and 3
+  }
+\end{verbatim}
+
+  参数为4个元素的逗号分隔的列表时,此选项用来设置日期的分隔符,分别用来设
+  置 \meta{year} 之前的分隔符 \meta{separator before year} ,\meta{year} 和
+  \meta{month} 之间的分隔符 \meta{separator between year and month} ,
+  \meta{month} 和 \meta{day} 之间的分隔符,以及 \meta{day} 之后的分隔符。对于
+  类型为 |date| 的属性,设置此选项时如果参数列表数量不是1或者4会触发报错。
+
+\begin{verbatim}
+  % date-attr is an attribute of database db
+  % suppose the val of date-attr is 2022/01/01
+  \dbNewStyle{date-sep}{db}{
+    date-attr/sep = -,             % print 2022-01-01
+    date-attr/sep = { |, -, -, | } % print |2022-01-01|
+  }
+\end{verbatim}
+
+\changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
+\begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+  \begin{syntax}
+    <attr>/zfill = <\TTF>
+  \end{syntax}
+
+  该选项只适用于类型为 |date| 的属性。控制输出月份和天时是否补零。
 \end{option}
 
 \subsubsection{装饰器}
@@ -385,69 +499,90 @@
   }
 \end{verbatim}
 
-\begin{option}{
-  opt = before-code,
-  desc = {= \meta{before code}}
-}
-  该选项用来设置在展示整个数据库之前需要执行的代码。
+\changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/wrapper}}
+\begin{option}[added=2022-01-08, rEXP]{<attr>/wrapper}
+  \begin{syntax}
+    <attr>/wrapper = <control sequence>
+  \end{syntax}
+
+  该选项只适用于类型为 |date| 的属性。\meta{control sequence} 只接收一个参数即
+  日期,如果设置了此选项,则最后输出的日期为
+  \meta{control sequence}\marg{date}。
 \end{option}
 
-\begin{option}{
-  opt = after-code,
-  desc = {= \meta{after code}}
-}
-  该选项用来设置在展示整个数据库之后需要执行的代码。
+\begin{option}[added=2022-01-05, rEXP]{before-code}
+  \begin{syntax}
+    before-code = <code>
+  \end{syntax}
+
+  该选项用来设置在展示整个数据库之\zhbefore 需要执行的代码。
 \end{option}
 
-\begin{option}{
-  opt = record-before-code,
-  desc = {= \meta{before code}}
-}
-  该选项用来设置在展示当前记录之前需要执行的代码。
+\begin{option}[added=2022-01-05, rEXP]{after-code}
+  \begin{syntax}
+    after-code = <code>
+  \end{syntax}
+
+  该选项用来设置在展示整个数据库之\zhafter 需要执行的代码。
 \end{option}
 
-\begin{option}{
-  opt = record-after-code,
-  desc = {= \meta{after code}}
-}
-  该选项用来设置在展示当前记录之后需要执行的代码。
+\changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
+\opt{record-after-code}}
+\begin{option}[added=2022-01-05, rEXP]{record-before-code}
+  \begin{syntax}
+    record-before-code = <code>
+  \end{syntax}
+
+  该选项用来设置在展示当前记录之\zhbefore 需要执行的代码。
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/before-code},
-  desc = {= \meta{before code}}
-}
-  该选项用来设置展示数据库中属性 \meta{attr} 对应数据之前需要执行的代码。
-  \cs{dbuse} 会在展示属性数据前执行此代码。
+\begin{option}[added=2022-01-05, rEXP]{record-after-code}
+  \begin{syntax}
+    record-after-code = <code>
+  \end{syntax}
+
+  该选项用来设置在展示当前记录之\zhafter 需要执行的代码。
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/after-code},
-  desc = {= \meta{after code}}
-}
-  该选项用来设置展示数据库中属性 \meta{attr} 对应数据之后需要执行的代码。
-  \cs{dbuse} 会在展示属性数据后执行此代码。
+\begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
+  \begin{syntax}
+    <attr>/before-code = <code>
+  \end{syntax}
+
+  该选项用来设置展示数据库中属性 \meta{attr} 对应数据之\zhbefore 需要执行的代
+  码。\cs{dbuse} 会在展示属性数据\zhbefore 执行此代码。
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/item-before-code},
-  desc = {= \meta{before code}}
-}
-  该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素前需要执行的代
-  码。
+\begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
+  \begin{syntax}
+    <attr>/after-code = <code>
+  \end{syntax}
+
+  该选项用来设置展示数据库中属性 \meta{attr} 对应数据之\zhafter 需要执行的代码。
+  \cs{dbuse} 会在展示属性数据\zhafter 执行此代码。
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/item-after-code},
-  desc = {= \meta{after code}}
-}
-  该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素后需要执行的代
-  码。
+\begin{option}[added=2022-01-05, rEXP]{<attr>/item-before-code}
+  \begin{syntax}
+    <attr>/item-before-code = <code>
+  \end{syntax}
+
+  该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素\zhbefore 需要
+  执行的代码。
 \end{option}
 
+\begin{option}[added=2022-01-05, rEXP]{<attr>/item-after-code}
+  \begin{syntax}
+    <attr>/item-after-code = <code>
+  \end{syntax}
+
+  该选项只适用于类型为 |clist| 的属性,用来设置展示列表每个元素\zhafter 需要执
+  行的代码。
+\end{option}
+
 \subsection{使用 \cs{dbNewReviewPoints} 定义复习点}
 
-\begin{function}{\dbNewReviewPoints}
+\begin{function}[added=2022-01-05]{\dbNewReviewPoints}
   \begin{syntax}
     \cs{dbNewReviewPoints} \marg{name} \marg{points}
   \end{syntax}
@@ -455,6 +590,8 @@
   定义名为 \meta{name} 的复习点。这是专门为错题本或复习所定制的功能,
   \meta{points}是一系列整数,现在假设每道错题你都将写错时的日期记录在了 |date|
   属性中,并且你希望每隔2,5,15天复习一次。下面的代码给出了一个实现示例。
+\end{function}
+
 \begin{verbatim}
   \dbNewReviewPoints{review-point}{2, 5, 15}            % 定义复习点
   \begin{dbFilters}
@@ -463,33 +600,34 @@
   \end{dbFilters}
   \dbNewStyle{review-style}{ques}{filter=filter1}       % 定义展示样式
 \end{verbatim}
-\end{function}
 
 \subsection{在 \env{dbFilters} 环境中定义过滤器}
 
-\noindent\DescribeEnv{dbFilters}
-\begin{Syntax}*
-  |\begin{dbFilters}|\marg{database} \\
-  ~~\meta{code}
-  |\end{dbFilters}| \\
-\end{Syntax}
+\begin{environment}[added=2022-01-05]{dbFilters}
+  \begin{syntax}
+    |\begin{dbFilters}|\marg{database} \\
+    ~~\meta{code}
+    |\end{dbFilters}| \\
+  \end{syntax}
 
-\env{dbFilters}用来定义过滤器,此环境中定义了 \cs{dbNewConditional} 命令用来定
-义条件和 \cs{dbCombineConditionals} 命令用来组合条件定义过滤器。过滤器独立于每
-个 \meta{database},这意味着你可以在不同数据库中定义名称相同的过滤条件和过滤器。
+  \env{dbFilters}用来定义过滤器,此环境中定义了 \cs{dbNewConditional} 命令用来
+  定义条件和 \cs{dbCombineConditionals} 命令用来组合条件定义过滤器。过滤器独立
+  于每个 \meta{database},这意味着你可以在不同数据库中定义名称相同的过滤条件和
+  过滤器。
+\end{environment}
 
-\begin{function}{\dbNewConditional, \dbNewConditional*}
+\begin{function}[added=2022-01-05, updated=2022-01-08]{\dbNewConditional, \dbNewConditional*}
   \begin{syntax}
     \cs{dbNewConditional}  \marg{name}        \marg{attr} \marg{cond spec} \\
     \cs{dbNewConditional}* \marg{name}        \marg{attr} \marg{cond spec} \\[2pt]
-    \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{relation} \\
-    \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{relation} \\
+    \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{expr} \\
+    \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \\
     \cs{dbNewConditional}  \marg{name} \marg{str/tl attr} \marg{regex expr} \\
     \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \\
     \cs{dbNewConditional}  \marg{name}  \marg{clist attr} \marg{val list} \\
     \cs{dbNewConditional}* \marg{name}  \marg{clist attr} \marg{val list} \\
-    \cs{dbNewConditional}  \marg{name}   \marg{date attr} \{\meta{review points}\textbar\meta{date}\} \\
-    \cs{dbNewConditional}* \marg{name}   \marg{date attr} \marg{relation}
+    \cs{dbNewConditional}  \marg{name}   \marg{date attr} \marg{expr}
+    \cs{dbNewConditional}* \marg{name}   \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \\
   \end{syntax}
 
   \cs{dbNewConditional} 用来定义名为 \meta{name} 的条件,\meta{attr} 指定条件
@@ -496,14 +634,18 @@
   所绑定的属性,在 \meta{cond spec} 中可以用 \cs{dbval} 指代属性的值。
 \end{function}
 
-  对于类型为 |int| 和 |fp| 的属性,两个版本的定义是一致的,\meta{relation} 可
-  以是单个关系式,比如 |\dbval > 3|,也可以是组合关系式,比如
-  |\dbval > 3 && \dbval < 10.2|。支持的操作符有 |<, >, =, ==, !=, >=, <=, !|。
+  \changes{1.3}{2022-01-10}{Update doc}{truncated division}
+  对于类型为 |int| 和 |fp| 的属性,\meta{expr} 传递给 \cs{int_compare:nTF} 或
+  \cs{fp_compare:nTF} 处理。
+  \begin{note}
+    |/| 为四舍五入除法,截断除法请用 \cs{dbIntDivTruncate}。
+  \end{note}
 
   对于类型为 |str| 和 |tl| 的属性,\meta{regex} 为正则表达式,
   \cs{dbNewConditional} 表示部分匹配,\cs{dbNewConditional*} 表示整体匹配。
+
 \begin{verbatim}
-  \dbNewConditional{cond1}{str-attr}{abc}  % 匹配 abc, abcd, 1abc, =abc= 等
+  \dbNewConditional {cond1}{str-attr}{abc} % 匹配 abc, abcd, 1abc, =abc= 等
   \dbNewConditional*{cond2}{str-attr}{abc} % 只匹配 abc
 \end{verbatim}
 
@@ -513,16 +655,19 @@
   (列表)中条件才成立。
 
 \begin{verbatim}
-  \dbNewConditional{cond1}{clist-attr}{a, b, c}  % a, b, d 满足条件
+  \dbNewConditional {cond1}{clist-attr}{a, b, c} % a, b, d 满足条件
   \dbNewConditional*{cond2}{clist-attr}{a, b, c} % a, b, d 不满足条件
 \end{verbatim}
 
-  对于类型为 |date| 的属性,\cs{dbNewConditional} 使用复习点来定义过滤条件,
-  \meta{review points} 是 \cs{dbNewReviewPoints} 定义的复习点,\meta{date} 是
-  用来比较的日期;\cs{dbNewConditional*} 使用\textbf{单个}关系式来定义过滤条件。
-  支持的操作符有 |<, >, =, ==, !=, >=, <=|。
+  \changes{1.3}{2022-01-08}{Update logic}{swap definition of starred and
+  unstarred conditionals of date}
+  对于类型为 |date| 的属性,\cs{dbNewConditional} 定义的条件后续处理中会将
+  \meta{expr} 中的所有日期转换成相对\textit{1971年1月1日}的一个整数值,然后将
+  处理后的表达式传递给 \cs{int_compare:nTF} 做进一步处理;
+  \cs{dbNewConditional*} 使用复习点来定义过滤条件,\meta{review points} 是
+  \cs{dbNewReviewPoints} 定义的复习点,\meta{date} 是用来比较的日期。
 
-\begin{function}{\dbCombineConditionals}
+\begin{function}[added=2022-01-05]{\dbCombineConditionals}
   \begin{syntax}
     \cs{dbCombineConditionals} \marg{name} \marg{cond combination} \oarg{info}
   \end{syntax}
@@ -537,51 +682,56 @@
 
 \subsection{使用 \env{dbitem} 环境存储数据}
 
-\noindent\DescribeEnv{dbitem}
-\begin{Syntax}*
-  |\begin{dbitem}|\marg{database}[ \\
-  ~~\meta{attr1} = \meta{val1}, \\
-  ~~\meta{attr2} = \meta{val2}, \\
-  ~~\ldots{} \\
-  ] \\
-  ~~\meta{code} \\
-  |\end{dbitem}|
-\end{Syntax}
+\begin{environment}[added=2022-01-05]{dbitem}
+  \begin{syntax}
+    |\begin{dbitem}|\marg{database}[ \\
+    ~~\meta{attr1} = \meta{val1}, \\
+    ~~\meta{attr2} = \meta{val2}, \\
+    ~~\ldots{} \\
+    ] \\
+    ~~\meta{code} \\
+    |\end{dbitem}|
+  \end{syntax}
 
   \env{dbitem} 环境用来存储数据。有两种存储数据的方法,较短的数据可以在选项列
   表中通过键值对设置值,较长的数据可以在 \meta{code} 中使用 \cs{dbsave} 存储。
   \cs{dbsave}会覆盖选项中设置的值。没有设置的值将会被设置为全局默认值,下面给
   出一个存储示例。
+\end{environment}
 
 \begin{verbatim}
-  \begin{dbitem}[date=2022-01-01, info=测试]
+  \begin{dbitem}[date = 2022-01-01, info = 测试]
     \dbsave{question}{这是一个测试问题}
-    \dbsave{answer}{这是一个测试答案}
+    \dbsave{answer}  {这是一个测试答案}
   \end{dbitem}
 \end{verbatim}
 
 \subsection{\cs{dbsave} 和 \cs{dbuse}}
 
-\begin{function}{\dbsave}
+\changes{1.3}{2022-01-08}{Add macro}{\cs{dbsave*}}
+\begin{function}[added=2022-01-05, updated=2022-01-08]{\dbsave, \dbsave*}
   \begin{syntax}
-    \cs{dbsave} \marg{attr} \marg{data}
+    \cs{dbsave}  \marg{attr} \marg{data} \\
+    \cs{dbsave}* \marg{attr} \marg{data}
   \end{syntax}
 
-  \cs{dbsave} 用来存储数据,只能在 \env{item} 环境中使用。
+  \cs{dbsave} 用来存储数据,只能在 \env{item} 环境中使用。使用 \cs{dbsave*} 存
+  储的数据会被 \cs{exp_not:n} 包裹。
 \end{function}
 
-\begin{function}[EXP]{\dbuse}
+\changes{1.2}{2022-01-08}{Update macro}{make \cs{dbuse} fully-expandable}
+\begin{function}[added=2022-01-05, updated=2022-01-08, EXP]{\dbuse}
   \begin{syntax}
-    \cs{dbuse}  \marg{attr}
+    \cs{dbuse} \marg{attr}
   \end{syntax}
 
-  \cs{dbuse} 用来使用数据,只能在 \opt{item-code} 选项中使用。\cs{dbuse} 是可
+  \cs{dbuse} 用来展示数据,只能在 \opt{item-code} 选项中使用。\cs{dbuse} 是可
   展开的。
 \end{function}
 
 \subsection{条件判别式}
 
-\begin{function}[EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
+\begin{function}[added=2022-01-05, EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
   \begin{syntax}
     \cs{dbIfEmptyTF} \marg{true code} \marg{false code} \\
     \cs{dbIfEmptyT} \marg{true code} \\
@@ -599,33 +749,68 @@
   }
 \end{verbatim}
 
-\subsection{特殊命令}
+\changes{1.2}{2022-01-08}{Remove macros}{\cs{dbItemIfEmpty(TF)}, \cs{dbClistItemIfEmpty(TF)}}
 
-\pkg{dbshow} 定义了一些特殊的命令,会根据语境展开为不同的内容。
+\subsection{表达式函数}
 
-\DescribeMacro{\dbval}当前属性的值,只能在 \cs{dbNewConditional} 中使用
+\changes{1.3}{2022-01-10}{Add macros}{expression function aliases}
+\begin{function}[added=2022-01-10, EXP]{
+  \dbIntAbs, \dbIntSign, \dbIntDivRound, \dbIntDivTruncate, \dbIntMax,
+  \dbIntMin, \dbIntMod, \dbFpSign,
+}
+  \begin{syntax}
+    \cs{dbIntAbs} \Arg{intexpr}
+    \cs{dbIntSign} \Arg{intexpr}
+    \cs{dbIntDivRound} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntDivTruncate} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntMax} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntMin} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntMod} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbFpSign} \Arg{fpexpr}
+  \end{syntax}
+  \cs{dbIntAbs} 等同于 \cs{int_abs:n} \\
+  \cs{dbIntSign} 等同于 \cs{int_sign:n} \\
+  \cs{dbIntDivRound} 等同于 \cs{int_div_round:nn} \\
+  \cs{dbIntDivTruncate} 等同于 \cs{int_div_truncate:nn} \\
+  \cs{dbIntMax} 等同于 \cs{int_max:nn} \\
+  \cs{dbIntMin} 等同于 \cs{int_min:nn} \\
+  \cs{dbIntMod} 等同于 \cs{int_mod:nn} \\
+  \cs{dbFpSign} 等同于 \cs{fp_sign:n} \\
+   详细的文档见 \pkg{interface3} \\
+\end{function}
 
-\DescribeMacro{\dbDatabase}数据库名称
+\subsection{特殊命令}
 
-\DescribeMacro{\dbFilterName}过滤器名称
+\pkg{dbshow} 定义了一些特殊的命令,会根据语境展开为不同的内容。
 
-\DescribeMacro{\dbFilterInfo}过滤器信息
+\changes{1.1}{2022-01-05}{Add macro}{
+  \cs{dbarabic}, \cs{dbalph}, \cs{dbAlph}, \cs{dbroman},
+  \cs{dbRoman}
+}
+\changes{1.1}{2022-01-06}{Fix bug}{\cs{dbIndex} not defined}
+\begin{function}[added=2022-01-05, EXP]{
+  \dbval, \dbDatabase, \dbFilterName, \dbFilterInfo,
+  \dbIndex, \dbarabic, \dbalph, \dbAlph, \dbroman, \dbRoman
+}
+\begin{tblr}{ll}
+  \cs{dbval} & 当前属性的值 \\
+  \cs{dbDatabase} & 数据库名称 \\
+  \cs{dbFilterName} & 当前样式过滤器的名称 \\
+  \cs{dbFilterInfo} & 当前样式过滤器的相关信息 \\
+  \cs{dbIndex} & 数据索引,等同于 \cs{dbuse}|{id}| \\
+  \cs{dbarabic} & 用数字表示的查询集数据计数 \\
+  \cs{dbalph} & 用小写字母表示的查询集数据计数 \\
+  \cs{dbAlph} & 用大写字母表示的查询集数据计数 \\
+  \cs{dbroman} & 用小写罗马字母表示的查询集数据计数 \\
+  \cs{dbroman} & 用大写罗马字母表示的查询集数据计数 \\
+  \end{tblr}
+\end{function}
 
-\DescribeMacro{\dbIndex}原始数据索引,等同于 |\dbuse{id}| 但是 \cs{dbuse} 是不可展开的
-
-\DescribeMacro{\dbarabic}用数字表示的查询集数据计数
-
-\DescribeMacro{\dbalph}用小写字母表示的查询集数据计数
-
-\DescribeMacro{\dbAlph}用小写字母表示的查询集数据计数
-
-\DescribeMacro{\dbroman}用小写罗马数字表示的查询集数据计数
-
-\DescribeMacro{\dbRoman}用大写罗马数字表示的查询集数据计数
-
 \section{错题本示例}
 见第 \ref{sec:example} 节。
 
+\changes{1.1}{2022-01-07}{Update doc}{improve example}
+
 \title{
   Package \pkg{dbshow} \version%
   \protect\footnote{%
@@ -653,13 +838,26 @@
 filtering, data sorting and data display. All data is saved once and then you
 can display these data with custom filters, orders and styles.
 
+\changes{1.2}{2022-01-09}{Add doc}{descripton for expansion}
+\begin{itemize}
+  \item Macros with a $\star$ are fully-expandable;
+  \item Macros with a \ding{73} are restricted-expandable;
+  \item Macros without appending a special symbol are nonexpandable;
+  \item Options with a $\star$ \textit{do not} affect the expandability of
+    related macros;
+  \item Options with a \ding{73} affect the expandability of related macros
+    according to its value;
+  \item Options without appending a special symbol make the related macros
+    nonexpandable.
+\end{itemize}
+
 \subsection{Data Types}
 
 The package constructs 6 types based on the internal typed of \pkg{expl3}:
 \begin{Description}[\texttt{clist}]
   \item[\texttt{date}]
-    date based on \pkg{datetime2} in iso format, supports comparison,
-    sorting (converting to |str|), default \cs{Today}.
+    date saved in |yyyy/mm/dd| format, supports comparison, sorting
+    (converting to string), default \cs{dbtoday}.
   \item[\texttt{str}]
     string,supports regex match and sorting, default empty.
   \item[\texttt{tl}]
@@ -672,8 +870,15 @@
     comma list, default empty.
 \end{Description}
 
+\changes{1.3}{2022-01-08}{Remove dependency}{\pkg{datatime2}}
+All types are internal types of \pkg{expl3} except |date| type, which provides
+by \pkg{dbshow} itself and supports converting to integer and printing with
+style.
+
 \subsection{Comparison to \pkg{datatool}}
 
+\changes{1.2}{2022-01-07}{Add doc}{add comparison to \pkg{datatool}}
+
 \pkg{dbshow} and \pkg{datatool} implement the same core functions. But
 \pkg{dbshow} is based on \pkg{expl3} and it supports string regex and
 multi-level sorting. \pkg{dbshow} tries to divide style from the contents
@@ -692,7 +897,7 @@
 
 \subsection{Create, Display and Clear Database}
 
-\begin{function}{\dbNewDatabase, \dbNewDatabase*}
+\begin{function}[added=2022-01-05]{\dbNewDatabase, \dbNewDatabase*}
   \begin{syntax}
     \cs{dbNewDatabase} \oarg{base database} \marg{database} \{ \\
     ~~\meta{attr1} = \meta{type spec1}, \\
@@ -713,10 +918,10 @@
 The unstarred form always replace the old definition, while starred form
 appends the new options.
 
-\begin{Syntax}
+\begin{syntax}
   \meta{attr} = \meta{type} \\
-  \meta{attr} = \meta{type}\textbar\meta{default}
-\end{Syntax}
+  \meta{attr} = \meta{type}\orbar\meta{default}
+\end{syntax}
 
 The first form defines the \meta{attr} as \meta{type}, and the second also
 sets the default value.
@@ -736,7 +941,7 @@
   }
 \end{verbatim}
 
-\begin{function}{\dbshow}
+\begin{function}[added=2022-01-05]{\dbshow}
   \begin{syntax}
     \cs{dbshow} \marg{style} \marg{database}
   \end{syntax}
@@ -744,36 +949,45 @@
   Show the \meta{database} with \meta{style}.
 \end{function}
 
-\begin{function}{\dbclear}
+\changes{1.2}{2022-01-07}{Add macro}{\cs{dbclear}}
+\begin{function}[added=2022-01-07]{\dbclear}
   \begin{syntax}
     \cs{dbclear} \marg{database}
   \end{syntax}
 
   Clear the content of \meta{database}.
-
 \end{function}
 
 \subsection{\cs{dbNewStyle} and Style Options}
 
-\begin{function}{\dbNewStyle}
+\begin{function}[added=2022-01-05]{\dbNewStyle}
   \begin{syntax}
     \cs{dbNewStyle} \oarg{base styles} \marg{style} \marg{database} \marg{opts}
   \end{syntax}
 
-Define a new \meta{style} that binds to \meta{database}. The style can inherit
-from a list of \meta{base styles} such as
-|\dbNewStyle[base1, base2]{new-style}{ques}{}|.
+  Define a new \meta{style} that binds to \meta{database}. The style can
+  inherit from a list of \meta{base styles} such as
+  |\dbNewStyle[base1, base2]{new-style}{ques}{}|.
 \end{function}
 
 \subsubsection{General Options}
 
-\begin{option}{opt=filter, desc={= \meta{filter}}, init=-none-}
+\begin{option}[added=2022-01-05]{filter}
+  \begin{syntax}
+    filter = <filter>
+  \end{syntax}
+
   Set the \meta{filter} defined by \cs{dbCombineFilters}.
 \end{option}
 
-\begin{option}{opt=raw-filter, desc={= \meta{cond combination}}}
-  Set anonymous with defined conditionals. Two examples below perform the same
-  function.
+\changes{1.1}{2022-01-06}{Add option}{\opt{raw-filter}}
+\begin{option}[added=2022-01-06]{raw-filter}
+  \begin{syntax}
+    raw-filter = <conditional expression>
+  \end{syntax}
+
+  Set anonymous with conditionals defined by \cs{dbNewConditional}. Two
+  filters shows in the code below have the same meaning.
 \end{option}
 
 \begin{verbatim}
@@ -792,10 +1006,12 @@
   \dbNewStyle{style}{db}{filter=filter}
 \end{verbatim}
 
-\begin{option}{
-  opt = sort,
-  desc = {= \{ \meta{attr spec1}, \meta{attr spec2}, \ldots{} \}},
-}
+\changes{1.2}{2022-01-08}{Fix bug}{string sorting bug}
+\begin{option}[added=2022-01-05]{sort}
+  \begin{syntax}
+    sort = \{ <attr spec1>, <attr spec2>, \ldots{} \}
+  \end{syntax}
+
   Set sorting rules. Attributes of type |str, date, int, fp| is supported to
   sort.  Multi-level sort is allowed. \meta{attr} represents for ascending
   order, and \meta{attr}* represents for descending order. The example below
@@ -816,31 +1032,40 @@
   }
 \end{verbatim}
 
-\begin{option}{
-  opt = item-code,
-  desc = {= \meta{item code}}
-}
+\begin{option}[added=2022-01-05, rEXP]{item-code}
+  \begin{syntax}
+    item-code = <code>
+  \end{syntax}
+
   Set the code that show a single record. You can use \cs{dbuse} to display
   certian attribute.
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/sep},
-  desc = {= \meta{sep spec}},
-  init = {,~\~}
-}
-\begin{Syntax}
-  \meta{attr}/separator = \meta{separator} \\
-  \meta{attr}/separator = \{ \\
-  ~~\meta{separator between two}, \\
-  ~~\meta{separator between more than two}, \\
-  ~~\meta{separator between final two} \\
-  \}
-\end{Syntax}
+\changes{1.3}{2022-01-09}{Update option}{\opt{<attr>/sep}}
+\begin{option}[added=2022-01-05, updated=2022-01-08, rEXP]{<attr>/sep}
+  \begin{syntax}
+    <attr>/sep = <separator> \\
+    <attr>/sep = \{ \\
+    ~~\meta{separator between two}, \\
+    ~~\meta{separator between more than two}, \\
+    ~~\meta{separator between final two} \\
+    \} \\
+    <attr>/sep = \{ \\
+    ~~\meta{separator before year}, \\
+    ~~\meta{separator between year and month}, \\
+    ~~\meta{separator between month and day}, \\
+    ~~\meta{separator after day} \\
+    \} \\
+  \end{syntax}
 
-  Only for attributes of type |clist|. Set the separator between clist items.
-  The first form accept one arguments and set the seperator as \meta{sep}. The
-  second form is more complicated, the following documentation is quoted from
+  Only for attributes of type |clist| or |date|. Set the separator between
+  items. If the argument is an one-item comma list, all separators are set to
+  \meta{separator} but \meta{separator before year} and \meta{separator after
+  day} is set empty.
+\end{option}
+
+  If the argument is a comma list of 3 items, it is used to set the separator
+  between items of the comma list. Following documentation is quoted from
   \pkg{interface3}:
   \begin{quote}
     If the comma list has more than two items, the \meta{separator between
@@ -851,7 +1076,39 @@
     it is placed in the input stream, and a comma list with no items produces
     no output.
   \end{quote}
+  For attributes of type |clist|, incorrect number (numbers exclude 1 and 3)
+  of items of the argument will raise an error.
 
+\begin{verbatim}
+  % clist-attr is an attribute of database db
+  % suppose the val of clist-attr is { 1, 2, 3 }
+  \dbNewStyle{clist-sep}{db}{
+    clist-attr/sep = { ,~ },                % print 1, 2, 3
+    clist-attr/sep = { {,~}, {,~}, {and~} } % print 1, 2 and 3
+  }
+\end{verbatim}
+
+  If the argument is a comma list of 4 items, it is used to set the separators
+  of the date. For attributes of type |date|, incorrect number (numbers
+  exclude 1 and 4) will raise an error.
+
+\begin{verbatim}
+  % date-attr is an attribute of database db
+  % suppose the val of date-attr is 2022/01/01
+  \dbNewStyle{date-sep}{db}{
+    date-attr/sep = -,             % print 2022-01-01
+    date-attr/sep = { |, -, -, | } % print |2022-01-01|
+  }
+\end{verbatim}
+
+\changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/zfill}}
+\begin{option}[added=2022-01-08, EXP]{<attr>/zfill}
+  \begin{syntax}
+    <attr>/zfill = <\TTF>
+  \end{syntax}
+
+  Only for attributes of type |date|. Control whether to fill zero on the left
+  of the month or day.
 \end{option}
 
 \subsubsection{Decorators}
@@ -889,69 +1146,89 @@
   }
 \end{verbatim}
 
-\begin{option}{
-  opt = before-code,
-  desc = {= \meta{before code}}
-}
-  Set the \meta{before code} that is executed before displaying the database.
+\changes{1.3}{2022-01-08}{Add option}{\opt{<attr>/wrapper}}
+\begin{option}[added=2022-01-08, rEXP]{<attr>/wrapper}
+  \begin{syntax}
+    <attr>/wrapper = <control sequence>
+  \end{syntax}
+
+  Only for attributes of type |date|. Output of \cs{dbuse}\marg{date attr}
+  will be \meta{control sequence}\marg{date}.
 \end{option}
 
-\begin{option}{
-  opt = after-code,
-  desc = {= \meta{after code}}
-}
-  Set the \meta{after code} that is executed after displaying the database.
+\begin{option}[added=2022-01-05, rEXP]{before-code}
+  \begin{syntax}
+    before-code = <code>
+  \end{syntax}
+
+  Set the \meta{code} that is executed \enbefore displaying the database.
 \end{option}
 
-\begin{option}{
-  opt = record-before-code,
-  desc = {= \meta{before code}}
-}
-  Set the \meta{before code} that is executed before displaying the record.
+\begin{option}[added=2022-01-05, rEXP]{after-code}
+  \begin{syntax}
+    after-code = <code>
+  \end{syntax}
+
+  Set the \meta{code} that is executed \enafter displaying the database.
 \end{option}
 
-\begin{option}{
-  opt = record-after-code,
-  desc = {= \meta{after code}}
-}
-  Set the \meta{after code} that is executed after displaying the record.
+\changes{1.2}{2022-01-08}{Add options}{\opt{record-before-code},
+\opt{record-after-code}}
+\begin{option}[added=2022-01-05, rEXP]{record-before-code}
+  \begin{syntax}
+    record-before-code = <code>
+  \end{syntax}
+
+  Set the \meta{code} that is executed \enbefore displaying a record.
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/before-code},
-  desc = {= \meta{before code}}
-}
-  Set the \meta{before code} that is executed by \cs{dbuse} before displaying
+\begin{option}[added=2022-01-05, rEXP]{record-after-code}
+  \begin{syntax}
+    record-after-code = <code>
+  \end{syntax}
+
+  Set the \meta{code} that is executed \enafter displaying the record.
+\end{option}
+
+\begin{option}[added=2022-01-05, rEXP]{<attr>/before-code}
+  \begin{syntax}
+    <attr>/before-code = <code>
+  \end{syntax}
+
+  Set the \meta{code} that is executed by \cs{dbuse} \enbefore displaying
   certain attribute.
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/after-code},
-  desc = {= \meta{after code}}
-}
-  Set the \meta{after code} that is executed by \cs{dbuse} after displaying
+\begin{option}[added=2022-01-05, rEXP]{<attr>/after-code}
+  \begin{syntax}
+    <attr>/after-code = <code>
+  \end{syntax}
+
+  Set the \meta{code} that is executed by \cs{dbuse} \enafter displaying
   certain attribute.
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/item-before-code},
-  desc = {= \meta{before code}}
-}
-  Only for attributes of type |clist|. Set the \meta{after code} that is
-  excuted before displaying the item of the comma list.
+\begin{option}[added=2022-01-05, rEXP]{<attr>/item-before-code}
+  \begin{syntax}
+    <attr>/item-before-code = <code>
+  \end{syntax}
+
+  Only for attributes of type |clist|. Set the \meta{code} that is excuted
+  \enbefore displaying the item of the comma list.
 \end{option}
 
-\begin{option}{
-  opt = {\meta{attr}/item-after-code},
-  desc = {= \meta{after code}}
-}
-  Only for attributes of type |clist|. Set the \meta{after code} that is
-  excuted after displaying the item of the comma list.
+\begin{option}[added=2022-01-05, rEXP]{<attr>/item-after-code}
+  \begin{syntax}
+    <attr>/item-after-code = <code>
+  \end{syntax}
+
+  Only for attributes of type |clist|. Set the \meta{code} that is excuted
+  \enafter displaying the item of the comma list.
 \end{option}
 
 \subsection{Use \cs{dbNewReviewPoints} to Define Review Points}
 
-\begin{function}{\dbNewReviewPoints}
+\begin{function}[added=2022-01-05]{\dbNewReviewPoints}
   \begin{syntax}
     \cs{dbNewReviewPoints} \marg{name} \marg{points}
   \end{syntax}
@@ -960,6 +1237,8 @@
   something. \meta{points} is a list of integers. Suppose you record the date
   when you did not answer correctly and you plan to review every 2, 5 and 15
   days. The following code give what you want.
+\end{function}
+
 \begin{verbatim}
   \dbNewReviewPoints{review-point}{2, 5, 15}            % define points
   \begin{dbFilters}
@@ -968,35 +1247,35 @@
   \end{dbFilters}
   \dbNewStyle{review-style}{ques}{filter=filter1}       % define style
 \end{verbatim}
-\end{function}
 
 \subsection{Define Filters inside \env{dbFilters} Environment}
 
-\noindent\DescribeEnv{dbFilters}
-\begin{Syntax}*
-  |\begin{dbFilters}|\marg{database} \\
-  ~~\meta{code}
-  |\end{dbFilters}| \\
-\end{Syntax}
+\begin{environment}[added=2022-01-05]{dbFilters}
+  \begin{syntax}
+    |\begin{dbFilters}|\marg{database} \\
+    ~~\meta{code}
+    |\end{dbFilters}| \\
+  \end{syntax}
 
-Filters are defined inside \env{dbFilters} environment, inside which,
-\cs{dbNewConditional} is defined to declare conditionals and
-\cs{dbCombineConditionals} is defined to combine conditionals. Filters are
-independent in different databases, which means the same name of filters is
-allowed in different databases.
+  Filters are defined inside \env{dbFilters} environment, inside which,
+  \cs{dbNewConditional} is defined to declare conditionals and
+  \cs{dbCombineConditionals} is defined to combine conditionals. Filters are
+  independent in different databases, which means the same name of filters is
+  allowed in different databases.
+\end{environment}
 
-\begin{function}{\dbNewConditional, \dbNewConditional*}
+\begin{function}[added=2022-01-05, updated=2022-01-08]{\dbNewConditional, \dbNewConditional*}
   \begin{syntax}
     \cs{dbNewConditional}  \marg{name}        \marg{attr} \marg{cond spec} \\
     \cs{dbNewConditional}* \marg{name}        \marg{attr} \marg{cond spec} \\[2pt]
-    \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{relation} \\
-    \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{relation} \\
+    \cs{dbNewConditional}  \marg{name} \marg{int/fp attr} \marg{expr} \\
+    \cs{dbNewConditional}* \marg{name} \marg{int/fp attr} \marg{expr} \\
     \cs{dbNewConditional}  \marg{name} \marg{str/tl attr} \marg{regex expr} \\
     \cs{dbNewConditional}* \marg{name} \marg{str/tl attr} \marg{regex expr} \\
     \cs{dbNewConditional}  \marg{name}  \marg{clist attr} \marg{val list} \\
     \cs{dbNewConditional}* \marg{name}  \marg{clist attr} \marg{val list} \\
-    \cs{dbNewConditional}  \marg{name}   \marg{date attr} \{\meta{review points}\textbar\meta{date}\} \\
-    \cs{dbNewConditional}* \marg{name}   \marg{date attr} \marg{relation}
+    \cs{dbNewConditional}  \marg{name}   \marg{date attr} \marg{expr}
+    \cs{dbNewConditional}* \marg{name}   \marg{date attr} \{\meta{review points}\orbar\meta{date}\} \\
   \end{syntax}
 
   Define the conditional named \meta{name} that binds to \meta{attr}. \cs{dbval}
@@ -1003,36 +1282,43 @@
   is replaced with the real value of the attribute inside the \meta{cond spec}.
 \end{function}
 
-For attributes of type |int| and |fp|, two forms have the same definition.
-\meta{relation} can be a single relation formula, such as |\dbval > 3|, or the
-combination of several relation formulas, such as |\dbval > 3 && \dbval < 10.2|.
-Supported operators are |<, >, =, ==, !=, >=, <=, !|.
+  \changes{1.3}{2022-01-10}{Update doc}{truncated division}
+  For attributes of type |int| and |fp|, \meta{expr} is passed to
+  \cs{int_compare:nTF} or \cs{fp_compare:nTF}.
+  \begin{note}
+    Division using |/| rounds to the closest integer. Use \cs{dbIntDivTruncate} to rounds
+    the result toward 0.
+  \end{note}
 
-For attribute of type |str| and |tl|, unstarred form matches any part while
-starred form matches the whole part with the \meta{regex expr}.
+  For attribute of type |str| and |tl|, unstarred form matches any part while
+  starred form matches the whole part with the \meta{regex expr}.
+
 \begin{verbatim}
-  \dbNewConditional{cond1}{str-attr}{abc}  % match abc, abcd, 1abc, =abc=, etc
+  \dbNewConditional {cond1}{str-attr}{abc}  % match abc, abcd, 1abc, =abc=, etc
   \dbNewConditional*{cond2}{str-attr}{abc} % only match abc
 \end{verbatim}
 
-For attributes of type |clist|, the conditional defined by unstarred form is
-true if any item of \meta{val list} is in the comma list. While the
-conditional defined by starred form is true only if every item of \meta{val
-list} is in the comma list. As is showed below, for |cond1|, |a| is in
-|{a, b, d}| so |cond1| is true. While |c| is not in |{a, b, d}| so |cond2| is
-false.
+  For attributes of type |clist|, the conditional defined by unstarred form is
+  true if any item of \meta{val list} is in the comma list. While the
+  conditional defined by starred form is true only if every item of \meta{val
+  list} is in the comma list. As is showed below, for |cond1|, |a| is in
+  |{a, b, d}| so |cond1| is true. While |c| is not in |{a, b, d}| so |cond2|
+  is false.
 
 \begin{verbatim}
-  \dbNewConditional{cond1}{clist-attr}{a, b, c}  % {a, b, d} -> true
+  \dbNewConditional {cond1}{clist-attr}{a, b, c}  % {a, b, d} -> true
   \dbNewConditional*{cond2}{clist-attr}{a, b, c} % {a, b, d} -> false
 \end{verbatim}
 
-For attributes of type |date|, unstarred form uses \meta{review points} to
-define the conditional and \meta{date} is the date to be compared. The starred
-form define the conditional with \textbf{single} relation formula. Supported
-operators are |<, >, =, ==, !=, >=, <=|.
+  \changes{1.3}{2022-01-08}{Update logic}{swap definition of starred and
+  unstarred conditionals of date}
+  For attributes of type |date|, unstarred form replace each date with a
+  integer representing for the days between \meta{date} and
+  \textit{1971/01/01}, and the result is passed to \cs{int_compare:nTF}.
+  Starred form defines the conditional with review points defined by
+  \cs{dbNewRdbNewReviewPoints} and \meta{date} is the date to be compared.
 
-\begin{function}{\dbCombineConditionals}
+\begin{function}[added=2022-01-05]{\dbCombineConditionals}
   \begin{syntax}
     \cs{dbCombineConditionals} \marg{name} \marg{cond combination} \oarg{info}
   \end{syntax}
@@ -1046,43 +1332,49 @@
 
 \subsection{Store Data with \env{dbitem} Environment}
 
-\noindent\DescribeEnv{dbitem}
-\begin{Syntax}*
-  |\begin{dbitem}|\marg{database}[ \\
-  ~~\meta{attr1} = \meta{val1}, \\
-  ~~\meta{attr2} = \meta{val2}, \\
-  ~~\ldots{} \\
-  ] \\
-  ~~\meta{code} \\
-  |\end{dbitem}|
-\end{Syntax}
+\begin{environment}[added=2022-01-05]{dbitem}
+  \begin{syntax}
+    |\begin{dbitem}|\marg{database}[ \\
+    ~~\meta{attr1} = \meta{val1}, \\
+    ~~\meta{attr2} = \meta{val2}, \\
+    ~~\ldots{} \\
+    ] \\
+    ~~\meta{code} \\
+    |\end{dbitem}|
+  \end{syntax}
 
-The data are stored with \env{dbitem} environment in two ways. Smaller data
-can be stored in the option list and the bigger data can be stored by
-\cs{dbsave}, which will suppress the value set by the option list. An example
-code is showned below.
+  The data are stored with \env{dbitem} environment in two ways. Smaller data
+  can be stored in the option list and the bigger data can be stored by
+  \cs{dbsave}, which will suppress the value set by the option list. An
+  example code is showned below.
+\end{environment}
 
 \begin{verbatim}
   \begin{dbitem}[date=2022-01-01, info=test]
     \dbsave{question}{This is a test question.}
-    \dbsave{answer}{This is the correct answer of the question.}
+    \dbsave{answer}  {This is a test answer.}
   \end{dbitem}
 \end{verbatim}
 
 \subsection{\cs{dbsave} and \cs{dbuse}}
 
-\begin{function}{\dbsave}
+\changes{1.3}{2022-01-08}{Add macro}{\cs{dbsave*}}
+\begin{function}[added=2022-01-05, updated=2022-01-08]{\dbsave, \dbsave*}
   \begin{syntax}
-    \cs{dbsave} \marg{attr} \marg{data}
+    \cs{dbsave}  \marg{attr} \marg{data} \\
+    \cs{dbsave}* \marg{attr} \marg{data}
   \end{syntax}
 
   \cs{dbsave} save the \meta{data} to \meta{attr} of current record.
   \cs{dbsave} can be used only inside the \env{dbitem} environment.
+  \meta{data} stored by \cs{dbsave*} is wrapped with \cs{exp_not:n} while
+  \meta{data} stored by \cs{dbsave} keeps the same.
 \end{function}
 
-\begin{function}[EXP]{\dbuse}
+\changes{1.2}{2022-01-08}{Update macro}{make \cs{dbuse} fully-expandable}
+\begin{function}[added=2022-01-05, updated=2022-01-08, EXP]{\dbuse}
   \begin{syntax}
-    \cs{dbuse}  \marg{attr}
+    \cs{dbuse} \marg{attr}
   \end{syntax}
 
   Display the value of \meta{attr} of current record. \cs{dbuse} is
@@ -1091,7 +1383,7 @@
 
 \subsection{Conditionals}
 
-\begin{function}[EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
+\begin{function}[added=2022-01-05, EXP]{\dbIfEmptyT, \dbIfEmptyF, \dbIfEmptyTF}
   \begin{syntax}
     \cs{dbIfEmptyTF} \marg{true code} \marg{false code} \\
     \cs{dbIfEmptyT} \marg{true code} \\
@@ -1110,43 +1402,77 @@
   }
 \end{verbatim}
 
-\subsection{Special Macros}
+\changes{1.2}{2022-01-08}{Remove macros}{\cs{dbItemIfEmpty(TF)}, \cs{dbClistItemIfEmpty(TF)}}
 
-Some special macros are defined to expand to different contents according to context.
+\subsection{Expression Functions}
 
-\DescribeMacro{\dbval} Attribute value, only accessible in \cs{dbNewConditional}.
+\changes{1.3}{2022-01-10}{Add macros}{expression function aliases}
+\begin{function}[added=2022-01-10, EXP]{
+  \dbIntAbs, \dbIntSign, \dbIntDivRound, \dbIntDivTruncate, \dbIntMax,
+  \dbIntMin, \dbIntMod, \dbFpSign,
+}
+  \begin{syntax}
+    \cs{dbIntAbs} \Arg{intexpr}
+    \cs{dbIntSign} \Arg{intexpr}
+    \cs{dbIntDivRound} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntDivTruncate} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntMax} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntMin} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbIntMod} \Arg{intexpr_1} \marg{intexpr_2}
+    \cs{dbFpSign} \Arg{fpexpr}
+  \end{syntax}
+  \cs{dbIntAbs} is identical to \cs{int_abs:n} \\
+  \cs{dbIntSign} is identical to \cs{int_sign:n} \\
+  \cs{dbIntDivRound} is identical to \cs{int_div_round:nn} \\
+  \cs{dbIntDivTruncate} is identical to \cs{int_div_truncate:nn} \\
+  \cs{dbIntMax} is identical to \cs{int_max:nn} \\
+  \cs{dbIntMin} is identical to \cs{int_min:nn} \\
+  \cs{dbIntMod} is identical to \cs{int_mod:nn} \\
+  \cs{dbFpSign} is identical to \cs{fp_sign:n} \\
+   Detailed documentation see \pkg{interface3} \\
+\end{function}
 
-\DescribeMacro{\dbDatabase} Database name.
+\subsection{Special Macros}
 
-\DescribeMacro{\dbFilterName} Filter name.
+Some special macros are defined to expand to different contents according to context.
 
-\DescribeMacro{\dbFilterInfo} Filter information.
+\changes{1.1}{2022-01-05}{Add macro}{
+  \cs{dbarabic}, \cs{dbalph}, \cs{dbAlph}, \cs{dbroman},
+  \cs{dbRoman}
+}
+\changes{1.1}{2022-01-06}{Fix bug}{\cs{dbIndex} not defined}
+\begin{function}[added=2022-01-05, EXP]{
+  \dbval, \dbDatabase, \dbFilterName, \dbFilterInfo,
+  \dbIndex, \dbarabic, \dbalph, \dbAlph, \dbroman, \dbRoman
+}
+\begin{tblr}{ll}
+  \cs{dbval} & Attribute value, only according in \cs{dbNewConditional}. \\
+  \cs{dbDatabase} & Database name. \\
+  \cs{dbFilterName} & Filter name. \\
+  \cs{dbFilterInfo} & Filter information. \\
+  \cs{dbIndex} & Record index, identical to \cs{dbuse}|{id}| \\
+  \cs{dbarabic} & Show the counter of query set as digits. \\
+  \cs{dbalph} & Show the counter of query set as lowercase letters. \\
+  \cs{dbAlph} & Show the counter of query set as uppercase letters. \\
+  \cs{dbroman} & Show the counter of query set as lowercase roman numerals. \\
+  \cs{dbroman} & Show the counter of query set as uppercase roman numerals. \\
+  \end{tblr}
+\end{function}
 
-\DescribeMacro{\dbIndex} Index of original records, which is equal to |\rvuse{id}| but \cs{rvuse} is nonexpandable.
-
-
-\DescribeMacro{\dbarabic} Show the counter of query set as digits.
-
-\DescribeMacro{\dbalph} Show the counter of query set as lowercase letters.
-
-\DescribeMacro{\dbAlph} Show the counter of query set as uppercase letters.
-
-\DescribeMacro{\dbroman} Show the counter of query set as roman numerals.
-
-\DescribeMacro{\dbRoman} Show the counter of query set as Roman numerals.
-
 \section{Example of Flaw Sweeper Template}
 \label{sec:example}
 
+\changes{1.1}{2022-01-07}{Update doc}{improve example}
+
 \begin{tcblisting}{enhanced jigsaw,lower separated=false,
-leftlower=0pt,rightlower=0pt,
-colframe=red!50!black,colback=yellow!10!white,
-listing options={style=tcblatex,texcsstyle=*\color{red!70!black}},
-listing and comment,
-pdf comment,freeze pdf,
-compilable listing,
-breakable,
-run pdflatex
+  leftlower=0pt,rightlower=0pt,
+  colframe=red!50!black,colback=yellow!10!white,
+  listing options={style=tcblatex,texcsstyle=*\color{red!70!black}},
+  listing and comment,
+  pdf comment,freeze pdf,
+  compilable listing,
+  breakable,
+  run pdflatex
 }
 \documentclass{article}
 \usepackage{amsmath, physics}
@@ -1202,7 +1528,8 @@
 \begin{dbFilters}{ques-book}
   \dbNewConditional{hard}{labels}{hard}
   \dbNewConditional{bad}{count}{\dbval > 1}
-  \dbNewConditional{review}{date}{review|2022-01-07}
+  \dbNewConditional*{review}{date}{review|2022/01/07}
+  \dbNewConditional{after}{date}{\dbval > 2022/01/02}
 \end{dbFilters}
 
 % show all questions with hyperlink to answers
@@ -1260,23 +1587,29 @@
   labels/sep = /,
 }
 
-% show all hard questions that have answered incorrectly for more than one
-% time with hyperlink to answers
+% show all hard questions that have been answered incorrectly for more than
+% one time with hyperlink to answers
 \dbNewStyle[hard]{bad}{ques-book}{
   before-code = {\section{Bad Questions}},
   raw-filter = {bad && hard},
 }
-% show all questions that plan to be reviewed on 2022-01-07 with hyperlink to
+% show all questions that plan to be reviewed on 2022/01/07 with hyperlink to
 % answers
 \dbNewStyle[hard]{review}{ques-book}{
   before-code = {\section{Questions to be Reviewed}},
   raw-filter = {review},
 }
+% show all questions that is record after 2022/01/02 with hyperlink to answers
+\dbNewStyle[hard]{after}{ques-book}{
+  before-code = {\section{Questions after 2022/01/02}},
+  raw-filter = {after},
+}
 
 \AtEndDocument{
   \dbshow{review}{ques-book}
   \dbshow{hard}{ques-book}
   \dbshow{bad}{ques-book}
+  \dbshow{after}{ques-book}
   \dbshow{ques}{ques-book}
   \dbshow{answer}{ques-book}
 }
@@ -1284,7 +1617,7 @@
 \begin{document}
 
 \begin{dbitem}{ques-book}[
-  date=2022-01-01,
+  date=2022/01/01,
   labels={math, equation, easy},
   count=2
   ]
@@ -1297,7 +1630,7 @@
 \end{dbitem}
 
 \begin{dbitem}{ques-book}[
-  date=2022-01-01,
+  date=2022/01/01,
   labels={math, equation, hard},
   count=3
   ]
@@ -1310,7 +1643,7 @@
 \end{dbitem}
 
 \begin{dbitem}{ques-book}[
-  date=2022-01-04,
+  date=2022/01/04,
   labels={math, integral, hard},
   count=1
   ]
@@ -1325,35 +1658,5 @@
 \end{document}
 \end{tcblisting}
 
-\section*{Change History}
-\markboth{Change History}{Change History}
-\addcontentsline{toc}{section}{Change History}
-\noindent
-\begin{tblr}{
-  colspec = {lll},
-  row{1} = {font=\bfseries},
-}
-  Date & Ver. & Describe \\
-  2022-01-05 & 1.0 & {
-    First version \\
-    Add macro: \cmd{\dbarabic}, \cmd{\dbalph}, \cmd{\dbAlph}, \cmd{\dbroman}, \cmd{\dbRoman}
-  } \\
-  2022-01-06 & & {
-    Fix bug: \cmd{\dbIndex} undefined \\
-    Add style option: \opt{raw-filter}
-  } \\
-  2022-01-07 & 1.1 & Improve example \\
-  2022-01-07 & 1.1.1 & Add macro: \cmd{\dbclear} \\
-  2022-01-07 & 1.1.2 & Add documentation: comparison to \pkg{datatool} \\
-  2022-01-08 & 1.2 & {
-    Fix str sorting bug \\
-    Remove macros: \cmd{\dbItemIfEmpty(TF)}, \cmd{\dbClistItemIfEmpty(TF)} \\
-    Make \cs{dbuse} expandable \\
-    Add option: \opt{record-before-code}, \opt{record-after-code}
-  } \\
-\end{tblr}
-
 \end{documentation}
-
-
 \end{document}

Modified: trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty	2022-01-10 21:27:44 UTC (rev 61559)
+++ trunk/Master/texmf-dist/tex/latex/dbshow/dbshow.sty	2022-01-10 21:27:56 UTC (rev 61560)
@@ -14,10 +14,9 @@
 % The Current Maintainer of this work is Li Changkai.
 %
 % This work consists of the files dbshow.sty, dbshow-doc.tex.
-\def\myfileversion{v1.2}
-\def\myfiledate{2022/01/08}
+\def\myfileversion{v1.3}
+\def\myfiledate{2022/01/10}
 \RequirePackage{expl3, xparse}
-\RequirePackage[calc]{datetime2}
 \ProvidesExplPackage
   {dbshow}
   {\myfiledate}
@@ -24,8 +23,6 @@
   {\myfileversion}
   {database to store and show data}
 
-\DTMsetdatestyle{iso}
-
 \msg_new:nnn { dbshow } { non-existent-database } {
   Database~'#1'~does~not~exist~\msg_line_context:.
 }
@@ -91,16 +88,17 @@
     { \msg_fatal:nnn { dbshow } { non-existent-type } { #1 } }
 }
 
-% #1 count #2 content
+% #1 valid count #2 real count #3 content
 \msg_new:nnn { dbshow } { wrong-seperator } {
-  option~sep~should~contain~1~or~3~items~but~only~#1~items~was~given,~
-  sep~=~\{#2\}~\msg_line_context:.
+  option~'sep'~should~contain~#1~items~but~only~#2~items~was~given,~
+  sep~=~\{#3\}~\msg_line_context:.
 }
 
-\cs_new:Nn \dbshow_sep_error:nn {
-  \msg_error:nnnn { dbshow } { wrong-seperator } { #1 } { #2 }
+% #1 valid count #2 real count #3 content
+\cs_new:Nn \dbshow_sep_error:nnn {
+  \msg_error:nnnnn { dbshow } { wrong-seperator } { #1 } { #2 } { #3 }
 }
-\cs_generate_variant:Nn \dbshow_sep_error:nn { xx }
+\cs_generate_variant:Nn \dbshow_sep_error:nnn { xxx }
 
 \msg_new:nnn { dbshow } { unsupported-sort-type } {
   unsupported~sort~type:~'#1'~\msg_line_context:.~The~type~should~be~one~of~
@@ -107,28 +105,14 @@
   \{str,~date,~int,~fp\}.
 }
 
-\clist_const:Nn \dbshow_type_clist { date, str, tl, clist, int, fp }
-
-\prop_const_from_keyval:Nn \dbshow_new_cs_map {
-  date = str_clear_new:c,
-  str = str_clear_new:c,
-  tl = tl_gclear_new:c,
-  clist = clist_gclear_new:c,
-  int = int_gzero_new:c,
-  fp = fp_gzero_new:c
+\msg_new:nnn { dbshow } { invalid-relation } {
+  invalid~relation:~'#1'.
 }
 
-\prop_const_from_keyval:Nn \dbshow_set_cs_map {
-  date = str_gset:cn,
-  str = str_gset:cn,
-  tl = tl_gset:cn,
-  clist = clist_gset:cn,
-  int = int_gset:cn,
-  fp = fp_gset:cn
-}
+\clist_const:Nn \dbshow_type_clist { date, str, tl, clist, int, fp }
 
 \prop_const_from_keyval:Nn \dbshow_default_value {
-  date = \Today,
+  date = \dbtoday,
   str = ,
   tl = ,
   clist = ,
@@ -136,15 +120,16 @@
   fp = 0
 }
 
-\newcount\l_dbshow_date_diff
-\clist_new:N \l_style_sep_clist
-\tl_new:N \l_style_item_before_code
-\tl_new:N \l_style_item_after_code
 \cs_generate_variant:Nn \clist_use:nn { xx }
 \cs_generate_variant:Nn \clist_use:nnnn { xxxx }
+\cs_generate_variant:Nn \prop_get:NnN { cVN }
+\cs_generate_variant:Nn \regex_extract_all:nnN { nVN }
+\cs_generate_variant:Nn \regex_split:nnN { nVN }
 \prg_generate_conditional_variant:Nnn \str_compare:nNn { VNV } { TF }
 \prg_generate_conditional_variant:Nnn \int_compare:nNn { VNV } { TF }
 \prg_generate_conditional_variant:Nnn \fp_compare:nNn { VNV } { TF }
+\prg_generate_conditional_variant:Nnn \regex_match:nn { VV } { TF }
+\prg_generate_conditional_variant:Nnn \clist_if_in:Nn { Nx } { TF }
 
 % #1 database #2 attr #3 type #4 default value
 \cs_new:Npn \dbshow_process_default_value:w #1|#2=#3|#4\scan_stop {
@@ -214,20 +199,29 @@
 % #1 database #2 attr #3 content
 \cs_new:Nn \dbshow_save_data:nnn {
   \dbshow_check_attr:nn { #1 } { #2 }
-  \str_set:Nx \l_tmp_type { \dbshow_get_type:nn { #1 } { #2 } }
-  \prop_get:NVN \dbshow_new_cs_map \l_tmp_type \l_tmp_cs_new
-  \prop_get:NVN \dbshow_set_cs_map \l_tmp_type \l_tmp_cs_set
-  \use:c { \l_tmp_cs_new }
-    { g__dbshow_data_#1_#2_\dbshow_get_counter:n { #1 } }
-  \use:c { \l_tmp_cs_set }
-    { g__dbshow_data_#1_#2_\dbshow_get_counter:n { #1 } } { #3 }
+  \use:c {
+    \str_case_e:nn { \prop_item:cn { g__dbshow_type_map_#1 } { #2 } } {
+      { str } { str_clear_new:c }
+      { tl } { tl_gclear_new:c }
+      { clist } { clist_gclear_new:c }
+      { int } { int_gzero_new:c }
+      { fp } { fp_gzero_new:c }
+      { date } { dbshow_date_gclear_new:n }
+    }
+  } { g__dbshow_data_#1_#2_\int_use:c { g__dbshow_counter_#1 } }
+  \use:c {
+    \str_case_e:nn { \prop_item:cn { g__dbshow_type_map_#1 } { #2 } } {
+      { str } { str_gset:cn }
+      { tl } { tl_gset:cn }
+      { clist } { clist_gset:cn }
+      { int } { int_gset:cn }
+      { fp } { fp_gset:cn }
+      { date } { dbshow_date_gset:nx }
+    }
+  } { g__dbshow_data_#1_#2_\int_use:c { g__dbshow_counter_#1 } } { #3 }
 }
 \cs_generate_variant:Nn \dbshow_save_data:nnn { nnx }
 
-\cs_new:Nn \dbshow_brace:n {
-  \exp_not:n { { #1 } }
-}
-
 % #1 before code tl #2 after code tl #3 item
 \cs_new:Nn \dbshow_clist_wrapper:NNn {
   \exp_not:n { { #1#3#2 }, }
@@ -249,17 +243,46 @@
         { \clist_item:Nn #2 { 3 } }
     }
   } {
-    \dbshow_sep_error:xx
+    \dbshow_sep_error:xxx
+      { 1~or~3 }
       { \clist_count:N #2 }
-      { \clist_use:Nn #2 { , } }
+      { \clist_use:Nn #2 { ,~ } }
   }
 }
 \cs_generate_variant:Nn \dbshow_clist_use:NNNN { cccc }
 
+% #1 date #2 sep #3 zfill bool
+\cs_new:Nn \dbshow_date_use:nNN {
+  \int_case:nnF { \clist_count:N #2 } {
+    { 1 } {
+      \bool_if:NTF { #3 }
+        { \dbshow_date_use_zfill:nf }
+        { \dbshow_date_use:nf }
+        { #1 }
+        { \clist_item:Nn #2 { 1 } }
+    }
+    { 4 } {
+      \bool_if:NTF { #3 }
+        { \dbshow_date_use_zfill:nffff }
+        { \dbshow_date_use:nffff }
+        { #1 }
+        { \clist_item:Nn #2 { 1 } }
+        { \clist_item:Nn #2 { 2 } }
+        { \clist_item:Nn #2 { 3 } }
+        { \clist_item:Nn #2 { 4 } }
+    }
+  } {
+    \dbshow_sep_error:xxx
+      { 1~or~4 }
+      { \clist_count:N #2 }
+      { \clist_use:Nn #2 { ,~ } }
+  }
+}
+\cs_generate_variant:Nn \dbshow_date_use:nNN { ncc }
+
 % #1 database #2 attr #3 index #4 style
 \cs_new:Nn \dbshow_use_data:nnnn {
   \str_case_e:nn { \prop_item:cn { g__dbshow_type_map_#1 } { #2 } } {
-    { date } { \str_use:c { g__dbshow_data_#1_#2_#3 } }
     { str } { \str_use:c { g__dbshow_data_#1_#2_#3 } }
     { tl } { \tl_use:c { g__dbshow_data_#1_#2_#3 } }
     { int } { \int_use:c { g__dbshow_data_#1_#2_#3 } }
@@ -266,10 +289,18 @@
     { fp } { \fp_use:c { g__dbshow_data_#1_#2_#3 } }
     { clist } {
       \dbshow_clist_use:cccc { g__dbshow_data_#1_#2_#3 }
-        { g__dbshow_style_clist_sep_#4_#1_#2 }
-        { g__dbshow_style_clist_item_before_#4_#1_#2 }
-        { g__dbshow_style_clist_item_after_#4_#1_#2 }
+        { g__dbshow_style_attr_sep_#4_#1_#2 }
+        { g__dbshow_style_attr_item_before_#4_#1_#2 }
+        { g__dbshow_style_attr_item_after_#4_#1_#2 }
     }
+    { date } {
+      \exp_args:Nnx
+      \tl_use:c { g__dbshow_style_attr_wrapper_#4_#1_#2 } {
+        \dbshow_date_use:ncc { g__dbshow_data_#1_#2_#3 }
+          { g__dbshow_style_attr_sep_#4_#1_#2 }
+          { g__dbshow_style_attr_zfill_#4_#1_#2 }
+      }
+    }
   }
 }
 
@@ -307,9 +338,13 @@
   \prop_map_function:cN { g__dbshow_type_map_#1 } \dbshow_set_default:nn
   \dbshow_save_data:nnx { #1 } { id } { \dbshow_get_counter:n { #1 } }
   \keys_set:nn { dbshow/database/#1 } { #2 }
-  % #2 attr #3 content
-  \NewDocumentCommand { \dbsave } { m m } {
-    \dbshow_save_data:nnn { #1 } { ##1 } { ##2 }
+  % ##1 exp or not ##2 attr ##3 content
+  \NewDocumentCommand { \dbsave } { s m m } {
+    \IfBooleanTF { ##1 } {
+      \dbshow_save_data:nnn { #1 } { ##2 } { \exp_not:n { ##3 } }
+    } {
+      \dbshow_save_data:nnn { #1 } { ##2 } { ##3 }
+    }
   }
 } { #3 }
 
@@ -368,43 +403,53 @@
   \tl_set:Nn \l_date_tl { #2 }
 }
 
-\cs_new:Nn \dbshow_if_date: {
-  \bool_if:NTF \l_star_bool {
-    \regex_extract_once:nVNF { \A(.*)([!<>=]+)(.*)\Z }
-      \l_dbshow_rela \l_tmpa_seq { }
-    \exp_args:Nnx \DTMsavedate{day1}{ \seq_item:Nn \l_tmpa_seq { 2 } }
-    \tl_set:Nx \l_rela { \seq_item:Nn \l_tmpa_seq { 3 } }
-    \exp_args:Nnx \DTMsavedate{day2}{ \seq_item:Nn \l_tmpa_seq { 4 } }
-    \DTMsaveddatediff{day1}{day2}{\l_dbshow_date_diff}% specious blank
-    \exp_args:NnV \int_compare:nNnTF
-      { \the\l_dbshow_date_diff } \l_rela { 0 }
+\cs_new_protected:Nn \dbshow_if_date: {
+  \int_zero_new:N \l__dbshow_if_tmpa_int
+  \int_zero_new:N \l__dbshow_if_tmpb_int
+  \int_zero_new:N \l__dbshow_if_diff_int
+  \bool_if:NTF \l_star_bool { % review points
+    \exp_after:wN \dbshow_parse_date:w \l_dbshow_rela\dbshow_stop
+    \dbshow_date_clear_new:n { tmp_day1 }
+    \dbshow_date_clear_new:n { tmp_day2 }
+    \dbshow_date_set:nx { tmp_day1 } { \l_date_tl }
+    \dbshow_date_set:nx { tmp_day2 } { \dbval }
+    \dbshow_date_sub:nnN { tmp_day1 } { tmp_day2 } \l__dbshow_if_diff_int
+    \clist_if_in:NxTF \l_point_clist { \int_use:N \l__dbshow_if_diff_int }
       { \dbshow_set_true: }
       { \dbshow_set_false: }
   }
-  {
-    \exp_after:wN \dbshow_parse_date:w \l_dbshow_rela\dbshow_stop
-    \exp_args:Nnx \DTMsavedate{day1}{ \l_date_tl }
-    \exp_args:Nnx \DTMsavedate{day2}{ \dbval }
-    \DTMsaveddatediff{day1}{day2}{\l_dbshow_date_diff}% specious blank
-    \clist_if_in:NoTF \l_point_clist { \the\l_dbshow_date_diff }
+  { % rela
+    \tl_set:Nx \l_dbshow_rela { \l_dbshow_rela }
+    \regex_extract_all:nVN { \d{4}/\d+/\d+ } \l_dbshow_rela \l_date_seq
+    \regex_split:nVN { \d{4}/\d+/\d+ } \l_dbshow_rela \l_other_seq
+    \tl_clear:N \l_dbshow_rela
+    \int_set:Nn \l__dbshow_if_tmpa_int { \seq_count:N \l_date_seq }
+    \int_step_inline:nn { \l__dbshow_if_tmpa_int } {
+      \tl_put_right:Nx \l_dbshow_rela { \seq_item:Nn \l_other_seq { ##1 } }
+      \dbshow_date_clear_new:n { rela-tmp }
+      \dbshow_date_set:nx { rela-tmp } { \seq_item:Nn \l_date_seq { ##1 } }
+      \dbshow_date_to_int:nN { rela-tmp } \l__dbshow_if_tmpb_int
+      \tl_put_right:Nx \l_dbshow_rela { \int_use:N \l__dbshow_if_tmpb_int }
+    }
+    \tl_put_right:Nx \l_dbshow_rela {
+      \seq_item:Nn \l_other_seq { \l__dbshow_if_tmpa_int + 1 }
+    }
+    \int_compare:nTF { \l_dbshow_rela }
       { \dbshow_set_true: }
       { \dbshow_set_false: }
   }
 }
 
-\cs_generate_variant:Nn \prop_get:NnN { cVN }
-\prg_generate_conditional_variant:Nnn \regex_extract_once:nnN { nVN } { T, F, TF, p }
-\prg_generate_conditional_variant:Nnn \regex_match:nn { VV } { T, F, TF, p }
 % #1 database name #2 cond name #3 index
 \cs_set:Nn \dbshow_if:nnn {
   \tl_set_eq:Nc \l_dbshow_attr { g__dbshow_filter_attr_#1_#2 }
   \tl_set_eq:Nc \l_dbshow_rela { g__dbshow_filter_rela_#1_#2 }
+  \prop_get:cVN { g__dbshow_type_map_#1 } \l_dbshow_attr \l_tmp_type
   \cs_set_eq:Nc \dbval { g__dbshow_data_#1_\l_dbshow_attr _#3 }
   \cs_set:Nn \dbshow_set_true:
     { \bool_gset_true:c { g__dbshow_filter_bool_#1_#2 } }
   \cs_set:Nn \dbshow_set_false:
     { \bool_gset_false:c { g__dbshow_filter_bool_#1_#2 } }
-  \prop_get:cVN { g__dbshow_type_map_#1 } \l_dbshow_attr \l_tmp_type
   \bool_set_eq:Nc \l_star_bool { g__dbshow_cond_star_#1_#2 }
   \use:c { dbshow_if_\l_tmp_type : }
 }
@@ -468,6 +513,8 @@
   \clist_set:cn { g__review_points_#1 } { #2 }
 }
 
+\cs_new:Nn \dbshow_identity:n { #1 }
+
 % #1 style name #2 database name #3 attr
 \cs_new_protected:Nn \dbshow_new_attr_style:nnn {
   \dbshow_check_attr:nn { #2 } { #3 }
@@ -476,17 +523,23 @@
     before-code .initial:n = ,
     after-code .tl_gset:c = { g__dbshow_style_attr_after_#1_#2_#3 },
     after-code .initial:n = ,
+    % for date and clist
+    sep .clist_gset:c = { g__dbshow_style_attr_sep_#1_#2_#3 },
+    % only for clist
+    item-before-code .tl_gset:c = { g__dbshow_style_attr_item_before_#1_#2_#3 },
+    item-before-code .initial:n = ,
+    item-after-code .tl_gset:c = { g__dbshow_style_attr_item_after_#1_#2_#3 },
+    item-after-code .initial:n = ,
+    % only for date
+    zfill .bool_gset:c = { g__dbshow_style_attr_zfill_#1_#2_#3 },
+    zfill .initial:n = true,
+    zfill .default:n = true,
+    wrapper .tl_gset:c = { g__dbshow_style_attr_wrapper_#1_#2_#3 },
+    wrapper .initial:n = { \dbshow_identity:n },
   }
-  \prop_get:cnN { g__dbshow_type_map_#2 } { #3 } \l_tmp_type
-  \str_if_eq:eeT { \l_tmp_type } { clist } {
-    \keys_define:nn { dbshow/style/#1/#3 } {
-      sep .clist_gset:c = { g__dbshow_style_clist_sep_#1_#2_#3 },
-      sep .initial:n = { { ,~ } },
-      item-before-code .tl_gset:c = { g__dbshow_style_clist_item_before_#1_#2_#3 },
-      item-before-code .initial:n = ,
-      item-after-code .tl_gset:c = { g__dbshow_style_clist_item_after_#1_#2_#3 },
-      item-after-code .initial:n = ,
-    }
+  \str_case_e:nn { \prop_item:cn { g__dbshow_type_map_#2 } { #3 } } {
+    { clist } { \keys_set:nn { dbshow/style/#1/#3 } { sep = { { ,~ } } } }
+    { date } { \keys_set:nn { dbshow/style/#1/#3 } { sep = { { / } } } }
   }
 }
 
@@ -553,7 +606,7 @@
     \int_zero:N \l_tmpa_int
     \cs_set:Nn \dbshow_sort_single: {
       \int_incr:N \l_tmpa_int
-      \str_set:Nx \l_tmpa_str
+      \str_set:Nx \l_tmpa_str % attr
         { \clist_item:cn { g__dbshow_sort_#3_#1 } { \l_tmpa_int } }
       \str_if_in:NnTF \l_tmpa_str { * } {
         \exp_after:wN \dbshow_sort_parse_star:w \l_tmpa_str
@@ -564,15 +617,17 @@
       }
       \exp_args:NnV \dbshow_check_attr:nn { #1 } \l_tmpa_str
 
-      \cs_set_eq:Nc \l_tmpa_tl { g__dbshow_data_#1_\l_tmpa_str _##1 }
-      \cs_set_eq:Nc \l_tmpb_tl { g__dbshow_data_#1_\l_tmpa_str _##2 }
-
       \prop_get:cVN { g__dbshow_type_map_#1 } \l_tmpa_str \l_tmp_type
       \clist_if_in:nVF { str, int, date, fp  } \l_tmp_type {
         \msg_error:nnx { dbshow } { unsupported-sort-type } { \l_tmp_type }
       }
-      \str_if_eq:eeT { \l_tmp_type } { date }
-        { \str_set:Nn \l_tmp_type { str } }
+
+      \str_if_eq:eeT { \l_tmp_type } { date } {
+        \str_set:Nn \l_tmp_type { str }
+      }
+
+      \cs_set_eq:Nc \l_tmpa_tl { g__dbshow_data_#1_\l_tmpa_str _##1 }
+      \cs_set_eq:Nc \l_tmpb_tl { g__dbshow_data_#1_\l_tmpa_str _##2 }
       \cs_set_eq:Nc \dbshow_compare { \l_tmp_type _compare:VNVTF }
 
       \dbshow_compare \l_tmpa_tl \l_op_same \l_tmpb_tl
@@ -660,4 +715,192 @@
     { #1 } { #2 } { g__dbshow_filter_#1_#2 }
 }
 
+\cs_set_eq:NN \dbIntAbs \int_abs:n
+\cs_set_eq:NN \dbIntSign \int_sign:n
+\cs_set_eq:NN \dbIntDivRound \int_div_round:nn
+\cs_set_eq:NN \dbIntDivTruncate \int_div_truncate:nn
+\cs_set_eq:NN \dbIntMax \int_max:nn
+\cs_set_eq:NN \dbIntMin \int_min:nn
+\cs_set_eq:NN \dbIntMod \int_mod:nn
+\cs_set_eq:NN \dbFpSign \fp_sign:n
+
+%%%%%%%%%%%%%%%%% date
+
+% #1 year
+\prg_new_conditional:Nnn \dbshow_date_if_leap:n { T, F, TF, p } {
+  \bool_if:nTF {
+    \int_compare_p:nNn { \int_mod:nn { #1 } { 400 } } = { 0 } ||
+    (
+      !\int_compare_p:nNn { \int_mod:nn { #1 } { 100 } } = { 0 } &&
+      \int_compare_p:nNn { \int_mod:nn { #1 } { 4 } } = { 0 }
+    )
+  }
+    { \prg_return_true: }
+    { \prg_return_false: }
+}
+
+\clist_const:Nn \dbshow_date_month_clist
+  { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+
+\int_new:N \l__date_ans_int
+\int_new:N \l__date_tmpa_int
+\int_new:N \l__date_tmpb_int
+
+% #1 year #2 month #3 day #4 token to save the result
+\cs_new_protected:Nn \dbshow_date_to_int:nnnN {
+  \int_set:Nn \l__date_ans_int { #3 - 1 }
+  \int_step_inline:nn { #2 - 1 } {
+    \int_add:Nn \l__date_ans_int {
+      \clist_item:Nn \dbshow_date_month_clist { ##1 }
+    }
+    \bool_if:nT {
+      \int_compare_p:nNn { ##1 } = { 2 } &&
+      \dbshow_date_if_leap_p:n { #1 }
+    } { \int_incr:N \l__date_ans_int }
+  }
+  \int_add:Nn \l__date_ans_int { 365 * (#1 - 1971) }
+  \int_add:Nn \l__date_ans_int {
+    \int_div_truncate:nn { #1 - 1 } { 4 } -
+    \int_div_truncate:nn { 1971 } { 4 }
+  }
+  \int_sub:Nn \l__date_ans_int {
+    \int_div_truncate:nn { #1 - 1 } { 100 } -
+    \int_div_truncate:nn { 1971 } { 100 }
+  }
+  \int_add:Nn \l__date_ans_int {
+    \int_div_truncate:nn { #1 - 1 } { 400 } -
+    \int_div_truncate:nn { 1971 } { 400 }
+  }
+  \int_set_eq:NN #4 \l__date_ans_int
+}
+
+\cs_new_protected:Nn \dbshow_date_to_int:NNNN {
+  \dbshow_date_to_int:nnnN { #1 } { #2 } { #3 } #4
+}
+\cs_generate_variant:Nn \dbshow_date_to_int:NNNN { cccN }
+
+% #1 date #2 int
+\cs_new:Nn \dbshow_date_to_int:nN {
+  \dbshow_date_to_int:cccN
+    { dbshow_date_year_#1 }
+    { dbshow_date_month_#1 }
+    { dbshow_date_day_#1 }
+    #2
+}
+
+\cs_new_protected:Nn \dbshow_date_set_val:n {
+  \tl_set:cx { #1 } { \dbshow_date_use_zfill:nn { #1 } { / } }
+}
+\cs_new_protected:Nn \dbshow_date_gset_val:n {
+  \tl_gset:cx { #1 } { \dbshow_date_use_zfill:nn { #1 } { / } }
+}
+
+\cs_new_protected:Nn \dbshow_date_init:n {
+  \dbshow_date_set:nnnn { #1 } { 1971 } { 1 } { 1 }
+  \dbshow_date_set_val:n { #1 }
+}
+\cs_new_protected:Nn \dbshow_date_ginit:n {
+  \dbshow_date_gset:nnnn { #1 } { 1971 } { 1 } { 1 }
+  \dbshow_date_gset_val:n { #1 }
+}
+
+\cs_new_protected:Nn \dbshow_date_new:n {
+  \int_new:c { dbshow_date_year_#1 }
+  \int_new:c { dbshow_date_month_#1 }
+  \int_new:c { dbshow_date_day_#1 }
+  \dbshow_date_ginit:n { #1 }
+}
+
+\cs_new_protected:Nn \dbshow_date_clear_new:n {
+  \int_zero_new:c { dbshow_date_year_#1 }
+  \int_zero_new:c { dbshow_date_month_#1 }
+  \int_zero_new:c { dbshow_date_day_#1 }
+  \dbshow_date_init:n { #1 }
+}
+
+\cs_new_protected:Nn \dbshow_date_gclear_new:n {
+  \int_gzero_new:c { dbshow_date_year_#1 }
+  \int_gzero_new:c { dbshow_date_month_#1 }
+  \int_gzero_new:c { dbshow_date_day_#1 }
+  \dbshow_date_ginit:n { #1 }
+}
+
+% #1 name #2 year #3 month #4 day
+\cs_new_protected:Nn \dbshow_date_set:nnnn {
+  \int_set:cn { dbshow_date_year_#1 } { #2 }
+  \int_set:cn { dbshow_date_month_#1 } { #3 }
+  \int_set:cn { dbshow_date_day_#1 } { #4 }
+  \dbshow_date_set_val:n { #1 }
+}
+
+% #1 name #2 year #3 month #4 day
+\cs_new_protected:Nn \dbshow_date_gset:nnnn {
+  \int_gset:cn { dbshow_date_year_#1 } { #2 }
+  \int_gset:cn { dbshow_date_month_#1 } { #3 }
+  \int_gset:cn { dbshow_date_day_#1 } { #4 }
+  \dbshow_date_gset_val:n { #1 }
+}
+
+\cs_new_protected:Npn \dbshow_date_set:w #1\dbshow_sep#2/#3/#4\dbshow_stop {
+  \dbshow_date_clear_new:n { #1 }
+  \dbshow_date_set:nnnn { #1 } { #2 } { #3 } { #4 }
+}
+\cs_new_protected:Npn \dbshow_date_gset:w #1\dbshow_sep#2/#3/#4\dbshow_stop {
+  \dbshow_date_gclear_new:n { #1 }
+  \dbshow_date_gset:nnnn { #1 } { #2 } { #3 } { #4 }
+}
+
+% #1 date name #2 date
+\cs_new_protected:Nn \dbshow_date_set:nn {
+  \dbshow_date_set:w #1\dbshow_sep#2\dbshow_stop
+}
+\cs_generate_variant:Nn \dbshow_date_set:nn { nx }
+\cs_new_protected:Nn \dbshow_date_gset:nn {
+  \dbshow_date_gset:w #1\dbshow_sep#2\dbshow_stop
+}
+\cs_generate_variant:Nn \dbshow_date_gset:nn { nx }
+
+% #1 date 1 #2 date 2 #3 int token
+\cs_new_protected:Nn \dbshow_date_sub:nnN {
+  \dbshow_date_to_int:nN { #1 } \l__date_tmpa_int
+  \dbshow_date_to_int:nN { #2 } \l__date_tmpb_int
+  \int_set:Nn #3 { \l__date_tmpa_int - \l__date_tmpb_int }
+}
+
+\cs_new:Nn \dbshow_date_show_two:N {
+  \int_compare:nNnTF { #1 } > { 9 }
+    { \int_use:N #1 } { 0\int_use:N #1 }
+}
+\cs_generate_variant:Nn \dbshow_date_show_two:N { c }
+
+\cs_new:Nn \dbshow_date_use:nnnnn {
+  #2\int_use:c { dbshow_date_year_#1 }
+  #3\int_use:c { dbshow_date_month_#1 }
+  #4\int_use:c { dbshow_date_day_#1 }#5
+}
+\cs_generate_variant:Nn \dbshow_date_use:nnnnn { nffff }
+
+\cs_new:Nn \dbshow_date_use_zfill:nnnnn {
+  #2\int_use:c { dbshow_date_year_#1 }
+  #3\dbshow_date_show_two:c { dbshow_date_month_#1 }
+  #4\dbshow_date_show_two:c { dbshow_date_day_#1 }#5
+}
+\cs_generate_variant:Nn \dbshow_date_use_zfill:nnnnn { nffff }
+
+\cs_new:Nn \dbshow_date_use:nn {
+  \dbshow_date_use:nnnnn { #1 } {  } { #2 } { #2 } {  }
+}
+\cs_generate_variant:Nn \dbshow_date_use:nn { nf }
+
+\cs_new:Nn \dbshow_date_use_zfill:nn {
+  \dbshow_date_use_zfill:nnnnn { #1 } {  } { #2 } { #2 } {  }
+}
+\cs_generate_variant:Nn \dbshow_date_use_zfill:nn { nf }
+
+\tl_set:Nx \dbtoday {
+  \int_use:N \c_sys_year_int/
+  \int_use:N \c_sys_month_int/
+  \int_use:N \c_sys_day_int
+}
+
 \endinput



More information about the tex-live-commits mailing list.