こんばんは、Magnoliaです。
この記事はPerl Advent Calendar 2018の16日目の記事です。昨日、15日目は(予定では…)@karupaneruraさんの「ISUCON8予選問題においてPerl実装で25万点を突破する方法」でした。
さて、Qiitaに投稿するのがすっかりPerl Advent Calendarの時だけになった気がしますが…最近Perlを書く機会もすっかり無くなり、先日珍しく30分枠という長い枠で登壇しましたが、コード例はRubyで書いています。
「設計Night2018 powered by Classi」で登壇してきました - Magnolia Tech
しかし、実は最初Perlで書こうとしたのですが、ちょっと想定と違った結果になったので、結局Rubyで書き直しました、今日はその話をします。
Time::Pieceモジュール
Perlの日付処理モジュールといえばコアモジュールにTime::Pieceが用意されています。少し古い話ですが、Perl 5.10からコアモジュール入りしていて、それ以前は日付関連のモジュールはかなり混沌としていたようです。その辺りの事情は以下の記事に詳しく書かれています。
第15回 DateTime:APIの標準化をめざして:モダンPerlの世界へようこそ|gihyo.jp … 技術評論社
Time::Secondsモジュールによる日付の計算
Time::Pieceには、Time::Secondsというモジュールが同梱されていて、こちらを使うと日付の計算ができるようになります(1年後とか、1ヶ月後とか)。
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $t = Time::Piece->strptime('2018-01-01', '%Y-%m-%d');
my $t1 = $t + ONE_DAY;
my $t2 = $t + ONE_MONTH;
my $t3 = $t + ONE_YEAR;
print $t . "\n";
print $t1 . "\n";
print $t2 . "\n";
print $t3 . "\n";
これを実行すると…
$ perl time.pl
Mon Jan 1 00:00:00 2018
Tue Jan 2 00:00:00 2018
Wed Jan 31 10:29:04 2018
Tue Jan 1 05:48:50 2019
年で演算すると時刻も…進んでいる??月は2月になってなくて一ヶ月進んでない??
まぁ、ドキュメントにはちゃんと書かれているんですけどね…
The methods make the assumption that there are 24 hours in a day, 7 days in a week, 365.24225 days in a year and 12 months in a year. (from The Calendar FAQ at http://www.tondering.dk/claus/calendar.html)
つまり、1年を365.24225日として計算しています…月あたりの日数は考慮していない(12等分しかしていない)ということなんですが…
4年経つと、うるう年が考慮されて丁度きれいになる…という訳だけど、ユースケース的に日付の計算をしているはずが、時刻が進むとか、月の日数に合わせた計算になっていないとか、全然直感的じゃないですよね…っていうか、普通にうるう年の日単位の計算をしてほしい…という訳で、日付の計算なのに、時刻が変わったり、月がきれいに揃わないというところにハマってしまった、という話でした。いや、ドキュメント読めばいいけど、でもユースケースと合わないと…思う。
ちなみにRubyのDateモジュールは時刻を一緒に扱わないので、そのような心配は無いです。
でも、年齢の到達日を計算する時はそれでもハマります…その辺りは冒頭で紹介したスライドをぜひ読んでみてください。
その他のハマりどころとして、3年前の「はてなデベロッパーアドンベントカレンダー 2015」にもこんな記事が有ります。
Perl の Time::Piece 利用上の注意点 - Hatena Developer Blog
というわけで、ちょっとしたTime::Pieceモジュールのちょっとしたハマりどころの紹介でした。
明日は、Morichanさんによる「Perlとクラス図の対応付け」という話です、お楽しみに!