个人日志中的自动日期

个人日志中的自动日期

我使用 LaTeX 记个人日记。我想创建一个环境,自动跟踪每条日记的日期,而无需手动输入。这是目前的代码

\documentclass{tufte-book}
\usepackage{datenumber, ifthen, xparse}
\usepackage{lipsum}
\setstartyear{2000}
\newcounter{day}
\setcounter{day}{0}
\newcounter{if_auxnewday_begun}
\setcounter{if_auxnewday_begun}{0}

\ExplSyntaxOn

\iow_new:N \g_journal_stream
\seq_new:N \g_journal_seq

\NewDocumentEnvironment{ newday }{ o }{
  \addtocounter{day}{1}
  \seq_gput_right:Nx \g_journal_seq {
    { \arabic{day} }
    { \datedayname,~\today }
    { \IfValueTF{ #1 }{ #1 }{} }
  }
  \file_if_exist_input:n {\c_sys_jobname_str.jrn}
}{
  \int_compare:nNnT { \arabic{if_auxnewday_begun} } = { 1 }{
    \end{ auxnewday}
    \setcounter{if_auxnewday_begun}{0}
  }
}

\NewDocumentCommand{ \saveday }{ mmm }{
  \int_compare:nNnT { #1 } = { \arabic{day} }{
    \begin{ auxnewday }{#2}{#3}
    \setcounter{if_auxnewday_begun}{1}
  }
}

\NewDocumentEnvironment{ auxnewday } { mm }{
  \textbf{ #2 }
  \marginnote{ #1} \\
}{
  \vspace{0.5cm}
}

\AtEndDocument{
  \iow_open:Nn \g_journal_stream { \c_sys_jobname_str.jrn }
  \save_days:
  \iow_close:N \g_journal_stream
}

\cs_new_protected:Nn \save_days: {
  \seq_map_function:NN \g_journal_seq \__save_days:n
}

\cs_new_protected:Nn \__save_days:n {
  \iow_now:Nn \g_journal_stream {
    \saveday #1
  }
}

\ExplSyntaxOff

\begin{document}
\begin{newday}[A day]
\lipsum[1-5]
\end{newday}

\begin{newday}[Another day]
\lipsum[6-9]
\end{newday}
\end{document}

事实上,newday环境只是更简单的

\NewDocumentEnvironment{ newday }{ o }{
  \textbf{#1}
  \marginnote{ \datedayname,~\today } \\
}{
  \vspace{0.5cm}
}

我想要解决的问题是:假设我输入了newday今天,即 2019 年 2 月 25 日。如何防止代码在一天结束时更改该条目的日期?

我开始编写第一个选项,认为它可以让我将每个日期保存在单独的文件中,但我很快意识到.jrn每次编译时该文件都会被覆盖,所以它没用。

关于如何解决这个问题有什么想法吗?

编辑有问题的代码

\documentclass[justified, symmetric]{tufte-book}
\usepackage{ifoddpage, ifthen, xparse}
\usepackage[calc, showdow, english]{datetime2}
\DTMnewdatestyle{mydateformat}{%
  \renewcommand{\DTMdisplaydate}[4]{%
    \DTMshortweekdayname{##4},\space% short weekday,
    \DTMmonthname{##2}\nobreakspace%  (full) Month
    \number##3,\space% day,
    \number##1% year
  }%
  \renewcommand{\DTMDisplaydate}{\DTMdisplaydate}%
}
\DTMsetdatestyle{mydateformat}

\usepackage{lipsum}
\newcounter{day}
\title{Title}
\author{Author}
\ExplSyntaxOn

% Declare variables
\seq_new:N \g_journal_seq
\seq_new:N \g_journal_out_seq
\iow_new:N \g_journal_stream
\tl_new:N \l_journal_date_tl

% At the beginning of the run, read the lines of the `.jrn` file into a sequence.
% These are the dates. If the file can not be opened, it probably does not exist and we treat it as empty.
\cs_new:Npn \readjournaldates {
  \ior_open:NnT \g_journal_stream { \c_sys_jobname_str.jrn } {
    \ior_map_inline:Nn \g_journal_stream {
      \seq_gput_right:Nn \g_journal_seq { ##1 }
    }
    \ior_close:N \g_journal_stream
  }
}

% The main environment:
\NewDocumentEnvironment{ newday }{ O{} }{
  \stepcounter{day}
  % If the sequence \g_journal_seq is not empty yet, then we already saved a date
  % for the current day. Save this day in `\l_journal_date_tl` and delete it from
  % the sequence. Otherwise we have not saved anything yet, so we choose the current date. 
  \seq_gpop_left:NNF \g_journal_seq \l_journal_date_tl {
    \tl_set:Nx \l_journal_date_tl {\today}
  }
  % Now we have to save the chosen date for the next run. First, only store it in the
  % sequence `\g_journal_out_seq`, we only write it to the file at the end to avoid
  % overwriting the file if something fails:
  \seq_gput_right:NV \g_journal_out_seq \l_journal_date_tl
  \textbf{ #1 }
  \marginnote{\checkoddpage\ifoddpage \l_journal_date_tl \else\raggedleft \l_journal_date_tl \fi} \\
}{
  \vspace{0.5cm}
}

% At the end of the document, iterate over `\g_journal_out_seq` and write every entry into a line.
\AtEndDocument{
  \iow_open:Nn \g_journal_stream { \c_sys_jobname_str.jrn }
  \seq_map_inline:Nn \g_journal_out_seq {
    \iow_now:Nn \g_journal_stream { #1 }
  }
  \iow_close:N \g_journal_stream
}

\ExplSyntaxOff
\readjournaldates

\begin{document}
\maketitle
\pagenumbering{arabic}
\begin{newday}[A day]
  \lipsum[1]
\end{newday}

\begin{newday}[Yet another day]
  \lipsum[2]
\end{newday}
\begin{newday}
  \lipsum[3]
\end{newday}

\begin{newday}[Ciao]
\lipsum[4]
\end{newday}

\begin{newday}[A day]
  \lipsum[1]
\end{newday}

\begin{newday}[Yet another day]
  \lipsum[2]
\end{newday}
\begin{newday}
  \lipsum[3]
\end{newday}

\begin{newday}[Ciao]
\lipsum[4]
\end{newday}

\begin{newday}[A day]
  \lipsum[1]
\end{newday}

\begin{newday}[Yet another day]
  \lipsum[2]
\end{newday}
\end{document}

答案1

每当你启动一个 时newday,你必须检查辅助文件中是否已经设置了日期。如果有,你只需将其复制到新文件中,否则你设置当前日期:

\documentclass{tufte-book}
\usepackage{datenumber, ifthen, xparse}
\usepackage{lipsum}
\setstartyear{2000}
\newcounter{day}

\ExplSyntaxOn

% Declare variables
\seq_new:N \g_journal_seq
\seq_new:N \g_journal_out_seq
\iow_new:N \g_journal_stream
\tl_new:N \l_journal_date_tl

% At the beginning of the run, read the lines of the `.jrn` file into a sequence.
% These are the dates. If the file can not be opened, it probably does not exists
% and we treat it as empty.
\cs_new:Npn \readjournaldates {
  \ior_open:NnT \g_journal_stream { \c_sys_jobname_str.jrn } {
    \ior_map_inline:Nn \g_journal_stream {
      \seq_gput_right:Nn \g_journal_seq { ##1 }
    }
    \ior_close:N \g_journal_stream
  }
}

% The main environment:
\NewDocumentEnvironment{ newday }{ O{} }{
  \stepcounter{day}
  % If the sequence \g_journal_seq is not empty yet, then we already saved a date
  % for the current day. Save this day in `\l_journal_date_tl` and delete it from
  % the sequence. Otherwise we have not saved anything yet, so we choose the current
  % date.
  \seq_gpop_left:NNF \g_journal_seq \l_journal_date_tl {
    \tl_set:Nx \l_journal_date_tl {\datedayname,~\today}
  }
  % Now we have to save the choosen date for the next run. First, only store it in the
  % sequence `\g_journal_out_seq`, we only write it to the file at the end to avoid
  % overwriting the file if something fails:
  \seq_gput_right:NV \g_journal_out_seq \l_journal_date_tl
  \textbf{ #1 }
  \marginnote{ \l_journal_date_tl } \\
}{
  \vspace{0.5cm}
}

% At the end of the document, iterate over `\g_journal_out_seq` and write every entry
% into a line
\AtEndDocument{
  \iow_open:Nn \g_journal_stream { \c_sys_jobname_str.jrn }
  \seq_map_inline:Nn \g_journal_out_seq {
    \iow_now:Nn \g_journal_stream { #1 }
  }
  \iow_close:N \g_journal_stream
}

\ExplSyntaxOff

\makeatletter
\readjournaldates
\makeatother

\begin{document}
\begin{newday}[A day]
  \lipsum[1]
\end{newday}

\begin{newday}[Yet another day]
  \lipsum[2]
\end{newday}
\begin{newday}
  \lipsum[3]
\end{newday}
\end{document}

通过仅在最后打开文件进行写入,我们确保只有在剩余文档被解释到最后时才会覆盖旧文件,因此如果编译失败,我们不会清除文件并丢失信息。

我们不必先将文件读入序列,而是可以在每次调用时读取一行辅助文件newday。但这样一来,我们就必须在整个运行过程中占用一个文件句柄。通过在一个块中读取文件,我们可以尽快释放文件句柄。 在此处输入图片描述

相关内容