我在字符串中有一个日期,如$str1="20120704"
. 我想从该日期减去 1 天,并将日期的值作为字符串存储在$str2
. 我该怎么做?
5 回答
这与您几天前提出的另一个问题非常相似。因此,不出所料,解决方案也非常相似。
Time::Piece 和 Time::Seconds 自 5.10.0 版以来一直是标准 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;
Perl 以易于操作的内部格式存储日期和时间。您所拥有的是 YYYYMMDD 格式的日期。所以,你需要做的是:
- 将您的日期(格式为 YYYYMMDD)转换为 Perl 的日期/时间存储格式。
- 使用 Perl 来操作这个日期和时间。
- 当您想要输出结果时,您必须将其转换回您想要的格式。
将您的日期(格式为 YYYYMMDD)转换为 Perl 的日期/时间存储格式。
执行此操作的最佳模块是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
to的两位数。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 之前的答案,但您并不理解它。这不好。
查看Time::Piece和Time::Seconds的文档。看看strfdate并玩弄它。学习它并理解它。如果您对这些有任何疑问,请在 Stackoverflow 上提问。Stackoverflow 上的人们更乐于回答诸如“这是如何工作的?”之类的问题。而不是“你能为我做这件事吗?”。他们会花时间和精力来解释第一个,而大多数人要么忽略后者,要么给你一个粗略的答案。
这将使您成为更好的程序员,这意味着您对公司更有价值,并转化为更高的薪水。值得您花时间和精力。
试着理解它。玩弄它。
附录
正在使用较旧的 perl 版本 5.8,并考虑使用系统中的现有模块。也不确定 time::piece 是如何工作的
这是一个相当老的 Perl 版本,但在 Solaris 上很常见。
在这种情况下,我们将采用非常古老的方式。
有两个 Perl 函数称为localtime和gmtime。这些取自 1970 年 1 月 1 日以来的秒数,并将其转换为一个值数组,每个值代表时间的特定部分(月、年、日、小时、分钟等)。
您需要的是反函数——它可以获取一组值并将其转换为自 1970 年以来的秒数。从 Perl 3.0 开始,每个版本的 Perl 中都包含了这样一个模块。在 Perl 5.x 中,tt 称为Time::Local。它为您提供了两个称为timelocal
和的函数timegm
。这些是我们需要的反函数。
首先,我们需要将您的字符串拆分为单独的年、月和日,将其放入一个数组中,timegm
或者timelocal
转换为自 1970 年 1 月 1 日以来的秒数。
接下来,我们将减去一天中的秒数。这是 60 * 60 * 24 或 86,400。
最后,我们将该新日期转换为一个数组,您可以使用该数组以 YYYYMMDD 顺序显示日期。
两个重要的警告!
- 该函数假定月份是从 0 到 11 而不是 1 到 12。这允许您创建一个数组以将月份编号转换为名称。这意味着我们必须在给它之前的月份减去 1,
gmtime
并在取回它时加上 1timegm
。 - 年份是自 1900 年以来的年数。这意味着我们必须在将 1900 给 给 之前减去 1900,
gmtime
从 取回时加上 1900timegm
。
而且,现在的程序:
#! /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;
我建议你使用模块DateTime
和一个分机作为格式。您还可以查看模块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;
这是一个简单的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;
这会吗?
use Date::Parse;
use POSIX;
my $s1 = "20120704";
my $t = str2time($s1) - 86400;
my $s2 = strftime "%Y%m%d", localtime $t;
print "$s2\n";
如果您关心这些,请注意 vs 和闰秒localtime
。gmtime