M.C.P.C.

―むり・くり―プラスコミュニケーション(更新終了)


| トップページ |

2008年6月23日 23:04

MIME::Lite用の時刻文字列生成

このエントリーをはてなブックマークに追加 mixiチェック

MIME::Liteで普通にメールを生成すると、

Date: Mon, 23 Jul 2008 10:00:00 UT

ていうヘッダが入ってイヤだ、という話題。何がイヤだか、ていうと、日本標準時(JST)でないので、Dateヘッダをそのまま採用するMUA(Mozilla Thunderbirdなど)でプリントアウトすると時刻が直感的にわからんのです。

最近入稿システムのメール連絡を面倒だからといって今までMIME::EntityでプログラムしていたところをMIME::Liteで組んでみたら発生した。Liteたるゆえんか。

再現コードどうぞ。

use strict;
use warnings;
use utf8;
use Encode;
use MIME::Lite;
use HTTP::Date;
 
my $msg = MIME::Lite->new(
    From      => 'from@example.com',
    To        => 'to@example.com',
    Subject   => Encode::encode('MIME-Header-ISO_2022_JP', 'コンニチワ'),
      # EncodeでMIME-Header-ISO_2022_JPが使えるのは
      # Perl5.8.6以降同梱のもの
    Type      => 'text/plain; charset="ISO-2022-JP"',
    Encoding  => '7bit',
    Data      => encode('iso-2022-jp', '元気でやってるかー?'),
);
 
$msg->send();

上記コードではDateヘッダ入れていませんが、MIME::Liteで勝手に現在時刻から入れます。それが、UT(世界時)になってしまう罠。

というわけで、MIME::Liteには、Dateヘッダを自分で設定するためのオプションとして、Datestamp => 0 を指定する方法がありますので、自分で時刻文字列作ってしまうことで、DateヘッダがUT(世界時)になることを防げます。

use strict;
use warnings;
use utf8;
use Encode;
use MIME::Lite;
use HTTP::Date;
 
my $msg = MIME::Lite->new(
    From      => 'from@example.com',
    To        => 'to@example.com',
    Subject   => Encode::encode('MIME-Header-ISO_2022_JP', 'コンニチワ'),
      # EncodeでMIME-Header-ISO_2022_JPが使えるのは
      # Perl5.8.6以降同梱のもの
    Type      => 'text/plain; charset="ISO-2022-JP"',
    Encoding  => '7bit',
    Data      => encode('iso-2022-jp', '元気でやってるかー?'),
    Datestamp => 0,
    Date      => 'Mon, 23 Jun 2008 20:00:00 +0900',
);
 
$msg->send();

なんてかんじにするとヘッダに好きな時刻を設定できます。

さて、時刻文字列を作る方法ですが、5つぐらい探しました。

#!/usr/bin/perl
use strict;
use warnings;
 
sub datestr0 {
  # UNIXのdateコマンド使う方法
  # dateコマンドの動作が違と動かない
  (local $_ = `date -R`) =~ s/\n//sgo;
  return $_;
}
 
sub datestr1 {
  # モジュールを使わない方法
  # via http://tech.bayashi.net/pdmemo/sendmailbyperl.html
  my ( $sec, $min, $hour, $mday, $mon, $year, $wday )
    = localtime( time );
  my @week  = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
  my @month = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
               'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' );
  my $d = sprintf( "%s, %d %s %04d %02d:%02d:%02d +0900",
                   $week[$wday], $mday, $month[$mon],
                   $year + 1900, $hour, $min, $sec,
          );
  return $d;
}
 
sub datestr2 {
  # HTTP::Dateモジュールを使用
  # via http://ja.doukaku.org/24/nested/
  use HTTP::Date;
  my $tz = +9;
  ( my $date = HTTP::Date::time2str( time + $tz * 3600 ) )
      =~ s/GMT/sprintf( '%+03d00', $tz )/e;
  return $date;
}
 
sub datestr3 {
  # Date::Manipモジュールを使用
  # via http://search.cpan.org/~sbeck/Date-Manip-5.54/lib/Date/Manip.pod
  use Date::Manip;
  return UnixDate('today', '%g');
}
 
sub datestr4 {
  # DateTime::Format::Mailモジュールを使用
  # via http://search.cpan.org/~sbeck/Date-Manip-5.54/lib/Date/Manip.pod
  use DateTime;
  use DateTime::Format::Mail;
  return DateTime::Format::Mail->format_datetime(
           DateTime->now(
             time_zone => 'Asia/Tokyo',
           )
         );
}
 
print datestr0()."\n";
print datestr1()."\n";
print datestr2()."\n";
print datestr3()."\n";
print datestr4()."\n";
 
__END__

実行結果:

$ perl date.pl 
Mon, 23 Jun 2008 19:49:23 +0900
Mon, 23 Jun 2008 19:49:23 +0900
Mon, 23 Jun 2008 19:49:23 +0900
Mon, 23 Jun 2008 19:49:24 +0900
Mon, 23 Jun 2008 19:49:24 +0900
$

それぞれの評価:

datestr0バッククオート演算子危ないので使用禁止
datestr1Perlのみテッパン
datestr2HTTP::Dateモジュール割と素直。環境依存しにくい
datestr3Date::Manipモジュール一番楽だがWindowsだと動かない可能性あり
datestr4DateTime::Format::Mailモジュールプログラム内でDateTime使ってしまったときについでに使う。

こう書いていると、なんだか大がかりになってきたので、普通にMIME::Entity使った方が楽なんじゃないかという気にもなってきました。

投稿 大野 義貴 [Perl] | |

トラックバック(0)

トラックバックURL: http://blog.dtpwiki.jp/MTOS/mt-tb.cgi/2511

コメントする