LaTeX 文書中に \today と書くと latex コマンドを実行した日付が出てくる。このことから分かるように、 TeX 文書中では何らかの形で現在時刻を取得できる。では実際のところ、時刻に関してどの程度の情報を取得できるのか。また、 TeX 文書に与えられる「現在時刻」を変更することはできるだろうか。
目次
日付と時刻を扱う LaTeX パッケージ
LaTeX のカジュアルユーザーが日付と時刻の表示方法に拘りたいときは、 datetime パッケージまたはその後継の datetime2 パッケージについて調べると良いかもしれない。ここでは詳しく解説しない。
1つだけ紹介しておくと、 datetime2 パッケージが提供する \DTMnow コマンドにより、現在時刻を分単位または秒単位で表示できる。
この記事におけるカジュアルユーザー向けの記述はここまでで、これ以降はある程度 TeX 言語に親しんだ人向けの記述となる。
古き良き TeX の場合
TeX で現在時刻を取得するには、次の4つの primitive を使う。
\year, \month, \day, \time
最初の3つはそのまんまだが、最後の \time はその日の午前0時から経過した分(時*60+分)が入っている。
TeX が持っている、時刻に関する primitive はこの4つだけである。すなわち、現在時刻の秒の情報は TeX 文書中からは取れない。
(さっきカジュアルユーザー除けのおまじないを書いたので改めて注意書きする必要はないと思うが)これら4つのコマンドは TeX のマクロではないし、文書中に直接 \year と書いても「年」を表す数字の列にはならない。これらの primitive を直接扱うには、 TeX における数値の扱いを知っておかなければならない。
これらの primitive の内容を書き出す LaTeX 文書の例と plain TeX 文書の例をそれぞれ載せておく。
LaTeX 文書の例:
\documentclass{article} \begin{document} year = \number\year, month = \number\month, day = \number\day, time = \number\time. \end{document}
plain TeX 文書の例:
year = \number\year, month = \number\month, day = \number\day, time = \number\time. \bye
pdfTeX の場合
現在広く使われている TeX 処理系は「古き良き TeX」に色々と拡張を加えたものなので、話にはまだ続きがある。
pdfTeX では \pdfcreationdate という primitive が導入された。これには、その名の通り、PDF ファイルの「作成日時」メタデータに相当するものが入っている(…と言えるのは PDF モードの場合のみで、 DVI モードのことも考えれば、これはむしろ pdfTeX の実行日時と言ったほうが正しい)。
\pdfcreationdate のフォーマットは PDF の仕様における日時の書式に従っており、具体的には、
D:YYYYMMDDHHmmSSOHH‘mm‘
YYYY: 年、MM: 月、DD: 日、HH: 時、mm: 分、SS: 秒、OHH‘mm‘: タイムゾーン(世界時の場合は Z で、地方時、例えば日本標準時の場合は +09’00’ となる)
となる。例えば、この記事の下書きを書いていた時の日時は
D:20161216163315+09’00’
となる。
他のエンジンではどうなっているかというと、日本語圏で使われている e-(u)pTeX の場合は pdfTeX と互換な \pdfcreationdate が導入されている。pdfTeX の後継とか言われている LuaTeX の場合は、 \pdfcreationdate が廃止されてしまって代わりに \pdffeedback creationdate を使うことになる。(そもそも LuaTeX の場合は Lua コードで現在時刻を取得できるのだが)
一方で、XeTeX の場合は \pdfcreationdate に相当する primitive は存在しない。一応、シェルエスケープを有効にすれば、外部コマンドを実行して現在時刻を取得することはできる(そのためのパッケージがある:texosquery)。
PDF の作成日時を指定する
TeX Live 2016 の pdfTeX や dvipdfmx 等では、起動時に特定の環境変数を設定することにより、PDF の作成日時を好きな値に指定できる。
氏のブログ記事に記載がある:
変わったこと (6):deterministic (reproducible) な出力のサポート
要するに、ソフトウェアをソースコードからバイナリへコンパイルする際の「再現性」の概念を、 TeX ファイルから PDF ファイルを作る工程にも持ち込もうということのようである。
環境変数 SOURCE_DATE_EPOCH
pdfTeX, XeTeX, e-(u)pTeX, dvipdfmx で有効。
pdfTeX (PDF モード), XeTeX (PDF モード), dvipdfmx の実行時に指定した場合、 PDF メタデータ中の「作成日時」等に使われる時刻を、 UNIX time で指定する。
pdfTeX, e-(u)pTeX の実行時に指定した場合は、 \pdfcreationdate の値もこれになる。その際の \pdfcreationdate のタイムゾーンは、世界時を意味する “Z” となる。
例:
$ env SOURCE_DATE_EPOCH=1481873595 pdflatex timetest.tex
→ \pdfcreationdate は D:20161216073315Z となる。
デフォルトでは、 SOURCE_DATE_EPOCH に指定した日時に関わらず、 TeX primitive の \year, \month, \day, \time は TeX プログラムの実行した日時になる。
LuaTeX の場合、TeX Live 2016 に収録されているバージョン 0.95.0 では PDF ファイルのメタデータ及び \pdffeedback creationdate のどちらにも反映されない。公式サイトからアクセスできる snapshot (trunk) のリファレンスマニュアルには記載があるので、将来のバージョン (TeX Live 2017 に収録?) では何らかの形で使えるようになるものと思われる。
ちなみに、この環境変数の仕様は TeX 特有のものではなく、 reproducible-builds.org というところが定めているらしい:SOURCE_DATE_EPOCH specification
環境変数 SOURCE_DATE_EPOCH_TEX_PRIMITIVES
pdfTeX, XeTeX, e-(u)pTeX で有効。
この環境変数に 1 を指定した場合、SOURCE_DATE_EPOCH に指定した日時を TeX primitive の \year, \month, \day, \time にも反映させる。
e-(u)pTeX Version 3.14159265-p3.7-160201-2.6 の場合、この環境変数を使った場合に \pdfcreationdate が空になるという不具合があるようである。(そのせいで、 datetime2 パッケージを読み込む際にエラーが出る)
日時を指定するその他の方法
SOURCE_DATE_EPOCH は TeX Live 2016 よりも前のエンジンでは使えなかったり、 TeX Live 2016 の LuaTeX では使えなかったりする。そんな時でも \today の値くらいは設定したい、という場合はどうすればいいか。(決め打ちするならそもそも \today を使うなという話だが)
やり方としては至極単純で、 \year, \month, \day, \time の各 primitive には自分で値を代入できるので、そうしてやれば良い。
$ latex “\year=2016 \month=12 \day=7 \time=993 \input sugoibunsho.tex”
ついでに、 datetime2 のようなパッケージ向けに、 \pdfcreationdate マクロを定義してやるのも良いかもしれない(もちろんこんなことをしても PDF ファイルのメタデータには反映されない)。\pdfcreationdate が primitive ではなくマクロとなってしまうが、実用上は問題ないだろう。
この方法だと、 XeTeX で処理する文書にシェルエスケープなしで秒単位の時刻を与えることができるという利点がある。
$ latex “\year=2016 \month=12 \day=7 \time=993 \def\pdfcreationdate{D:20161216163315+09’00’}\input sugoibunsho.tex”
おまけ:調査用ファイル
各エンジンでの primitive の有無と値、およびそれらを元に datetime2 パッケージが算出した時刻を表示する LaTeX 文書があると便利である。
\documentclass{article} \usepackage[T1]{fontenc} % バックスラッシュをバックスラッシュとして表示する \usepackage{datetime2} \begin{document} % datetime2 パッケージの読み込みの有無で \today の定義が変わるので注意 \string\today{} = \today. \string\year{} = \number\year, \string\month{} = \number\month, \string\day{} = \number\day, \string\time{} = \number\time. % pdfTeX and e-(u)pTeX \ifdefined\pdfcreationdate \string\pdfcreationdate{} = \pdfcreationdate. \else \string\pdfcreationdate{} is not defined. \fi % LuaTeX \ifdefined\pdffeedback \string\pdffeedback{} creationdate = \pdffeedback creationdate. \else \string\pdffeedback{} is not defined. \fi \ifdefined\directlua Lua os.date() = \directlua{tex.sprint(os.date())}. \fi % \DTMnow is provided by `datetime2' package \string\DTMnow{} = \DTMnow. \end{document}
以前に書いた関連記事: