Home日記コラム書評HintsLinks自己紹介
 

フィンローダのあっぱれご意見番 第147回「リマインダーを作ろう (1)」

← 前のをみる | 「フィンローダのあっぱれご意見番」一覧 | 次のをみる →

仕事が1つだけある、というのはプログラマーには理想の環境かもしれないが、 現実にはマルチタスクは当たり前、という感じで、 優先順位を付けてスケジューリングを行う羽目になる。 ここで、優先度の低いタスクを後回しにしたら、 タスクがあったことも忘れて超整理法の実践になってしまう、 というのもありがちな話だ。

 

※ ここでの「マルチタスク」 は一人の人間が複数のプロジェクトや案件にひっかかっている様子を意味する。

多少は探したつもりだが、 期待した仕様のスケジュール管理ソフトがないので自分で作ることにした。 スケジュール管理というより、 実際はメールで通知してくれるリマインダーである。 自分ではそんなにややこしい機能ではないと思うのだが、 必須の機能は2つある。

1つ目は、スケジュールに指定した日付の直前に、 メールの通知を行う機能である。

まず、その日または翌日の予定、という内容で指定アドレスにメールを送る。 私の場合、メールアドレスが複数あるが、 数個のアドレスは、数時間に一度の間隔でチェックしている。 大量にメールが来たりするから、 この程度の間隔で読み出さないと訳が分からなくなるのだ。 もっとも、その9割は spam とウィルスメールなのだが。 例えば 10月1日の10時から会議、というようなスケジュールを入れた場合、 9月30日の夜に「明日の予定」のようなメールを送ってくれるとありがたい。

そして、まさに直前の 10月1日の9時30分、 「10時から会議です」という内容のメールを携帯に送る。 この機能が重要。 このように、 その日の予定をpcのメールに、直前の予定を携帯に、 というような複数アドレスに送付する機能が絶対に欲しいのである。 墓穴を掘るかもしれないが、「締め切りを3日過ぎました」みたいな機能も…?

2つ目は、 毎週、毎月、というような指定を可能とすることである。 ビデオデッキの録画予約は、毎週月曜夜 01:00 ~、のように指定できるが、 アレである。 実際、私の場合はそういうスケジュールが多いので、 特に毎週機能がないと困るのだ。 毎月機能も、毎月何日までに何を振り込む、というような処理を忘れないための、 リマインダーとしても重要ではないかと思ったのだ。

§

最初、これを Xoops にモジュール追加で作ろうとしたのだが、 単純に考えると、これはかなり無茶な話である。 なぜかというと、 Xoops は基本的に Web アプリケーションだ。 Web アプリケーションというのは、 どこかクライアントから http のリクエストがあったら、 それに対してオンデマンドの処理を行うという仕組みである。 つまり、誰もアクセスしていないのに9月30日の20時に自動的にメールを送る、 というような機能は想定外なのだ。 これを解決する方法はいくつかあるが、 とりあえず、 定期的に Web アプリケーションをアクセスするプログラムを書くことにした。 このプログラムは、 Xoops なら、Xoops サイト内の「スケジュール確認」というページ(を作ったとして)を自動的にアクセスするのである。 あとは、このプログラムを5分毎とか15分毎に実行すればいい。

予定を調べてメールを出す、それだけの話なら、 何も Xoops を使わなくてもよさそうだが、 Xoops を使ったのは、 スケジュールの入力を行う処理が必要だからである。 PHP と MySQL を使うためのフレームワークとして考えれば、 Xoops は結構便利なのだ。 そこで、問題としては、データベースのテーブルをどうするかを考えることになる。

§

U「ということで、考えてみましたが。」

ふ「なにを?」

U「テーブルですがな。」

ふ「何の?」

U「スケジュールを入れるテーブルですがな。」

ふ「なるほど。どういう構成になりますか?」

U「DBは何でもいいのですが、とりあえず MySQL を使うことにしておきます。 お約束のID、これはintegerで unique の primary key にします。 各予定に対応するIDですね。 予定は開始時刻と終了時刻、 それぞれ timestamp 型にします。 予定の内容を text 型にします。」

ふ「通知はどうしますか?」

U「cron のように定期的に何か実行できる仕組みがあると想定しておきます。 実際あるわけですが。Windows だとどうなるのか知りませんが、とにかくあります。」

  

ふ「まあ Cygwin で何とかなるということで。」

 

※ admin カテゴリにある cron と cygrunsrv をインストールして、サービスを設定する必要がある。

U「毎日実行する処理で、翌日の予定一覧を抜き出し、5分毎に実行する処理で、直前になった予定を抜き出す、というのでどうでしょうか。 処理内容は似通っていますが、 cron 的には別の処理を起動するということで。」

ふ「毎日の処理というように分かりきっているのなら、それでokっぽいですね。 今回は、自分だけのスケジュールだけということで、 どんなタイミングで誰にメールを送る、というような情報はテーブルには含めないことにしておきます。では、次に、翌日の予定だけを選択するクエリーを考えてみてください。」

§

U「翌日の予定を抜き出すには、 List 1 みたいな感じですか?」

---- List 1 ----

SELECT * FROM schedule WHERE 明日の予定 ORDER BY start

ふ「ちなみに、今回、Xoops のようなところからクエリーを出すということで、最後にセミコロンを書かないでいます。さて、明日の予定というのは、具体的にはどうやって判定しますかね?」

U 「日付が一致すればいいいでは?」

ふ「まあそれでもいいです。余談ですが、私みたいな生活パターンだと、TV番組欄みたいな感じで、午前4時頃を一日の区切りにしてもらった方がありがたいですね、つまり、明日の予定の中に、明後日の午前3時のものまで含めるみたいな。とりあえず今回はそれはナシにして、1日で区切ることにしましょう。」

U「説明のために、明日の開始日時を t_start、終了日時を t_end としておきます。 これは timestamp 型としては、 "2004-10-01 00:00:00" と "2004-10-01 23:59:59" となります。」

ふ「終了日時は "2004-10-02 00:00:00" でなくてもいいのですか?」

U「両端を含めてしまうと、2004-10-01 00:00:00 に予定が入っていたときにお知らせのメールが2回出てしまうことになりそうだから、含めないようにしたのだけど。」

ふ「例えばスケジュールとして23時から1時間の会議、というのを考えてみましょう。 UIとしては、どういう値を入れさせるといいでしょうか?」

U「そりゃ23時と24時でしょう。」

ふ「もう少し詳しく。」

U「秒まで入れろというのはナニだから、分までを扱うものとして、 23:00と、翌日の 00:00、でいいのではないでしょうか。」

ふ「予定の終了は 23:59 にしなくていいのですか?」

U「そういう面倒なことはしないというか、23:59 は内部処理的に 23:59:00 なのか、23:59:59 なのか、みたいな話が出てくるのか。翌日の00:00にした場合、何か問題がありますか?」

ふ「その日の予定かどうかを判定する処理を考えてみると分かります。 23:00から翌日の01:00まで会議する場合とか。」

U「そんな時間に会議すること自体が間違っています。」

  

ふ「まあそういう説はあるとして、フォーラムの毎週の定例会議が金曜の23:59から始まって少なくとも翌日01:05までだと。」

 

※ パソコン通信時代のプログラマーズフォーラムで、 この時間にchat を行うという慣習があった。 Webフォーラムに移転してからどうなるかは今のところ様子を見ている段階である。 当時のchat のアクティブユーザーは、 Webフォーラムのchat ではなく、IRC に移転してしまった。 というか私もそうなんですけど。

U「なんと実際にあるのか。その場合、木曜のメールで明日の予定として、定例会議があると通知しますが、金曜のメールでどうするか、という話ですか。」

ふ「確かに、予定が複数日にまたがる場合に、最初の日だけ通知すればよいのか、毎日通知した方がいいか、という話は出てきますね。」

U「毎日メールが来るというのも何かひっかかるけど、 現実的に考えて、明日の予定が夜にメールで来るとしたら、 金曜の23:59から土曜の01:05に会議、というような内容は、金曜の夜に(も)来て欲しいかも。」

ふ「とりあえず、複数日にまたがる場合は、またがった日全部に対して通知することにしましょう。すると、先の場合は木曜と金曜にメールが来るわけですが、 ここで問題です。 金曜の23:00から土曜の00:00まで会議、という場合はいつメールが来ますか?」

U「00:00まで、というのが土曜に予定ありと解釈されて、金曜にもメールが来るのか…。

ふ「こういう時は半直線の発想で、開始時刻は含むが、終了時刻は含まない、ということにして、23時から24時、とすれば割とすっきりするのです。」

U「なるほど、では仕様変更して、 tomorrow_end は "2004-10-02 00:00:00" として、 判定時には、終了時刻は含まない、という条件にします。 開始時刻が指定日に含まれるかどうか、というのは、 List 2 みたいな感じで判定できます。」

---- List 2 ----

SELECT * FROM schedule WHERE start>=t_start and start<t_end ORDER BY start

ふ「終了時刻の判定は?」

U「end>=t_start and end<t_end のような条件もチェックして、or で判定ですか?」

ふ「終了時刻は、その時刻を含めないのでしょ? それに、開始時刻と終了時刻だけを判定して or とすると、予定が何日にもまたがる場合に、最初と最後しかメールが来なくなってしまう。」

U「あ、そうか、」

ふ「こういう時は、予定の範囲と明日との共通部分があるかどうかを判定する必要があります。」

U「なるほど、List 3 でどうですか?」

---- List 3 ----

SELECT * FROM schedule WHERE start<t_end and end>t_start ORDER BY start

ふ「いいですね、ただ、この判定には start < end という条件が必要なので、待ち合わせの時刻のように、1つだけ時刻を指定するような場合には List 2 のように判定する、といった使い分けが必要になります。で、次に、毎週発生するような予定はどうやって判定するかを考えてください。」

(つづく)

  

(C MAGAZINE 2004年9月号掲載)
内容は雑誌に掲載されたものと異なることがあります。

修正情報:
2006-03-01 裏ページに転載。

(C) Phinloda 2004-2006, All rights reserved.