我正在用 LaTeX 写一本 365 页的个人一年日记。我将使用日+月作为页码,而不是数字,因此:
首页页码不是1,而是1 Jan...
第 32 页不是 32,而是 2 月 1 日……
最后一个不是 365/366,而是 12 月 31 日......
等等。我该怎么做?
答案1
可能不是最理想的,但是...
使用expl3
:)
代码略加注释以解释其本身。基本上,我们使用\SetupDiary
创建每个月天数的列表。您可以使用\SetupDiary[<year>]
指定年份。如果未提供可选参数,则默认为\year
。
之后,\SetupDiary
您可以使用 将日期转换为日期\SeqToDate{<day>}
。在示例中,我使用 对日期进行页码编号\def\thepage{\SeqToDate{\value{page}}}
。
注意!如果给定年份中不存在该日期,则会引发错误。例如,\SetupYear[2018]\SeqToDate{366}
不起作用。确保在日期部分完成后取消定义页码。
随机一页:)
\documentclass{article}
\usepackage[a6paper]{geometry}
\usepackage{xparse}
\usepackage{pgffor}% Just for printing many pages
\usepackage{lipsum}% Dummy text
\usepackage[super]{nth}% For ordinal printing
\ExplSyntaxOn
% First we create an auxiliary command that checks if the year is a leap year
% \leapyear{<year>}
% Expands to 1 if February has 29 days
% Takes into account the 4-year rule, the 100-year exception, and the 400-year
\NewExpandableDocumentCommand\leapyear
{ m }
{
\fp_eval:n {
(
\int_mod:nn { #1 } { 4 } = 0 % 4-year rule
&&
\int_mod:nn { #1 } { 100 } != 0 % 100-year exception
)
|| \int_mod:nn { #1 } { 400 } = 0 % 400-year meta-exception
}
}
% A few variables
\seq_new:N \moz_eomday
\seq_new:N \moz_eomsum
\seq_new:N \moz_months
% Now we create a \seq list with the month names
\seq_set_from_clist:Nn \moz_months
{ Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dez }
% Create a function that generates the number of days per month taking \leapyear into account
\cs_new:Npn \moz_make_eomday:n #1 {
\seq_set_from_clist:Nn \moz_eomday
{ 0, 31, \int_eval:n {28 + \leapyear {#1} }, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
}
% A recursive function that creates a cumulative sum of the number of days
\cs_new:Npn \moz_make_eomsum: {
\seq_pop_left:NNTF \moz_eomday \l_tmpa_tl
{
\int_set:Nn \l_tmpa_int { \l_tmpa_tl + \l_tmpa_int }
\seq_put_right:Nx \moz_eomsum { \int_use:N \l_tmpa_int }
\moz_make_eomsum:
}
{ }
}
% Now the main thing begins.
% First, a function that generates the number-of-days list
% \SetupDiary[<year>]
% Doesn't produce output
% The optional argument is the year to be used. If none is given, defaults to \year
\NewDocumentCommand\SetupDiary
{ O { \year } }
{
\moz_make_eomday:n { #1 }
\int_zero:N \l_tmpa_int
\seq_clear:N \moz_eomsum
\moz_make_eomsum:
}
% And the main function that takes the sequential day and converts to day and month
% \SeqToDate{<sequential-day>}[\<output-function>]
% Converts <sequential-day> to <dom> and <month> then calls \<output-function> {<dom>}{<month>}
\NewDocumentCommand\SeqToDate
{ m O { \moz_print_date:nn } }
{
\seq_get_right:NN \moz_eomsum \l_tmpa_tl
\int_compare:nNnT
{ \int_eval:n { #1 } }
>
{ \l_tmpa_tl }
{ \msg_fatal:nn { SeqToDate } { Day~\int_eval:n { #1 }~too~big.~Max~=~\tl_use:N \l_tmpa_tl. } }
\int_zero:N \l_tmpa_int
\int_do_while:nNnn
{ \int_eval:n { #1 } }
>
{ \seq_item:Nn \moz_eomsum { \l_tmpa_int + 1 } }
{ \int_incr:N \l_tmpa_int }
\int_set:Nn \l_tmpb_int { #1 - \seq_item:Nn \moz_eomsum { \l_tmpa_int } }
#2 { \int_use:N \l_tmpb_int } { \seq_item:Nn \moz_months { \l_tmpa_int } }
}
% This function takes the <dom> and <month> as arguments and prints them as <dom>~<month>
\cs_new:Npn \moz_print_date:nn #1 #2 {
#1~#2
}
% This function takes the <dom> and <month> as arguments and prints them as <month>,~<dom>th
\cs_new:Npn \printordinal #1 #2 {
#2,~\nth{ #1 }
}
\ExplSyntaxOff
% Test document
\begin{document}
% Setup first to create the number-of-days list
\SetupDiary
% Make the page number be the date
\def\thepage{\SeqToDate{\value{page}}}
% Prints lots of pages :)
\foreach \i in {1,...,365}{%
\section*{\SeqToDate{\i}[\printordinal]}%
\lipsum[4]\clearpage
}
% CAREFUL! One more page will throw an error!
% Make the page numbering sequential again
\def\thepage{\value{page}}
\end{document}