Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Perl,如何比较YYYY-MM-DD形式的日期?_Perl - Fatal编程技术网

使用Perl,如何比较YYYY-MM-DD形式的日期?

使用Perl,如何比较YYYY-MM-DD形式的日期?,perl,Perl,我有一个带有n字符串的数组,格式为YYYY-MM-DD(例如,“2010-10-31”) 如何将日期与此数组中的字符串进行比较 例如,在30多天前删除字符串?一个好的开始是阅读和访问站点 YYYY-MM-DD格式是一种日期表示形式。它的一些变体被认为是可以接受的,例如YYYY-MM-DD和YYYYMMDD甚至在旧数据中yyymm。在选择比较这些日期的方法之前,您应该先查看一个 如果ISO 8601日期字符串为:1)有效日期;2) 使用相同格式,带或不带-分隔符;3) 由于缺少前导和尾随空格,一个

我有一个带有
n
字符串的数组,格式为YYYY-MM-DD(例如,“2010-10-31”)

如何将日期与此数组中的字符串进行比较

例如,在30多天前删除字符串?

一个好的开始是阅读和访问站点

YYYY-MM-DD格式是一种日期表示形式。它的一些变体被认为是可以接受的,例如
YYYY-MM-DD
YYYYMMDD
甚至在旧数据中
yyymm
。在选择比较这些日期的方法之前,您应该先查看一个

如果ISO 8601日期字符串为:1)有效日期;2) 使用相同格式,带或不带
-
分隔符;3) 由于缺少前导和尾随空格,一个吸引人的特性是您可以使用简单的字典式字符串比较对字符串进行排序或比较

一般来说:

  • IFF您不需要检查日期是否有效,并且IFF它们的格式是否相同,并且IFF没有前导或尾随空格,您可以与表示相同格式的目标日期的另一个字符串进行比较 ---否则---

  • 决定一个CPAN模块来解析日期字符串(或者自己匹配)

  • 如果日期在该范围内,则转换为历元时间(或使用CPAN模块,该模块执行更大规模的日期/时间操作,如date::Manip或date::Calc)

  • 对时间类型(历元时间、绝对天数等)执行算术

  • 将时间转换回您想要的格式

  • 下面是实现此目的的代码:

    use warnings; use strict;
    use Date::Calc qw/:all/;
    
    my (@date_strings, @abs_days);
    
    my $target=Date_to_Days(2010, 1, 15);
    
    # set @date_string to "YYYY-MM-DAY" between some dates
    for my $AbsDay(Date_to_Days(2009,1,1)..Date_to_Days(2011,12,31)) {
       my ($year, $mon, $day)=Add_Delta_Days(1,1,1,$AbsDay-1);
       my $s="$year-$mon-$day";
       push @date_strings, $s;
    }
    
    foreach my $s (@date_strings) {
        my ($year, $mon, $day);
    
        if(($year, $mon, $day)=$s=~/^(\d+)-(\d+)-(\d+)/) {
            my $days=Date_to_Days($year, $mon, $day);
            push @abs_days, $days 
                 if ($target-$days <= 30 && $target-$days >= -30 );
        }
    }
    
    print "absolute day way:\n";
    foreach my $days (@abs_days) {
        my ($year, $mon, $day)=Add_Delta_Days(1,1,1,$days-1);
        print "$year-$mon-$day\n";
    }
    
    使用警告;严格使用;
    使用日期::Calc qw/:all/;
    我的(@date\u字符串,@abs\u天);
    我的$target=日期到日期(2010年1月15日);
    #在某些日期之间将@date\u字符串设置为“YYYY-MM-DAY”
    对于我的$AbsDay(日期到日期(2009,1,1)…日期到日期(2011,12,31)){
    my($year,$mon,$day)=添加增量天数(1,1,1,$AbsDay-1);
    my$s=“$year-$mon-$day”;
    推送@date\u字符串,$s;
    }
    foreach my$s(@date\u字符串){
    我的($year,$mon,$day);
    如果($year,$mon,$day)=$s=~/^(\d+)-(\d+)-(\d+)/){
    我的$days=日期到天数($year,$mon,$day);
    推送@abs\u天,$days
    如果($target-$days=-30);
    }
    }
    打印“绝对日方式:\n”;
    每个我的$days(@abs\u days){
    my($year,$mon,$day)=添加增量天数(1,1,1,$Days-1);
    打印“$year-$mon-$day\n”;
    }
    
    严格使用;使用警告;
    使用DateTime();
    使用DateTime::Duration();
    使用DateTime::Format::Natural();
    my$parser=DateTime::Format::Natural->new;
    my$now=日期时间->现在;
    my$delta=DateTime::Duration->new(天=>30);
    我的$cutoff=$now->减去持续时间($delta);
    我的@new_dates=map{$\uu->[1]}
    grep{-1=$\->[0]}
    映射{
    咀嚼;
    [
    日期时间->比较(
    $parser->parse_datetime($),
    美元截止
    ),
    $_ 
    ]
    } ;
    打印“@new_dates”;
    __资料__
    2010-07-31
    2010-08-31
    2010-09-30
    2010-10-31
    
    您可以使用模块


    我想有不止一种方法,但我喜欢这样的东西

    文档中的一个示例:

    use Date::Simple ('date', 'today');
    
    # Difference in days between two dates:
    $diff = date('2001-08-27') - date('1977-10-05');
    
    # Offset $n days from now:
    $date = today() + $n;
    print "$date\n";  # uses ISO 8601 format (YYYY-MM-DD)
    
    它非常适合在objects++上进行算术运算


    但是,只有日期,没有小时、分钟或秒

    格式日期的好处在于,您可以使用简单的字符串比较来比较它们。在Perl中,这是
    lt
    gt
    运算符

    在本例中,听起来您只是想检查数组中的日期是否早于或晚于给定的目标日期(正好是“30天前”)。对于这种情况,我将采取的方法是首先确定30天前的日期,然后将其作为字符串与数组中的每个日期进行比较。我不会引入将所有
    YYYY-MM-DD
    字符串转换为“适当的”日期对象、纪元时间等并返回的开销,这仅仅是为了测试表示较早日期的字符串

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    my $thirty_days = 30 * 24 * 60 * 60;
    my ($old_day, $old_month, $old_year) = (localtime(time - $thirty_days))[3..5];
    my $cutoff = sprintf('%04d-%02d-%02d', 
                         $old_year + 1900, $old_month + 1, $old_day);
    
    my @dates = ('2010-10-12', '2010-09-12', '2010-08-12', '2010-09-13');
    for my $date (@dates) {
      print "$date\n" if $date gt $cutoff;
    } 
    

    我是这样做的,有点冗长,但很容易理解,也能完成工作@out2是一个2d数组,我使用for循环读取值。我将每个循环的输入与@out2进行比较,看它是较早的时间还是较晚的时间/日期。如果是,则将值写入数组,然后比较下一个输入

    if ($year < $out2[$j][7]) {
      $lt = 1;
      goto JUMP;
    }
    if ($year > $out2[$j][7]) {
      $gt = 1;
      goto JUMP;
    }
    if ($month < $out2[$j][5]) {
      $lt = 1;
      goto JUMP;
    }
    if ($month > $out2[$j][5]) {
      $gt = 1;
      goto JUMP;
    }
    if ($day < $out2[$j][6]) {
      $lt = 1;
      goto JUMP;
    }
    if ($day > $out2[$j][6]) {
      $gt = 1;
      goto JUMP;
    }
    if ($time < $out2[$j][4]) {
      $lt = 1;
      goto JUMP;
    }
    if ($time > $out2[$j][4]) {
      $gt = 1;
      goto JUMP;
    }
    

    为什么不是5.10以后的核心,而不是CPAN搜索的前几个结果

    use strict;
    use warnings;
    use Time::Piece (); # we don't need to include overloaded locatime
    use Time::Seconds;
    use Data::Dumper;
    
    my @dates = qw/2010-10-31 2012-10-16 2011-09-08/;
    
    my $now = Time::Piece::localtime();
    
    my @date_objects = map {
        Time::Piece->strptime( $_, '%F')  # %F is the same as %Y-%m-%d 
    } @dates;
    
    my @filtered_dates = grep {
        $now - $_ < (ONE_DAY * 30)
    } @date_objects;
    
    print Dumper(map($_->strftime('%F'), @filtered_dates));
    
    使用严格;
    使用警告;
    使用Time::Piece();#我们不需要包含重载的locatime
    使用时间:秒;
    使用数据::转储程序;
    my@dates=qw/2010-10-31 2012-10-16 2011-09-08/;
    my$now=Time::Piece::localtime();
    我的@date\u objects=地图{
    Time::Piece->strTime($,,%F')#%F与%Y-%m-%d相同
    }@日期;
    我的@filtered_dates=grep{
    $now-$\<(一天*30)
    }@date_对象;
    打印转储程序(映射($)->strftime('%F'),@filtered_dates));
    
    要在循环中查找最小日期,请执行以下操作:

    var minDate = ...;
    var maxDate = ...;
    
    foreach my $date ( @$dates ) {
        if ($minDate gt $date){ # Less than.
            $minDate = $date; # Minimal date.
        }
        if ($minDate lt $date){ # Greater than.
            $minDate = $date; # Maxamal date.
        }
    }
    

    为什么投票反对?这个问题很公平,是吗?我喜欢这个问题如何引发纯粹主义者和实用主义者之间的争论无需解析
    localtime
    的输出。这可能会对程序的性能造成很大的、不必要的消耗。一旦你构建了(单一)截止日期,就可以很容易地从词汇上比较日期。来吧,这是正确的解决方案。您描述的是一种可能在分析后使用的黑客,几乎不适用于任何其他日期格式,@brian d foy:恕我直言,我不同意您的看法。我认为最好是承受开销,妥善处理日期。大多数Perl专家(包括您)都会讲到如何将CPAN用于经过良好测试的解决方案,而不是快速推出肮脏的解决方案。
    if ($lt == 1) {
      $out2[$j][2] = "$dtime $month\/$day\/$year";
      $out2[$j][4] = $time;
      $out2[$j][5] = $month;
      $out2[$j][6] = $day;
      $out2[$j][7] = $year;
      $lt = 0;
      }
    
    if ($gt == 1) {
      $out2[$j][3] = "$dtime $month\/$day\/$year";
      $out2[$j][4] = $time;
      $out2[$j][5] = $month;
      $out2[$j][6] = $day;
      $out2[$j][7] = $year;
      $gt = 0;
    }
    
    use strict;
    use warnings;
    use Time::Piece (); # we don't need to include overloaded locatime
    use Time::Seconds;
    use Data::Dumper;
    
    my @dates = qw/2010-10-31 2012-10-16 2011-09-08/;
    
    my $now = Time::Piece::localtime();
    
    my @date_objects = map {
        Time::Piece->strptime( $_, '%F')  # %F is the same as %Y-%m-%d 
    } @dates;
    
    my @filtered_dates = grep {
        $now - $_ < (ONE_DAY * 30)
    } @date_objects;
    
    print Dumper(map($_->strftime('%F'), @filtered_dates));
    
    var minDate = ...;
    var maxDate = ...;
    
    foreach my $date ( @$dates ) {
        if ($minDate gt $date){ # Less than.
            $minDate = $date; # Minimal date.
        }
        if ($minDate lt $date){ # Greater than.
            $minDate = $date; # Maxamal date.
        }
    }