我正在寻找一个Perl脚本,它可以为任何指定的日期提供上一个星期一。
例如,对于日期2011-06-11,该脚本应返回2011-06-06。
我假设如果给定的日期是周一,你想要相同的日期(而不是上个周一)。以下是使用DateTime的一种方法:
use DateTime;
my $date = DateTime->new(year => 2011, month => 6, day => 11);
my $desired_dow = 1; # Monday
$date->subtract(days => ($date->day_of_week - $desired_dow) % 7);
print "$date\n";
实际上,对于星期一这个特殊情况,% 7
并不是必要的,因为$date->day_of_week - 1
始终为0-6,并且mod 7没有任何操作。但是使用% 7
,它适用于任何所需的星期几,而不仅仅是星期一。
如果您想要前一个星期一,可以更改减法:
$date->subtract(days => ($date->day_of_week - $desired_dow) % 7 || 7);
你还可以使用 Time::ParseDate,它能够理解“last Monday”这样的时间表达。
一个用于维护 Perl 声誉的单行代码:
perl -MTime::ParseDate -M'POSIX qw(strftime)' -l -e'foreach (@ARGV) { my $now= parsedate( $_); my $e= parsedate( "last Monday", NOW => $now) ; print "$_ : ", strftime "%F", localtime( $e)}' 2011-06-11 2011-06-12 2011-06-13 2011-06-14
以下是一个健全的脚本:
#!/usr/bin/perl
use strict;
use warnings;
use Time::ParseDate; # to parse dates
use POSIX qw(strftime); # to format dates
foreach my $date (@ARGV)
{ my $date_epoch= parsedate( $date) || die"'cannot parse date '$date'\n";
my $monday= parsedate( "last Monday", NOW => $date_epoch); # last Monday before NOW
print "Monday before $date: ", strftime( "%F", localtime( $monday)), "\n"; # %F is YYYY-MM-DD
}
需要注意的是:如果日期是星期一,则会得到上一个星期一,这可能不是您想要的,要更改只需将NOW设置为下一天(将60*60*24,即一天,添加到$date_epoch)。然后Time::ParseDate相当宽容,例如它将愉快地解析2011-23-38(作为2012-12-09)。
DateTime
是处理日期和时间的规范方式,但是 Time::ParseDate
一直是我处理这类事情的首选。 - Grrrr#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Time::Local;
use POSIX 'strftime';
my $date = shift || die "No date given\n";
my @date = split /-/, $date;
$date[0] -= 1900;
$date[1]--;
die "Invalid date: $date\n" unless @date == 3;
my $now = timelocal(0, 0, 12, reverse @date);
while (strftime('%u', localtime $now) != 1) {
$now -= 24 * 60 * 60;
}
我会把使用的各种模块和函数留给读者自己练习查找。
如果您使用DateTime,可能会更简单。
use Modern::Perl;
use Date::Calc qw/Day_of_Week/;
my $date = '2011/6/11';
my @fields = split /\//, $date;
my @new_date = Add_Delta_Days( @fields , 1 - Day_of_Week( @fields ) );
say join "/", @new_date;
Date_GetPrev
函数,并且理解“星期一”。$ perl -MDate::Manip -le 'print UnixDate(Date_GetPrev(shift, "Monday", 0), "%Y-%m-%d")' 2011-06-11
2011-06-06
泽勒公式可以帮助你计算出星期几。从那里开始,应该就很容易了。
( localtime )[6]
表示的是一周中的星期几。 - Axeman$tstamp
将拥有你想要的时间戳。use strict;
use warnings;
use POSIX qw<mktime>;
my $time = '2011-06-11';
my ( $year, $month, $day ) = split /-0?/, $time;
my $tstamp = mktime( 0, 0, 0, $day, $month - 1, $year - 1900 );
my $dow = ( localtime $tstamp )[6];
$tstamp -= (( $dow > 1 ? 0 : 7 ) + $dow - 1 ) * 24 * 60 * 60;
这里假设“上个星期一”是指在给定日期之前最后一次出现的星期一。所以如果给定日期是星期一(1),那么它会再减去7天。
如果你像我一样是个奴隶,必须使用没有库的企业版Perl,而且也不允许安装它们,那就老老实实地按照传统方式操作:
my $datestring = "";
my $secondsEpoc = time(); #gives the seconds from system epoch
my $secondsWantedDate;
my $seconds2substract;
$datestring = localtime($secondsEpoc);
print "Today's date and time ".$datestring."\n";
my ($second,$minute,$hour,$d,$M,$y,$wd,$yd) = (localtime)[0,1,2,3,4,5,6,7];
#print "hour: ".$hour;
#print "minute: ".$minute;
#print "second: ".$second;
#print "week day: ".$wd; #week day is 1=Monday .. 7=Sunday
$seconds2substract = 24 * 60 * 60; # seconds in 24 hours
$secondsWantedDate=$secondsEpoc-$seconds2substract;
$datestring = localtime($secondsWantedDate);
print "Yesterday at the same time ".$datestring."\n";
my $days2Substract = $wd-1;
$seconds2substract = ($days2Substract * 24 * 60 * 60);
$secondsWantedDate=$secondsEpoc-$seconds2substract;
$datestring = localtime($secondsWantedDate);
print "Past Monday same time ".$datestring."\n";
$seconds2substract = ($days2Substract * 24 * 60 * 60) + ($hour *60 *60) + ($minute * 60) + $second;
$secondsWantedDate = $secondsEpoc-$seconds2substract;
$datestring = localtime($secondsWantedDate);
print "Past Monday at 00:00:00 ".$datestring."\n";
有很多种方法可以在Perl中实现。以下是使用Perl库Moment的方法。
#!/usr/bin/perl
use strict;
use warnings FATAL => 'all';
use feature 'say';
use Moment;
sub get_monday_date {
my ($date) = @_;
my $moment = Moment->new( dt => "$date 00:00:00" );
my $weekday_number = $moment->get_weekday_number( first_day => 'monday' );
my $monday = $moment->minus( day => ($weekday_number - 1) );
return $monday->get_d();
}
say get_monday_date('2011-06-11'); # 2011-06-06