01時53分45秒 [Perl/CGI]
エポック秒(UNIX時間)から日時を得るPerlの組み込み関数 localtime では、「年」の値が1900年からの相対値で得られる仕様なので、返ってきた値から西暦を知るには 1900 を足してやる必要があります。
で、そのlocaltime関数と逆のこと(=日時をエポック秒に変換)をやってくれる Time::Localモジュールの timelocal関数では、当然「年」の値を「西暦-1900」で渡さねばならないのだろう……と思ってそうしていたのですけども、そうするのは望ましくないんですね!
timelocal関数に「年」の情報を渡すときには、普通に西暦の4桁をそのまま渡せば良いのであって、1900を引いてしまうと(たまたま意図通りの結果が得られるケースもあるのですけども)場合によっては意図しない結果が得られることもあるのだと知りました。
具体的には、西暦から1900を引いた結果が2桁の数値になる場合、その2桁の数値を年の値としてtimelocal関数へ渡してしまうと、「現在から50年以上前の日付」に対しては未来の日付だと解釈されてしまう仕様なのだそうです。
……という仕様なのだとか。
わざわざ -1900 する手間をかけると(変換可能な年の幅に制約ができて)不便になってしまい、
そのまま西暦を渡せば何の問題もなく変換できる仕様だったとは……。
なんてこったい。┌(:3」└)┐
なんか1973年あたり以前の日付を処理するときにおかしなことになるなあ……と思って調べてみたところ、下記の分かりやすい解説記事を見かけて初めて知りました。^^;
➡ Perl : [ timegm / timelocal ] で「年」引数の仕様の正しい理解と使い方について
今年が2023年なので、50年前の1973年あたり以前の日付を示そうとして例えば 72 を渡すと、それは 1972年のことではなく 2072年のことだと解釈されるわけですね。
1972年を示したいのなら、単に 1972 をそのまま(timelocal関数へ)渡せば良かったのでした。
例えば、変数 $epoch
に任意のエポック秒が入っているとき、
my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime($epoch); $year += 1900; # 1900を足すと西暦になる(=西暦1900年からの相対値で得られるため) $month += 1; # 1を足すと月になる(=Januaryが0でDecemberが11なので)
……のような感じでPerlソースを書くと、変数 $year
には西暦、$month
には月、$mday
には日、$hour
には時、$min
には分、$sec
には秒が入ります。
なお、$wday
には曜日が数値で入ります。(0=日曜日、1=月曜日、……、6=土曜日)
このように、localtime関数では、西暦を得るには返ってきた年の値に 1900 を足さないといけませんし、月を得るには返ってきた月の値に 1 を足さないといけません。
上記の逆で、各変数に格納された任意の年・月・日・時・分・秒の値(=下記2行目)からエポック秒を求める場合は、
use Time::Local; my ($year, $month, $mday, $hour, $min, $sec) = (2023, 2, 23, 12, 34, 56); # 年・月・日・時・分・秒の値$year -= 1900;# ←この処理は要らない……! $month -= 1; # 月は0~11でないといけないので1を引く my $epoch = timelocal($sec,$min,$hour,$mday,$month,$year);
変に西暦から1900を引いたりせずに西暦4桁はそのまま渡して、上記のような感じでPerlソースを書くと、変数 $epoch
に指定した日時のエポック秒(UNIX時間)が数値で入ります。
localtime関数とは違って、timelocal関数の年の値は最初から西暦4桁をそのまま渡せる仕様なので、何も加工せずに西暦4桁の数値を引数に与えれば良いのだった、という話でした。
この日記へのコメントはお気軽に! コメント数:0件
コメント数: 0件