在Perl中,如何解析日期字符串并从它代表的日期中减去天数?

时间:2012-07-08 11:54:10

标签: perl datetime

我在$str1="20120704"中的字符串中有一个日期。我想从该日期减去1天,并将日期值存储为$str2中的字符串。我该怎么办?

5 个答案:

答案 0 :(得分:10)

这与您几天前提出的另一个问题非常相似。所以,不出所料,解决方案也非常相似。

Time :: Piece and Time ::自版本5.10.0以来,Seconds已成为标准Perl发行版的一部分。你应该使用它们。

#!/usr/bin/perl

use strict;
use warnings;
use 5.010;

use Time::Piece;
use Time::Seconds;

my $format = '%Y%m%d';
my $str1 = '20120704';

my $dt1 = Time::Piece->strptime($str1, $format);
my $dt2 = $dt1 - ONE_DAY;
my $str2 = $dt2->strftime($format);
say $str2;

答案 1 :(得分:9)

Perl以易于操作的内部格式存储日期和时间。你所拥有的是YYYYMMDD格式的日期。所以,你需要做的是:

  1. 将您的日期(采用YYYYMMDD格式)转换为Perl的日期/时间存储格式。
  2. 使用Perl来操纵此日期和时间。
  3. 如果要输出结果,则必须将其转换回所需的格式。
  4. 将您的日期(采用YYYYMMDD格式)转换为Perl的日期/时间存储格式。

    执行此操作的最佳模块是Perl附带的Time::Piece。这很简单:

    my $date = Time::Piece->strptime($str1, '%Y%m%d');
    

    $date现在将成为您的日期和时间,但以Perl可以理解和操作的格式存储。 %Y%m%d是对您的格式的描述,因此Perl知道在哪里可以找到该月的年,月和日。您可以查看strftime以查看各种格式参数。在你的情况下:

    • %Y - 代表世纪的年份,例如2012
    • %m - 将月份表示为两位数字,例如0312
    • %d - 如果当月有很多天,则将月份日期表示为0131的两位数字。

    下一步:操纵你的约会。

    您可以使用另一个名为Time::Seconds的模块来处理此问题。

    Time::Seconds定义了一堆常量,如ONE_DAY,这使事情变得更容易:

     my $date = $date - ONE_DAY;
    

    最后:将日期转换回您想要的格式。

    同样,Time::Piece有一个非常简单的方法为您做到这一点:

    $date->ymd("");
    

    这会将$date转换为年 - 月 - 日格式的字符串。默认情况下,这会在每个部分之间放置-。但是,您可以将要用作分隔符的字符传递给它。在这种情况下,没有。

    所有在一起:

    use Time::Piece   # For manipulating and storing the date
    use Time::Seconds # For the nice constants such as ONE_DAY and ONE_WEEK
    
    my $date = Time::Piece->strptime($str1, '%Y%m%d');
    my $date = $date - ONE_DAY;
    my $str2 = $date->ymd('');
    

    这很简单。


    Dave Cross给了你一个很好的答案。我通常只是投票给他,并留下它。不过,他也提到你几天前问了一个类似的问题。对我而言,这意味着您可能已经使用过Dave Cross之前的答案,但您并不理解它。那不好。

    查看Time::PieceTime::Seconds的文档。看一下strfdate并玩弄它。学习并理解它。如果您对这些有任何疑问,请在Stackoverflow上询问。 Stackoverflow上的人们更乐意回答诸如“这如何工作?”之类的问题。而不是“你能为我做这件事吗?”他们会花时间和精力来解释第一个,而大多数人会忽略后者或给你一个粗略的答案。

    这将使您成为更好的程序员,这意味着您对公司更有价值,并转化为更高的薪酬。值得您花时间和精力。

    尝试理解它。玩弄它。


    附录

      

    使用较旧的perl版本5.8,并考虑使用系统中的现有模块。也不确定time :: piece如何工作

    这是一个非常古老的Perl版本,但它在Solaris上很常见。

    在这种情况下,我们将采用非常古老的方式。

    有两个名为localtimegmtime的Perl函数。这些采用自1970年1月1日以来的秒数并将其转换为值数组,每个值代表时间的特定部分(月,年,日,小时,分钟等)。

    你需要的是反函数 - 可以采用一系列值并将其转换为自1970年以来的秒数。自Perl 3.0以来,Perl的每个版本都包含了这样的模块。在Perl 5.x中,tt称为Time::Local。它为您提供了两个名为timelocaltimegm的函数。这些是我们需要的反函数。

    首先,我们需要将您的字符串拆分为单独的年,月和日,将其放入数组中timegmtimelocal转换为自1月1日以来的秒数, 1970。

    接下来,我们将减去一天中的秒数。这是60 * 60 * 24或86,400。

    最后,我们会将新的 date 转换为可用于以YYYYMMDD顺序显示日期的数组。

    两个重要的警告!

    • 该函数假定月份为0到11而不是1到12.这允许您创建一个数组以将月号转换为名称。这意味着我们必须在向gmtime提交之前的一个月中减去1,并在从timegm收回时添加一个。
    • 这一年是自1900年以来的年数。这意味着我们必须先将1900减去gmtime,然后在我们从timegm取回时增加1900。

    而且,现在的程序:

    #! /usr/bin/env perl
    
    use strict;
    use warnings;
    
    use Time::Local;
    
    my $date = 20120615;    #2012-June-15
    
    $date =~ /(....)(..)(..)/;  #Parse the date
    
    my $year = $1;
    my $month = $2;
    my $day = $3;
    
    $month -= 1;    #Month is 0 to 11 and not 1 to 12
    $year -= 1900;  #Year is number of years since 1900
    
    my $seconds = 0;
    my $minutes = 0;
    my $hours = 0;
    
    my $perl_date = timegm($seconds, $minutes, $hours, $day, $month, $year);
    
    my $perl_date2 = $perl_date - (60 * 60 *24);
    
    my ($seconds2, $minutes2, $hours2, $day2, $month2, $year2)  = gmtime($perl_date2);
    
    $month2 += 1;   #Month is returned as 0 - 11. Make 1 - 12
    $year2 += 1900; #Year is given as years since 1900. Add 1900 back to it. 
    
    printf qq(The date is %04d-%02d-%02d \n), $year2, $month2, $day2;
    

答案 2 :(得分:8)

我建议你使用模块DateTime和一个ext格式。您还可以看到模块Date::CalcDate::Parse + POSIX函数strftime。

use strict;
use DateTime;
use DateTime::Format::Strptime;

my $date_str = '20120704';
my $date_obj = DateTime::Format::Strptime->parse_datetime($date_str);

my $date_res = $date_obj->subtract(days => 1)->ymd;

答案 3 :(得分:1)

这会吗?

use Date::Parse;
use POSIX;

my $s1 = "20120704";
my $t = str2time($s1) - 86400;
my $s2 = strftime "%Y%m%d", localtime $t;

print "$s2\n";

注意localtime vs gmtime,如果你关心这些,请注意闰秒。

答案 4 :(得分:1)

这是一个简单的strptime / strftime往返。由于strftime标准化输入,因此只需从mday字段中减去1即可。

use POSIX 'strftime';
use POSIX::strptime 'strptime';

my $fmt = "%Y%m%d";
my @t = strptime "20120704", $fmt;
$t[3] -= 1;  # 1 day
my $str2 = strftime $fmt, @t;