Home > Perl > Perlで日付・時間を操作 - DateTime モジュールの使い方

Perlで日付・時間を操作 - DateTime モジュールの使い方

  • 2006-06-04 (日)
  • Perl
  • このエントリーを含むはてなブックマーク

Perlには、日時の加・減算を扱うモジュールが標準でついてきません。僕の仕事場ではずっと、同僚が作ったオリジナルモジュールを皆で使いまわしていたのですが、今になって、世間的 (CPAN) にはどんなものがあるのか気になって調べてみました。※参考になったのは miyagawa 氏のメールマガジンの過去記事と、perl.com の The Many Dates and Times of Perl なるエントリでした。

今回は数ある日付関連モジュールの中から、Dave Rolsky氏の DateTime モジュールについて、その基本的な使い方について簡単にまとめたので共有してみます。 同氏は上記 perl.com 記事の執筆者であり、この前の YAPC::Asia で DateTime project について講演してくれていた人です。気合の入ったモジュールを作ってくれた事に感謝。

目次

基本

現在日時のインスタンスを作る

use DateTime;
my $dt = DateTime->now( time_zone=>'local' );

任意の日時のインスタンスを作る

my $dt = DateTime->new(
    time_zone => 'local',
    year => 2006, month => 6,   day => 2,
    hour => 16,   minute => 30, second => 50
);

文字列に変換する

print $dt->ymd('/'); # 2006/06/02
print $dt->hms(':'); # 16:30:50
print "$dt";         # 2006-06-02T16:30:50

任意のフォーマットに整形された文字列を作る

# 2006/06/02 16:35:33
print $dt->strftime('%Y/%m/%d %H:%M:%S');
# 2006年06月02日 16時35分33秒
print $dt->strftime('%Y年%m月%d日 %H時%M分%S秒');

※フォーマット指定記号については perldoc DateTime > USAGE > strftime Specifiersを参照

月の日数を調べる

my $dt = DateTime->last_day_of_month( year=>2005, month=>2 );
print $dt->day; # 28

曜日を調べる

$dt->wday; # 1から7の数字で、1が月曜
my @wd = qw(月 火 水 木 金 土 日);
print $wd[ $dt->wday ]; # 金

▲RETURN TO TOP

日時の加算・減算

4日足す (4日後)

my $dt = DateTime->new( year=>2006, month=>5, day=>30 );
$dt->add( days => 4 );
print $dt->ymd; # 2006-06-03

3年引く (3年前)

my $dt = DateTime->new( year=>2006, month=>5, day=>30 );
$dt->subtract( years => 3 );
print $dt->ymd; # 2003-05-30

うるう年も考慮したい場合は年や月を日数で計算すべし

# 2004年はうるう年
my $dt = DateTime->new( year=>2005, month=>1, day=>10 );
$dt->subtract( days => 365 ); # 1年前
print $dt->ymd; # 2004-01-11

▲RETURN TO TOP

2つの日時の差分を調べる

普通に引き算

DateTimeインスタンス同士を引き算すると DateTime::Duration オブジェクトが作成されます

my $d1 = DateTime->new( year=>2006, month=>10, day=>5 );
my $d2 = DateTime->new( year=>2005, month=>12, day=>1 ); my $dur = $d1 - $d2; print $dur->months; # 10 print $dur->days; # 4

差分日数が知りたい

上記コードにて $dur 取得後は、 10ヶ月と4日 という差分結果を、308日 というような日数に変換することはできません。DateTime::Duration オブジェクトは変換元の日時情報を覚えていない為です (詳しくは perldoc DateTime > METHODS > in_units(..) の項目 を参照のこと)。なので、差分日数が欲しい場合は、普通に引き算する代わりに、以下のようなメソッドを使います:

my $dur = $d1->delta_days($d2);
print $dur->in_units('days'); # 308

同様に、差分の分数・秒数が知りたい場合は以下のメソッドを使います:

my $dur = $d1->delta_ms($d2); # minutes & seconds の略
print $dur->in_units('minutes'); # 444420

※この辺りはちょっとわかり難い感じ。うーん。

▲RETURN TO TOP

日時っぽい文字列を DateTime オブジェクトに変換する

文字列パターンを指定した上で変換

use DateTime::Format::Strptime;
my $strp = DateTime::Format::Strptime->new( pattern => '%Y年%m月%d日 %H:%M:%S' # 文字列のパターンを指定 );
$dt = $strp->parse_datetime('2003年04月18日 15:30:22'); print $dt->day; # 18

※パターン記号については perldoc DateTime::Format::Strptime > STRPTIME PATTER TOKENS を参照

WEBで使われているフォーマットを変換

ウェブで使われている様々な形式の日時文字列を、DateTimeオブジェクトに変換してくれます。おりこうさん。

use DateTime::Format::HTTP;
my $dt = DateTime::Format::HTTP->parse_datetime(
    '09 Feb 1994 22:23:32 GMT' # 対象文字列
);
print $dt->year; # 1994

※変換可能な文字列の一覧は perldoc DateTime::Format::HTTP > METHODS > parse_datetime() を参照

▲RETURN TO TOP

様々なフォーマットの文字列に変換する

MySQL の日付型カラム用

my $dt = DateTime->now( time_zone=>'local' );
use DateTime::Format::MySQL;
my $str = DateTime::Format::MySQL->format_datetime($dt);
print $str; # 2006-06-02 19:52:41

メールヘッダー用

use DateTime::Format::Mail;
my $str = DateTime::Format::Mail->format_datetime($dt);
print $str; # Fri, 02 Jun 2006 19:52:41 +0900

HTTP Protocol 用 (RFC 1123)

use DateTime::Format::HTTP;
my $str = DateTime::Format::HTTP->format_datetime($dt);
print $str; # Fri, 02 Jun 2006 10:52:41 GMT

日本語 with 和暦年号

use DateTime::Format::Japanese;
my $fmt = DateTime::Format::Japanese->new(
number_format => 2,
);
my $str = $fmt->format_datetime($dt); print $str; # 平成18年6月2日19時33分31秒 my $wareki = $fmt->format_year($dt); print $wareki; # 平成18年

$str や $wareki には、perl internal string 形式の文字列 (utf8 エンコード + utf8 flag on) が入ります。別の文字コードに変換する場合は、さらに以下のように書くと良いかと思われます。

use Encode;
$str = encode('euc-jp',$str); print $str; # 平成18年

※単純に '平成' とか '昭和' とかの年号がほしいだけなら、代わりに Date::Japanese::Era を使うのも良いっすね。

▲RETURN TO TOP

タイムゾーンの概念

サーバOSのタイムゾーン設定に従う

new や now 等のコンストラクタに time_zone => 'local' と指定する事で、サーバと同じタイムゾーンに設定されます。指定しなかった場合、タイムゾーンは 'UTC' (GMTとも言う) になるので注意。

my $dt = DateTime->now( time_zone=>'local' ); # 現在地域(日本)の日時
my $dt = DateTime->now();                     # UTC日時

※サーバによって 'local' が通用しないケースがあるみたい。うまくいかない場合は perldoc DateTime::TimeZone > USAGE > the "local" timezone を参照のこと。

現在のタイムゾーン名を取得

print $dt->time_zone_long_name; # Asia/Tokyo

タイムゾーンを変更する

my $dt = DateTime->now( time_zone=>'local' );
print $dt->hms; # 19:30:58 - 東京の現在時刻
$dt->set_time_zone('America/Chicago');
print $dt->hms; # 05:30:58 - シカゴの現在時刻

※指定可能なタイムゾーン名の一覧は こちら を参照、または perldoc DateTime::TimeZoneCatalog を見るべし

2つのタイムゾーン間の時差を調べる

my $d1 = DateTime->now(time_zone=>'Asia/Tokyo');
my $d2 = DateTime->now(time_zone=>'America/Chicago'); my $seconds = $d1->offset - $d2->offset; print $seconds / 60 / 60; # 14時間

▲RETURN TO TOP

ロケールの概念

デフォルトは English

my $dt = DateTime->now( time_zone => 'local' );
print $dt->month_name; # June
print $dt->day_name;   # Friday
print $dt->strftime( $dt->locale->long_date_format );
# June 2, 2006

ロケールを設定すると...

my $dt = DateTime->now(
  time_zone => 'local',
  locale => 'ja'
);
print $dt->month_name; # 6月
print $dt->day_name;   # 金曜日
print $dt->strftime( $dt->locale->long_date_format );
# 2006年6月2日

※これらの文字列は perl internal string 形式 (utf8 エンコード + utf8 flag on) なので、必要に応じて Encode::encode() 等で変換してあげましょう。

※指定可能なロケールの一覧は perldoc > DateTime::LocaleCatalog を参照のこと

▲RETURN TO TOP

難点について

他の日付関連モジュールを熟知しているわけでは無いので実行速度を含め、比較検討的な指摘は今のところできません。で、強いて難点挙げるならば

  1. インストールするのに必要な依存モジュールが多いこと
  2. 展開&作成されるモジュールファイル数・サイズが膨大 (合計5.0MB前後)

なのかなぁ、と。これだけ何でもできてしまうモジュールだけに「まあ、いっか」となりますが。

shell + make が使える環境ならば $ perl -MCPAN -e 'install CPAN' にて自動インストールできるので問題ないのですが、ライトユーザの人たちや、あまり自由の利かないサーバ環境での使用となると、敷居が高くなってしまうのが惜しい。

で、その辺についての解決策を次のエントリ「いつでもどこでも、すぐに DateTime モジュールを使いたい」で書いてみようと思います。To Be Continued...

▲RETURN TO TOP

関連情報

▲RETURN TO TOP

Comments:0

Comment Form

コメントを表示する前にこのブログのオーナーの承認が必要になることがあります。

Remember personal info

Home > Perl > Perlで日付・時間を操作 - DateTime モジュールの使い方

Search
Feeds

Page Top