我在$str1="20120704"
中的字符串中有一个日期。我想从该日期减去1天,并将日期值存储为$str2
中的字符串。我该怎么办?
答案 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格式的日期。所以,你需要做的是:
执行此操作的最佳模块是Perl附带的Time::Piece。这很简单:
my $date = Time::Piece->strptime($str1, '%Y%m%d');
$date
现在将成为您的日期和时间,但以Perl可以理解和操作的格式存储。 %Y%m%d
是对您的格式的描述,因此Perl知道在哪里可以找到该月的年,月和日。您可以查看strftime以查看各种格式参数。在你的情况下:
%Y
- 代表世纪的年份,例如2012
。%m
- 将月份表示为两位数字,例如03
或12
。%d
- 如果当月有很多天,则将月份日期表示为01
到31
的两位数字。您可以使用另一个名为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::Piece和Time::Seconds的文档。看一下strfdate并玩弄它。学习并理解它。如果您对这些有任何疑问,请在Stackoverflow上询问。 Stackoverflow上的人们更乐意回答诸如“这如何工作?”之类的问题。而不是“你能为我做这件事吗?”他们会花时间和精力来解释第一个,而大多数人会忽略后者或给你一个粗略的答案。
这将使您成为更好的程序员,这意味着您对公司更有价值,并转化为更高的薪酬。值得您花时间和精力。
尝试理解它。玩弄它。
使用较旧的perl版本5.8,并考虑使用系统中的现有模块。也不确定time :: piece如何工作
这是一个非常古老的Perl版本,但它在Solaris上很常见。
在这种情况下,我们将采用非常古老的方式。
有两个名为localtime和gmtime的Perl函数。这些采用自1970年1月1日以来的秒数并将其转换为值数组,每个值代表时间的特定部分(月,年,日,小时,分钟等)。
你需要的是反函数 - 可以采用一系列值并将其转换为自1970年以来的秒数。自Perl 3.0以来,Perl的每个版本都包含了这样的模块。在Perl 5.x中,tt称为Time::Local。它为您提供了两个名为timelocal
和timegm
的函数。这些是我们需要的反函数。
首先,我们需要将您的字符串拆分为单独的年,月和日,将其放入数组中timegm
或timelocal
转换为自1月1日以来的秒数, 1970。
接下来,我们将减去一天中的秒数。这是60 * 60 * 24或86,400。
最后,我们会将新的 date 转换为可用于以YYYYMMDD顺序显示日期的数组。
两个重要的警告!
gmtime
提交之前的一个月中减去1,并在从timegm
收回时添加一个。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::Calc
或Date::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;