新年とテスト

0
772

あけましておめでとうございます。
2020年は兎にも角にもコロナで大変な年でしたが、2021年はどんな年になるでしょう?
未だにコロナ次第ではありますが、良い年にしたいものです。

さて今回は「新年とテスト」と銘打ちました。
新春を寿いでもう少しめでたい話題でもと思いましたがお屠蘇が抜けない頭で思いついたのがこれだったので。
「新年」と「テスト」から連想されるのは一般的には「センター試験」ですかね?私は「共通一次」世代ですが。
ただ、ここで言う「テスト」はプログラムの動作確認のことです。

新年、特に3末辺りまでの期間は日付を扱う処理を含むプログラムにとっては少々厄介な時期です。
例えば、直近一週間以内に誕生日を迎えるユーザーをDBから抽出するような処理を考えたとします。実行日付が12月21日であれば、対象は12月21日〜27日となりますが、これは12月21日以上12月27日以下と言う条件で判定できます。しかし、実行日付が12月28日の場合、対象は12月28日〜1月3日となりますが、これを同様に12月28日以上1月3日以下とは条件付けできません。年を含まず単に日付だけであれば12月28日よりも1月3日の方が小さいため、上記条件では対象がなくなってしまいます。12月28日以上12月31日以下と1月1日以上1月3日以下のいずれかの条件を満たす場合と言うように条件設定を変える必要があります。
他には「年」と「年度」の違いとか。例えば、2021年1月3日は「2021年」であり「2020年度」です。この辺も油断しているとバグり易いところかと。

処理内容はケースバイケースかと思いますが、いずれにしても胡散臭い所なのでしっかりと動作確認はしておくべきです。しかし、実際に動作検証を行うのは検証したい日付とは別の日付と言うことがほとんどです。よって、対象処理に対して「実行時の日付」を「目的の日付」に見せかける必要が生じます。以前は力技で動作検証を行うPCの時刻情報自体を変更していたこともありますが、PC自体の運用に影響が出る可能性もあり、あまり推奨できる方法ではないでしょう。

PHPには時刻情報操作を行うライブラリとして「Carbon」があります。開発するプログラムにおける時刻関連処理で同ライブラリを使用するように統一しておくことで上記問題が簡単に解消します。
具体的な使用方法は以下の通り。

Carbon::setTestNow('2021-04-01 12:34:56');
echo Carbon::now()->format("Y-m-d H:i:s")."\n";
echo date("Y-m-d H:i:s")."\n";

「setTestNow」で設定したい「目的の日付(日時)」を指定しています。
実は引数に関しては、ネット情報では以下のような書き方を見かけることが多いです。

Carbon::setTestNow(Carbon::parse('2021-04-01 12:34:56'));

しかし、試しに前述のようにsetTestNowの引数に直接対象日時(文字列)を指定したところ期待する結果が得られましたので、こちらの方が簡単で良いように思うのですが。

で、上記実行結果は以下のようになります。

2021-04-01 12:34:56
2021-01-03 14:48:14

Carbon経由で取得したカレント日時は直前で設定した内容になっています。
一方、一般的な時刻操作関数であるdateで取得した日時は実際の実行日時のままです。setTestNowによる時刻情報変更の影響範囲が良くも悪くもCarbonに関する操作に限定されていることが分かります。
個人的に愛用しているLaravelでは、Eloquentで「protected $dates」に指定した要素は自動的にCarbonインスタンスに変更されるなど標準的に時刻操作にCarbonを使用するようになっていますので、独自に実装した処理でも漏れなくCarbonを使用するようにしておくことが吉だと思ってます(Carbon便利ですし)。

かつては「西暦2000年問題」などもありました。当時も現役プログラマだったため、正月三が日も24時間2交代性で出社し、トラブルに備えて待機していたことを思い出します。そこまでの状況が発生することはカレンダー的には当面ないかと思いますが、先に書いたように新年が日付関連処理として特殊性を持つ時期であることは毎年変わりませんので、その類の処理を持つプログラムの運用に関わっている限りリスクは0にはなりません。
安心して新年が迎えられるよう、関連する動作検証はしっかり行っておきたいところです。