使用“DateTime”修改文件后经过的时间错误

Posted

技术标签:

【中文标题】使用“DateTime”修改文件后经过的时间错误【英文标题】:Error in elapsed time since modification of file using "DateTime" 【发布时间】:2017-10-18 22:46:37 【问题描述】:

我正在尝试清理一个相当大的文件系统。我使用stat函数来获取每个文件的修改时间。

根据perldoc -f stat,返回列表的第十个元素是自纪元以来的最后修改时间,以秒为单位。

我用DateTime->from_epoch 减去DateTime->now 来计算燃料的年龄

    #!/usr/bin/perl

    use strict;
    use warnings;

    use DateTime;

    my $now = DateTime->now();
    #my $now = DateTime->now( time_zone => "America/New_York" );

    $self->dir = '/tmp/test';
    opendir(DIR, $self->dir) or die $@;
    my @files = grep(/\.txt$/, readdir(DIR));
    closedir(DIR);

    for ( @files ) 

            my $file = stat($self->dir . '/' . $_);
            my $mtime = DateTime->from_epoch(epoch => $file->mtime);
            #my $mtime = DateTime->from_epoch(epoch => $file->mtime, time_zone=> "America/New_York");
            my $elapsed = $now - $mtime;
            push(@$self->stale, file => $self->dir . '/' . $_, mtime => $elapsed->in_units('minutes')) if $elapsed->in_units('minutes') > 15;
            push(@$self->remove, file => $self->dir . '/' . $_, mtime => $elapsed->in_units('days')) if $elapsed->in_units('days') > 10;
    

如果我手动创建测试文件并更改修改时间,结果是关闭了 30 天

$ touch /tmp/test/test100..104.txt -d '-45 days'
$ perl MTIME.pm 
$VAR1 = 
          'mtime' => 15,
          'file' => '/tmp/test/test100.txt'
        ; $VAR1 = 
          'mtime' => 15,
          'file' => '/tmp/test/test104.txt'
        ; $VAR1 = 
          'mtime' => 15,
          'file' => '/tmp/test/test103.txt'
        ; $VAR1 = 
          'mtime' => 15,
          'file' => '/tmp/test/test101.txt'
        ; $VAR1 = 
          'mtime' => 15,
          'file' => '/tmp/test/test102.txt'
        ;

我尝试了DateTime 对象,无论是否设置时区,结果都没有差异。

$ touch /tmp/test/test100..104.txt -d '-45 days'
$ touch /tmp/test/test105..110.txt
$ ll /tmp/test
total 11
-rw-r--r-- 1 root root    0 Apr  3 19:31 test100.txt
-rw-r--r-- 1 root root    0 Apr  3 19:31 test101.txt
-rw-r--r-- 1 root root    0 Apr  3 19:31 test102.txt
-rw-r--r-- 1 root root    0 Apr  3 19:31 test103.txt
-rw-r--r-- 1 root root    0 Apr  3 19:31 test104.txt
-rw-r--r-- 1 root root    0 May 18 19:30 test105.txt
-rw-r--r-- 1 root root    0 May 18 19:30 test106.txt
-rw-r--r-- 1 root root    0 May 18 19:30 test107.txt
-rw-r--r-- 1 root root    0 May 18 19:30 test108.txt
-rw-r--r-- 1 root root    0 May 18 19:30 test109.txt
-rw-r--r-- 1 root root    0 May 18 19:30 test110.txt

工作解决方案:

#!/usr/bin/perl

use strict;
use warnings 'all';

use Data::Dumper;

my $self = bless  , 'My::Class';

my @files = glob '/tmp/test/*.txt';

for (@files) 
        my $days = int(-M $_);
        my $mins = int((time - (stat $_)[9]) / 60);
        my $item = 
                file  => $_,
                days => $days,
                minutes => $mins
        ;
        push @ $self->remove , $item if $days > 10;
        push @ $self->stale ,  $item if $mins > 15;


print Dumper $self;

【问题讨论】:

你考虑过-M $file吗?这是脚本开始时间(所以,“现在”)和最后修改时间之间的差异,这似乎是您需要的。见file tests (-X)。 请查看您发布的内容。 $self->dir ... 不应该在 strict 下编译(而且没有任何意义) 你会发现要获得完整的持续时间,仅仅调用 in_units('days') 是不够的。查看 DateTime::Duration 文档,您可能会错过几个月甚至几年而没有意识到这一点。在这里直接使用纪元数和秒数可能会更容易。 您发布的代码缺少大量内容,这将使其成为一个完整的、独立的示例。就目前而言,这是胡言乱语。但是,大约 30 天的 delta 似乎向我表明,您错过了基于 Perl 或类似内容的月份为零的事实。这是我要寻找的第一件事。 如果您相隔一年创建两个 DateTime 对象,将它们相减以获得持续时间,然后调用 in_unit('days'),您会得到 ... 0。这是由于 DateTime 数学和文档中提到。 【参考方案1】:

您的问题很难理解,因为您正在编写一个面向对象的模块,然后将其作为程序运行。您显示的代码不会编译,主要是因为 $self 从未声明或定义。如果您希望得到有用的答案,请发布一个完整的程序,我们可以运行该程序并演示您所询问的问题

我无法尝试您的程序并亲自查看问题,但有两个明显的改进需要进行

调用glob 比打开和读取目​​录、删除不需要的文件并通过重新添加目录来重建每个文件的路径要容易得多

您可以使用内置的-M 运算符以浮点天数发现文件的年龄

我已经写了这个,它在My::Class 类中创建了一个空对象并向其中添加数据。它包含了我已经讨论过的想法,但就像您自己的代码不提供输出一样。希望您能理解如何将其解释为您自己的结构

您可能遇到的唯一问题是mtime 字段是浮点天数。您可能需要应用 intPOSIX::ceil,具体取决于这些值的用途

use strict;
use warnings 'all';

my $self = bless  , 'My::Class';

my @files = glob '/temp/text/*.txt';

for my $file ( @files ) 

    my $age = -M $file;

    if ( $age >= 10.0 ) 

        my $item = 
            file  => $file,
            mtime => $age,
        ;

        push @ $self->remove , $item;

        push @ $self->stale ,  $item if $age >= 15.0;
    

【讨论】:

对示例中的不完整表示歉意。我在这里发布的文章是一个包含多个方法的模块中的一种方法,并且发布整个内容既臃肿又耗时。对于调试/测试,我暂时让模块执行 PACKAGE->new->test 以查看输出。明天我会试试你的例子,看看它是如何工作的,我没有考虑过 glob。我不完全是 Perl 专业人士,而且我的大部分脚本都不处理文件系统。鉴于数据的敏感性,我想确保我以最好的方式处理这个问题。明天 2 点测试。 另外,我最初是从 -M 开始的,但是 $self->stale 以分钟而不是天为单位存储年龄,而 $self->remove 以天为单位存储年龄。 -M 的性能比利用 DateTime 好得多,但我没有得到我期望尝试它的结果(日期/时间对我来说是一个绊脚石)所以我认为也许 DateTime 可能是更安全的选择,尽管不是最理想的选择.【参考方案2】:

除了任何其他可能的问题:

my $elapsed = $now - $mtime;
push(@$self->remove, 
    file => $self->dir . '/' . $_, 
    mtime => $elapsed->in_units('days')
) 
if $elapsed->in_units('days') > 10;

不符合你的预期。

您可以创建一个 10 天的 DateTime::Duration 对象并与之进行比较。为此,您需要一个基准日期时间。

例如

my $base = DateTime->now;
my $ten_days = DateTime::Duration->new( days => 10 );

if ( DateTime::Duration->compare($elapsed,$ten_days,$base) == 1 )
    push(@$self->remove, 
        file => $self->dir . '/' . $_, 
        mtime => $elapsed->in_units('days')
    ) 

不过,我建议简单地计算 10 天内的秒数,看看经过的时间是否比这更大,因为这似乎更容易,而且 stat 无论如何都会返回 epoch。

【讨论】:

或使用-M,它会为您计算并在几天内获取输入。 Re "不过,我建议简单计算 10 天内的秒数",这实际上非常复杂。 DateTime::Duration->compare($elapsed,$ten_days,$base) == 1 确实是这样做的简单方法。然而,OP 可以做的是与time-10*24*60*60 进行比较。可能不是 10 天前,但对于 OP 来说可能已经足够接近了。

以上是关于使用“DateTime”修改文件后经过的时间错误的主要内容,如果未能解决你的问题,请参考以下文章

修修改hdfs上的文件所属用户、所属组等读写执行控制权限

泰国/佛教时代时间的 DateTime.ParseExact 问题

用批处理(vbs也行)控制winrar,将拖到批处理文件上的压缩包,进行修改,把压缩包里ABC文件夹中的文件修

解决xorm逆向mssql报datetime2不兼容的异常错误

解决从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值的问题

错误记录Melodyne 报错 ( 无法打开音频文件 )