ルモーリン
ホーム 更新 Perl Sample サービス 雑談 鉄ゲタ Linux リンク 連絡先

Perlサンプル16 FTPのファイル日時判定

2020-01-29

FTPのリモートファイルの更新日時を基に、DateTimeオブジェクトを生成します。

Perlスクリプトの中でNet::FTPSSLを使いリモートファイルの情報を取得すると、更新日時がファイル毎に異なる書式で戻ります。 なお、このサンプルではNet::FTPSSLを呼ばずファイル情報の文字列だけを用意して日時を設定します。
Net::FTPSSL - A FTP over TLS/SSL class - metacpan.org
書式の違いは次の通りです。

  1. 半年経過したファイルは年月日の日付だけ
    -rw-r--r-- 1 1007 1007 11941 Jan 30 2019 yome.jpg
  2. 半年以内のファイルは月日と日時の両方
    -rw------- 1 1007 1007 155225 Sep 6 19:46 takoluka.jpg
年が省略されている場合、今年の前半で使った場合は去年のケースがあるので実行日時と比較して去年と判定します。

#!/usr/bin/env perl

use v5.26;
use utf8;
use warnings;
use strict;

use feature "say";
use open IO => ":utf8";

use DateTime;
use DateTime::Format::Strptime;
use Encode::Argv;
use Encode::Locale;

binmode STDOUT, ":encoding(console_out)";
binmode STDERR, ":encoding(console_out)";

$| = 1;

my @test_data = (
	{
		case => "半年超過",
		string => "-rw-r--r-- 1 1007 1007 11941 Jan 30 2019 yome.jpg",
	},
	{
		case => "半年以内で去年",
		string => "-rw------- 1 1007 1007 155225 Sep 6 19:46 takoluka.jpg",
	},
	{
		case => "半年以内で今年",
		string => "-rw------- 1 1007 1007 155225 Jan 15 13:14 luka.jpg",
	},
);

for (@test_data) {
	say "ケース:$_->{case}";
	say "文字列:$_->{string}";

	my $dt = file_datetime($_->{string});
	say "日時:" . $dt->strftime("%F %T");
	say "-----";
}

exit;

sub file_datetime {
	my ($file_status) = @_;

	my @field = split / +/, $file_status, 9;
	my $dt_str = join " ", @field[5..7];
	my $file_dt;

	if ($dt_str =~ /:/) {
		# 半年以内
		my $strp = DateTime::Format::Strptime->new(pattern => "%b %d %R %Y");
		# 現在日時
		my $now_dt = DateTime->now(time_zone => "local");
		# 今年前提でパース
		$file_dt = $strp->parse_datetime($dt_str . " " . $now_dt->year);
		# 現在日時より進んでしまった場合は去年でパース
		$file_dt = $strp->parse_datetime("$dt_str @{[$now_dt->year - 1]}") if DateTime->compare($now_dt, $file_dt) < 0;
	} else {
		# 半年超過
		$file_dt = DateTime::Format::Strptime->new(pattern => "%b %d %Y")->parse_datetime($dt_str);
	}

	return $file_dt;
}
ケース:半年超過
文字列:-rw-r--r-- 1 1007 1007 11941 Jan 30 2019 yome.jpg
日時:2019-01-30 00:00:00
-----
ケース:半年以内で去年
文字列:-rw------- 1 1007 1007 155225 Sep 6 19:46 takoluka.jpg
日時:2019-09-06 19:46:00
-----
ケース:半年以内で今年
文字列:-rw------- 1 1007 1007 155225 Jan 15 13:14 luka.jpg
日時:2020-01-15 13:14:00
-----

Net::FTPSSLには同一書式でファイル情報を返すインターフェースがあるのでそれを使えば、2種類の書式(3種類の条件)の切り分けを省けます。

mlsd( [DIRECTORY [, PATTERN [, FTYPE]]] )

    Returns a list of files/directories in a standardized machine readable format designed for easy parsing.

modify=20041027194930;type=file;size=28194; foo
modify=20041027194932;type=file;size=3201931; pub
modify=20180329120944;type=dir;size=256; bar