perlのDate::Simpleのformatを使うと時間がUTC(GMT?)になってしまうのですが、これを回避する方法はありますか?


redhat linux 上のperl5.8.0で下記のようなコードを動かすと

use utf8;
use Date::Simple;

print $Date::Simple::VERSION."\n";

$ENV{'TZ'}= "JST-9";
print "$ENV{'TZ'}\n";

print "1st time is ".localtime()."\n";
my $date = Date::Simple->new();
print "2nd time is ".localtime()."\n";
my $formated_date = $date->format('%Y年%m月%d日') ;
$ENV{'TZ'}= "JST-9";
print "3rd time is ".localtime()."\n";

結果が、

3.02
JST-9
1st time is Mon Apr 5 10:33:13 2010
2nd time is Mon Apr 5 10:33:13 2010
3rd time is Mon Apr 5 01:33:13 2010

な感じで、9時間戻ってしまうのですが、これを回避する方法ありますか?
Date::Simpleは、print $Date::Simple::VERSION."\n"; したところ、3.02 でした。

「 my $formated_date = $date->format('%Y年%m月%d日') ;」

処理以後のタイムゾーンが変更になってしまうので、期間チェックの処理がおかしくなります。
タイムゾーンを再び日本時間JSTに戻すのはどうしたらよいのでしょうか?

回答の条件
  • 1人2回まで
  • 13歳以上
  • 登録:2010/04/05 10:35:28
  • 終了:2010/04/12 06:36:25

回答(1件)

id:b-wind No.1

b-wind回答回数3344ベストアンサー獲得回数4402010/04/05 11:49:27

ポイント60pt
use strict;
use warnings;
use utf8;
use Date::Simple;

print $Date::Simple::VERSION."\n";

$ENV{'TZ'}= "GMT-9"; # JST
print "$ENV{'TZ'}\n";

print "1st time is ".localtime()."\n";
my $date = Date::Simple->new();
print "2nd time is ".localtime()."\n";
$ENV{'TZ'}= "GMT+0";
my $formated_date1 = $date->format('%Y年%m月%d日') ;
print "2nd time is ".localtime()."\n";
$ENV{'TZ'}= "GMT-9"; # JST
my $formated_date2 = $date->format('%Y年%m月%d日') ;
print "3rd time is ".localtime()."\n";

良くわからんが環境変数の設定を勘違いしてるだけでは?

id:samasuya

残念ながら、下記のような結果でした。


3.02

GMT-9

1st time is Mon Apr 5 13:07:02 2010

2nd time is Mon Apr 5 13:07:02 2010

2nd time is Mon Apr 5 04:07:02 2010

3rd time is Mon Apr 5 04:07:02 2010

Date::Simpleのformat関数の部分の一部が

local $ENV{TZ} = 'UTC+0';

return POSIX::strftime ($format, _gmtime ($self));

という感じらしいので、その処理の後で、

POSIX::tzset();

を入れないといけないんでしょうか?

私もよくわかってないのですが・・・。

2010/04/05 13:09:08
  • id:taknt
    use Time::Local;
  • id:samasuya
    あ、POSIX::tzset();でいいのかな?
  • id:samasuya
    taknt 2010-04-05 10:48:48 さん、コメントありがとうございます。

    use Time::Local;

    だけではNGでした。
    すみません。
  • id:samasuya
    一応、POSIX::tzset();で解決してしまいましたが、他に方法あるかもしれないので、回答お待ちしております。
  • id:JULY
    Date::Simple のドキュメント(http://search.cpan.org/~izut/Date-Simple-3.03/lib/Date/Simple.pm)に、

     It does not deal with hours, minutes, seconds, and time zones.
     (時分秒とタイムゾーンは扱わない。)

    とあるので、ローカルタイムを渡した時の挙動に関して、Date::Simple が最初から意図していないものと思われます。

    上記のドキュメントの冒頭も、

     Dates are complex enough without times and timezones.
     (日付は、時刻やタイムゾーンの話を抜きにしても、十分に複雑だ。)

    と言っているので、「タイムゾーンなんて知ったこっちゃない」というところなのかな。
  • id:samasuya
    「ローカルタイムを渡した時の挙動に関して、Date::Simple が最初から意図していないものと思われます。」

    なるほど、根本的に、日付データをフォーマットしたいときの方法が間違ってるんでしょうかね・・・。
    コメントありがとうございます。
  • id:JULY
    ひょっとしたら Perl 側のバグかも...

    CentOS 5.4 上の Perl 5.8.8 では、質問にあったスクリプトをそのまま実行しても、9時間ずれる現象は起きません。

    実行結果:
    -----------------------------------------
    3.02
    JST-9
    1st time is Tue Apr 6 13:36:48 2010
    2nd time is Tue Apr 6 13:36:48 2010
    3rd time is Tue Apr 6 13:36:48 2010
    -----------------------------------------

    気になったのは、samasuya が示された、Date::Simple で $ENV{TZ} を書き換えているところですが、本来であれば local で指定されてれば、その行を含むブロックを出た時点で、元の値に戻っているはずです。

    しかし、samasuya さんの実行結果だと、Date::Simple が書き換えた後に元に戻らず、かつ、以降、上書き出来なくなっているような雰囲気に見えます。

    5.8.0 から 5.8.1 への変更点で、local に関する変更点はあるのですが、

    http://fleur.hio.jp/perldoc/perl/5.8.1-RC4/perldelta.ja.html#local____x_

    このケースとは違うように思われるので、5.8.0 のバグだ、と決めつける事は出来ません。

    う~ん、それとも POSIX の問題なのかなぁ...。
    混迷の度を増してしまって、すみません。
  • id:samasuya
    検索してたら、http://web.archive.org/web/20060916041003/http://tokuhirom.dnsalias.org/~tokuhirom/tokulog/2131.html というようなページがありました。

    意味判る方いらっしゃいますかね?
  • id:b-wind
    >検索してたら、http://web.archive.org/web/20060916041003/http://tokuhirom.dnsalias.org/~tokuhirom/tokulog/2131.html というようなページがありました。
    >意味判る方いらっしゃいますかね?

    文面を見る限りでは非常にシンプル。
    環境変数 TZ とシステムのタイムゾーンの値は同期しているわけではない。
    POSIX::tzset() または同等の関数を呼ぶことで環境変数の値が反映されると言うのが前提になっている。

    で、この場合 POSIX::strftime の中で暗黙的に tzset が呼ばれているので strftime 自体は環境変数を反映するが、
    そのご、Perl の local 宣言のスコープからはずれ、環境変数が元に戻ってもシステムのタイムゾーンが同時に戻るわけではない。
    これを回避するためリンク先では元の環境変数を一時待避、strftime 実行後に環境変数を戻した上で改めて tzset を呼ぶことで
    strftime によって変更されたタイムゾーンを元に戻すと言う対処を行っている。


    上記はリンク先の内容を説明しただけでその真偽や是非は確認してないけどこんな所。
  • id:samasuya
    結局、現時点で、Date::Simple を使うのはまずいってことですかねぇ?Linuxだけの問題のようなんですけど。

    回答も付かないようなのでこれにて終了いたします。折角なのでコメント頂いた方々にもポイント送信しますね。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません