業務用ソフトウェアの開発時にバグの原因になりやすい処理のひとつに日付の計算がある。エンタープライズ向けのコマンド群であるOpen usp Tukubaiにはmdate(1)とyobi(1)というコマンドがあり、問題になりがちな日付や曜日の処理を解決できるようになっている。
ここではmdate(1)やyobi(1)の便利な使い方を紹介する。
たとえば2012年の2月の末日を出力させたいとする。2月の末日は平年と閏年で28日になるか29日になるかが変わってくる。平年であるか閏年であるかの判定処理は日付処理のライブラリがすでに実装として持っているため、通常は「2012年3月1日の1日前を出力」といった指定をして2月の末日を得るといった処理を記述することになる。
こうした処理はmdate(1)を使うと簡単に記述できる。
$ mdate 20120301/-1 20120229 $
同様の処理をBSD date(1)で記述すると次のようになる。
$ date -v-1d -j "+%Y%m%d" 201203010000 20120229 $
GNU date(1)で記述すると次のようになる。
$ date -d "20120301 1 day ago" "+%Y%m%d" 20120229 $
mdate(1)に比べると通常のdate(1)コマンドの指定は煩雑といえる。mdate(1)は業務用ソフトウェアでよく利用される機能が簡単に記述できるように設計されている。
「2012年1月3日は2012年1月2日の何日後か」という計算はmdate(1)を使うことで次のように処理できる。
$ mdate 20120103 20120102 1 $
年をまたいだ計算も簡単に実施できる。
$ mdate 20140101 20120101 731 $
次のようにmdate(1)を使うことで、2012年4月26日から1週間(6日後まで)の日付出力を得ることができる。
$ mdate -e 20120426/+6 20120426 20120427 20120428 20120429 20120430 20120501 20120502 $
この出力をtarr(1)あるいはtr(1)に通すことで一列にデータが出力される。
$ mdate -e 20120426/+6 | tarr 20120426 20120427 20120428 20120429 20120430 20120501 20120502 $ mdate -e 20120426/+6 | tr ' ' 'n' 20120426 20120427 20120428 20120429 20120430 20120501 20120502 $
BSD date(1)やGNU date(1)でも同様の処理は実現できるが、実現するためにはスクリプトを組む必要がある。BSD date(1)では次のようになる。
$ i=$(date "+%Y%m%d") $ for j in $(seq 7) > do > echo $i > i=$(date -v+1d -j -f "%Y%m%d" "${i}" "+%Y%m%d") > done 20120427 20120428 20120429 20120430 20120501 20120502 20120503 $
GNU date(1)では次のようになる。
$ i=$(date "+%Y%m%d") $ for j in $(seq 7) > do > echo $i > i=$(date -d "${i} 1 day" "+%Y%m%d") > done 20120427 20120428 20120429 20120430 20120501 20120502 20120503 $
mdate(1)ではコマンドの機能としてこの処理を提供しており、1行で処理を完結させることができる。
「2012年4月26日の曜日」を知りたい場合には次のようにyobi(1)コマンドを使用する。
$ echo 20120426 | yobi -j 1 20120426 木 $
yobi(1)の-jオプションは日本語で曜日を出力する指定。第1引数で指定した値は処理するフィールドの番号を表しており、ここで1を指定することで行の最初の文字列を処理している。
mdate(1)と組み合わせれば、2012年4月26日から1週間の曜日を出力するといった処理も次のように記述できる。
$ mdate -e 20120426/+6 | tarr | yobi -j 1 20120426 木 20120427 金 20120428 土 20120429 日 20120430 月 20120501 火 20120502 水 $
任意の月の日付をすべて出力するといった処理もmdate(1)を使うと簡単に実現できる。2012年4月の日付をすべて出力する場合には次のようにmdate(1)を実行する。
$ mdate -d 201204m | tarr -7 20120401 20120402 20120403 20120404 20120405 20120406 20120407 20120408 20120409 20120410 20120411 20120412 20120413 20120414 20120415 20120416 20120417 20120418 20120419 20120420 20120421 20120422 20120423 20120424 20120425 20120426 20120427 20120428 20120429 20120430 $
tarr(1)の-7は7フィールドごとに改行するといった処理の指定。
たとえば、次のような業務データがあったとする。日付と売上数のリストなどがこうした形式のファイルになる。
$ cat data 20120128 5 20120129 32 20120203 11 $
このデータファイルには売上がない日のデータが存在していない。このデータファイルに、売上がない日には売上数0としてデータを追加したいといった要望があったとする。
手続き型プログラミングの発想では日付を比較して処理をすることになるが、ユニケージ開発手法の発想ではこの処理は次のように記述する。
$ FROM=$(head -n 1 data | self 1) $ TO=$(tail -n 1 data | self 1) $ mdate -e $FROM $TO 20120128 20120129 20120130 20120131 20120201 20120202 20120203 $ mdate -e $FROM $TO | tarr | join2 -d0 key=1 data - 20120128 5 20120129 32 20120130 0 20120131 0 20120201 0 20120202 0 20120203 11 $
日付のデータを作成し、そのデータをデータファイルとjoin2(1)で結合するといった処理になる。
mdate(1)の機能一覧は次のようにmdate(1)に何の引数も指定せずに実行すれば表示される。またはオンラインマニュアルTukubaiオンラインコマンドマニュアル : mdate(1)を参照すればよい。
$ mdate
mdate(1)における機能は業務システムの開発を通じて「これがないと困る」という機能のみが追加されてきたという歴史的背景がある。業務システム開発において日付処理に要求されるほとんど機能がmdate(1)によってカバーされている。
※ ユニケージはユニバーサル・シェル・プログラミング研究所の登録商標。
※ usp Tukubaiはユニバーサル・シェル・プログラミング研究所の登録商標。