【问题标题】:perl's datetime subtraction with signperl 的带符号的日期时间减法
【发布时间】:2021-12-08 16:38:30
【问题描述】:

我正在尝试使用 Perl 的 DateTime 用符号从另一天减去一天。我可以轻松地度过中间的日子:

sub delta_days {
    my $date1 = shift;
    my $date2 = shift;
    my $d1 = str_to_date_object($date1);
    my $d2 = str_to_date_object($date2);
    return $d2->delta_days($d1)->delta_days();
}
say delta_days('2021-10-21', '1980-8-20');
say delta_days('1980-8-20',  '2021-10-21');

但是这两个调用都给出了 15037 的区别,没有符号。

按照文档https://metacpan.org/pod/DateTime

我明白了

# not DST
my $dt1 = DateTime->new(
    year      => 2003,
    month     => 5,
    day       => 6,
    time_zone => 'America/Chicago',
);
 
# is DST
my $dt2 = DateTime->new(
    year      => 2003,
    month     => 11,
    day       => 6,
    time_zone => 'America/Chicago',
);
my $dur = $dt2->subtract_datetime($dt1)->days();

我在How to make DateTime::Duration output only in days? 中检查了一个类似的问题,但我不知道如何在那里获得签名差异。

我怎样才能得到一个标志的天数差异?

【问题讨论】:

    标签: date perl


    【解决方案1】:

    两个问题:如果你想要一个负偏移量,你正在以错误的顺序对日期进行减法,并且你正在测试 subtract_datetime() 的日期,持续时间对象将有 0 天。

    与此版本比较:

    #!/usr/bin/env perl
    use strict;
    use warnings;
    use feature qw/say/;
    use DateTime;
    use Data::Dumper;
    
    # not DST
    my $dt1 = DateTime->new(
        year      => 2003,
        month     => 5,
        day       => 6,
        time_zone => 'America/Chicago',
    );
    
    # is DST
    my $dt2 = DateTime->new(
        year      => 2003,
        month     => 11,
        day       => 6,
        time_zone => 'America/Chicago',
        );
    say $dt1;
    say $dt2;
    
    my $dur = $dt1->subtract_datetime($dt2);
    print Dumper({$dur->deltas});
    

    运行时产生的

    2003-05-06T00:00:00
    2003-11-06T00:00:00
    $VAR1 = {
              'minutes' => 0,
              'nanoseconds' => 0,
              'months' => -6,
              'seconds' => 0,
              'days' => 0
            };
    

    注意 -6 个月的偏移量。 DateTime::Duration 对象不会根据 the documentation 在月份和日期之间转换,所以这看起来像死路一条。

    您首先查看的delta_days 方法返回实际天数差异,但如前所述,它是一个绝对值。如果第一个日期在第二个日期之前,您可以添加一个检查以将其转换为负数:

    my $days = $dt1->delta_days($dt2)->in_units('days');
    $days *= -1 if $dt1 < $dt2;
    say $days; # Prints -184
    

    以及您的 delta_days() 函数的变体:

    sub delta_days {
        my $date1 = shift;
        my $date2 = shift;
        my $d1 = str_to_date_object($date1);
        my $d2 = str_to_date_object($date2);
        return $d1->delta_days($d2)->in_units('days') * ($d1 < $d2 ? -1 : 1);
    }
    say delta_days('2021-10-21', '1980-8-20');
    say delta_days('1980-8-20',  '2021-10-21');
    

    【讨论】:

    • 如果您希望负偏移量表示第一个日期相对于第二个日期而不是过去的未来,只需检查大于而不是小于。
    猜你喜欢
    • 1970-01-01
    • 2018-12-21
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多