Obsidian: Templaterスクリプトで日数計算
はじめに
前回の記事でTemplaterスクリプトの作成について調べました。せっかくなのでもうひとつくらいスクリプトを作りたい!
日数計算
Obsidianを使っているとき、自分は簡単な日数計算(AからBまでの日数、Aからn日後の日付)をすることが時々あるのですが、長めの日数になるとその都度ブラウザで日数計算サイトを開くか、サイドバーにCalendarプラグインを開いて「m週×7+n日だから…」とカレンダーを目視で数えたりしていて、面倒に思っていました。
計算を行うコミュニティプラグインはいくつかありますが、意外と日付計算に対応していません(把握している範囲では、Solveというプラグインがある程度対応しているようです。ノートに入力した計算式を片っ端から計算してくれる面白いプラグインです。他にもご存じの方がいましたらお教えください)。
過去に小規模なプラグインを作ることも少し考えましたが、多分UI作成とかで手間取って苦労することになると思い、そのままになっていました。
でもシンプルな計算なので、Templaterスクリプトで作れるのでは?
要件
AからBまでの日数nを求める計算と、Aからn日後の日付Bを求める計算を行いたい。別々のスクリプトで良い。
日付は手打ちで良い。UIや見た目は気にしない(あんまり入力が面倒だと困るけど)。
必要な情報を収集
日付の解釈や計算はObsidian経由でmoment.jsがやってくれるはず。Daily Note Outlineの作成で履修しました!
Templaterでダイアログを表示して値を入力
https://silentvoid13.github.io/Templater/internal-functions/internal-modules/system-module.html
Templater側でtp.system.promptというコマンドを用意してくれている模様。
moment.jsで日付の差分を求める
https://momentjs.com/docs/#/durations/diffing/
https://momentjs.com/docs/#/displaying/difference/
日付の表示形式
これらを元に、以下のスクリプトを作成しました。
スクリプト:2点間の日数を求める
<%*
const a = await tp.system.prompt("2点間の日数を求めます。起点日を入力してください");
const day1 = a ? moment(a):moment().startOf('day');
const instruction = `終点日を入力してください。起点日は${day1.format("YYYY年MM月DD日dddd")}`;
const b = await tp.system.prompt(instruction);
const day2 = b? moment(b):moment().startOf('day');
const duration = day2.diff(day1,'days');
const result = `${day1.format("YYYY年MM月DD日dddd")}から${day2.format("YYYY年MM月DD日dddd")}の日数は${duration.toString()+'日'}です(当日を含む場合は1日加算してください)`;
const value = await tp.system.prompt(result, duration.toString()+'日');
if (value){ tR = value}
%>
2回ダイアログが出るので、起点日と終点日の日付を入力します。入力した文字列をmoment.jsが日付として解釈します(どのような書式が正しく解釈されるか詳しくは把握していませんが、2023-12-14とか2023/12/14は大丈夫だったのでとりあえずは良いでしょう)。
空欄のままEnterで本日の日付が入るようにしました。
3回目のダイアログに計算結果が表示されます。そのままEnterでカーソル位置に結果が挿入され、ESCや×をクリックでキャンセルします。
使用頻度は低いので、コマンドにも登録せずTemplaterのリボンアイコンから選択して実行。
曜日が英語なのはCalendarプラグインでlocaleをオーバーライドしているからです。とりあえずは正しく計算できているんではないでしょうか。
スクリプト:n日後の日付を求める
想像よりだいぶスムーズにできたので、続いてn日後の日付を求めるスクリプトも作成します。
<%*
const a = await tp.system.prompt("起点日のn日後の日付を求めます。起点日を入力してください");
const day1 = a ? moment(a):moment().startOf('day');
const instruction = `何日後の日付を求めるか入力して下さい。起点日は${day1.format("YYYY年MM月DD日dddd")}`;
const b = await tp.system.prompt(instruction);
const day2 = day1.clone().add(b,'day');
const result = `${day1.format("YYYY年MM月DD日dddd")}の${b}日後は${day2.format("YYYY年MM月DD日dddd")}です`;
const value = await tp.system.prompt(result,day2.format("YYYY年MM月DD日") );
if (value) {tR = value}
%>
そして実行。
スクリプトを統合
別々のスクリプトで良いと思ってましたが、単純に二番目の入力値が整数がどうかで場合分けすれば2つのスクリプトを統合できる気がしてきました。
<%*
const a = await tp.system.prompt("起点日を入力してください");
const day1 = a ? moment(a):moment().startOf('day');
const instruction = `終点日または加算する日数を入力してください。起点日は${day1.format("YYYY年MM月DD日dddd")}`;
const b = await tp.system.prompt(instruction);
if (b !="" && Number.isInteger(Number(b))){
const day2 = day1.clone().add(b,'day');
const result = `${day1.format("YYYY年MM月DD日dddd")}の${b}日後は${day2.format("YYYY年MM月DD日dddd")}です`;
const value = await tp.system.prompt(result,day2.format("YYYY年MM月DD日") );
if (value) {tR = value}
} else {
const day2 = b? moment(b):moment().startOf('day');
const duration = day2.diff(day1,'days');
const result = `${day1.format("YYYY年MM月DD日dddd")}から${day2.format("YYYY年MM月DD日dddd")}の日数は${duration.toString()+'日'}です(当日を含む場合は+1してください)`;
const value = await tp.system.prompt(result, duration.toString()+'日');
if (value){ tR = value}
}
%>
検証が雑だけど、まあ動いているかな?欠点は20231214みたいな入力が日付にならないこと。
まとめ
想像より遙かに簡単に日付計算スクリプトができたと思います。プラグイン作成に踏み切らなくて良かった💦 もしObsidianで日数を計算したい方がいたら(いるのか?!)使ってみてください。
Templaterスクリプトは汎用性やUIを気にしなくていいのが良い
エラー処理も気にしなくて良いのが良い(エラーが起きないように入力すればよいので)
今後も「スクリプト化したら楽できないか」と意識していきたいです。
Bing AIに頼ってみる
…と思ったけど、今時は日付の計算なんてAIに聞いて済ませる時代なのでは?と思い当たり、Bing先生に聞いてみる事にしました。
合ってますね。しかも「I hope that helps!」と気さくな感じまで漂わせています。となると正解はスクリプト作成することよりAIコンパニオンプラグインを探すことだったかもしれません。
ただ、既にAI関連プラグインは多数リリースされており、検索するだけで圧倒されてしまい、どれも試せていません(「chatGPT」と検索するだけでも16件もヒットします)。どなたかObsidian AI関連プラグイン年越し100時間レビューに挑戦していただけないでしょうか。