編集(管理者用) | 編集 | 差分 | 新規作成 | 一覧 | RSS | 表紙 | 検索 | 更新履歴

W3CDTFをPerlで扱う

PerlでW3CDTFとエポック秒を相互に変換するためのスクリプトを作ってみました。 (そのためだけに新しくモジュールを入れるのは避けたかったので)

Time::Localはたぶん標準でPerlに入っているのではないかと思います。

正規表現はPerlメモ/W3C形式の日時の解析を参考にしました。

blosxom用のプラグインentries_kacheで使用しています。

use strict;
use Time::Local;
use HTTP::Date;  # 比較のため

my $samp = &sampledate;
print "-----\n";
print "origin:   $samp\n";
my $t = wdt2time($samp) || 0;
print "str2time: ", str2time($samp), "\n";
print "wdt2time: ", $t, "\n";
print "time2str: ", time2str($t), "\n";
print "time2wdt: ", time2wdt($t), "\n";
print "-----\n";

sub wdt2time {
	my $str = $_[0];
	$str =~ m{
		^(\d{4})(?:                 # $1 : 年
		-(\d\d)(?:                  # $2 : 月
		-(\d\d)(?:                  # $3 : 日
		T(\d\d)                     # $4 : 時
		:(\d\d)(?:                  # $5 : 分
		:(\d\d)(?:                  # $6 : 秒
		\.(\d+) )?)?                # $7 : 小数秒
		( Z|([+-])(\d\d):(\d\d) )?  # $8 ($9, $10, $11) : 時差
		)?)?)?
	}x or return;
	my ($y, $mo, $d, $h, $mi, $s, $z);
	$y  = $1 - 1900;
	$mo = ($2 || 1) - 1;
	$d  = $3 || 1;
	$h  = $4 || 0;
	$mi = $5 || 0;
	$s  = $6 || 0;
	if (!$8) {
		$z = timegm localtime 0;
	} elsif ($8 eq 'Z') {
		$z = 0;
	} else {
		$z = ($10 * 3600 + $11 * 60);
		$9 eq '-' and $z *= -1;
	}
	my $gmt;
	eval { $gmt = timegm($s, $mi, $h, $d, $mo, $y) };
	if ($@) {
		warn $@;
		return;
	} else {
		return $gmt - $z;
	}
}

sub time2wdt {
	my $time = $_[0];
	my $z = timegm localtime 0;
	my $zh = $z / 3600;
	my $zm = (abs($z) % 3600) / 60;
	# $zh, $zmの小数部は、後のsprintfにより切り捨てられる。
	my ($s, $mi, $h, $d, $mo, $y) = localtime($time);
	$y += 1900;
	$mo += 1;
	return sprintf(
		"%04d-%02d-%02dT%02d:%02d:%02d%+03d:%02d",
		 $y,  $mo, $d,  $h,  $mi, $s, $zh,  $zm
	);
}

# 日付のサンプル(てきとう)

sub sampledate {
	return sprintf(
		"%04d-%02d-%02dT%02d:%02d:%02d%+03d:00",
		rand(68) + 1970,
		rand(12) + 1,
		rand(27) + 1,
		rand(23) + 1,
		rand(60),
		rand(60),
		rand(25) - 12,
	);
}

ご意見などありましたら是非に。