マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

例の修正ユリウス通日なアレ

どなたか \TeX で修正ユリウス通日とか計算するマクロとか もってらっしゃいませんかね?

TeX 修正ユリウス通日」でググるとトップに次のようなページが引っかかる。

残念ながらそこに掲載されている修正ユリウス通日(MJD)のコードは「スヤァTeX」という画期的な TeX フォーマットを必要とするようだが、( ˘ω˘ )スヤァ… を平凡な \relax に戻す(あと \newcommand\def とする)と、どの(plain ベースの)フォーマットでも使えるようになる。

% plain pTeX 文書
%---------------------------------------
% (この中のコードはどのTeXでもどの漢字コードでも動作する)
\newcount\xxCntA
\newcount\xxCntB
%
%% \calcJulian\制御綴{<年>}{<月>}{<日>}
% 指定の日付のMJDの値(の数字)を整数値マクロに返す.
\def\calcJulian#1#2#3#4{%
  \xxCntA=#2\relax \xxCntB=#3\relax
  \ifnum\xxCntA<1 \xxCntA=1 \fi
  \ifnum\xxCntB<1 \xxCntB=1 \fi
  \ifnum\xxCntB<3 \advance\xxCntB12 \advance\xxCntA-1 \fi
  \mathchardef\xxTYear\xxCntA \chardef\xxTMonth\xxCntB
  \multiply\xxCntA1461 \divide\xxCntA4
  \xxCntB\xxTYear \divide\xxCntB100 \advance\xxCntA-\xxCntB
  \divide\xxCntB4 \advance\xxCntA\xxCntB
  \xxCntB\xxTMonth \advance\xxCntB-2
  \multiply\xxCntB520 \divide\xxCntB17 \advance\xxCntA\xxCntB
  \advance\xxCntA#4\relax \advance\xxCntA-678912
  \edef#1{\the\xxCntA}%
}
%% \xxReadNumAndDo\制御綴<整数><区切トークン>
% 整数を読み取って \制御綴{<整数>} を実行する.
% (<区切トークン> は消費される.)
\def\xxReadNumAndDo#1{%
  \def\xxTmpA##1{\expandafter#1\expandafter{\the\xxCntA}}%
  \afterassignment\xxTmpA \xxCntA=%
}
%% \parseDateAndDo\制御綴{<年><区切><月><区切><日><区切>}
% 日付を読み取って \制御綴{<年>}{<月>}{<日>} を実行する.
\def\parseDateAndDo#1#2{%
  \xxReadNumAndDo\xxParseDateAndDoA#2\relax#1%
}
\def\xxParseDateAndDoA#1{%<年>
  \def\xxDateArg{{#1}}%
  \xxReadNumAndDo\xxParseDateAndDoB
}
\def\xxParseDateAndDoB#1{%<月>
  \edef\xxDateArg{\xxDateArg{#1}}%
  \xxReadNumAndDo\xxParseDateAndDoC
}
\def\xxParseDateAndDoC#1{%<日>
  \edef\xxDateArg{\xxDateArg{#1}}%
  \xxParseDateAndDoD
}
\def\xxParseDateAndDoD#1\relax#2{%
  \expandafter#2\xxDateArg
}
%% \calcPeriod{<日付1>}{<日付2>}
% 2つの日付の間の日数(両端含む)をレジスタ \Period に返す.
\newcount\Period
\def\calcPeriod#1#2{%
  \def\xxTmpB{\calcJulian\xxStart}%
  \parseDateAndDo\xxTmpB{#1}%
  \def\xxTmpB{\calcJulian\xxEnd}%
  \parseDateAndDo\xxTmpB{#2}%
  \Period=\xxEnd\relax
  \advance\Period-\xxStart
  \advance\Period1
}
%-------------------------------------------------
% テスト
\calcPeriod{2012年1月1日}{2012年12月31日}
結果=\the\Period \par
\calcPeriod{2013年1月1日}{2013年12月31日}
結果=\the\Period \par
\calcPeriod{1999年12月29日}{2000年1月3日}
結果=\the\Period \par
%
\bye

この実装では MJD を算術演算で求めるアルゴリズム(曜日を求める Zeller の公式と似ている*1)を用いているので非常に簡潔なコードになっている。しかし、日付文字列(「2012年1月1日」とか)のパーズが少し手こずっている。これは「和文文字をコードに含めるのを避ける*2ために任意の(数値と解釈できない)文字 1 つを区切りと解釈するようにしている」ためである。もう少し上手く書けないのかな…。

*1:Zeller の公式は「美文書」で紹介されているので TeX な人にはお馴染みだろう。ちなみに、MJD が求められれば、曜日は 7 で割った余りですぐに解る。

*2:パッケージ化したときに漢字コードの違いによるトラブルを防ぐため。