2011-06-07 59 views

回答

24

我假设如果给定的日期是星期一,你想要相同的日期(而不是前一个星期一)。下面是与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,并认为国防部7是无糖。OP但随着% 7,它适用于任何所需日的一周,而不仅仅是星期一)

如果你确实想在上周一,你可以改变减法:

$date->subtract(days => ($date->day_of_week - $desired_dow) % 7 || 7); 

如果您需要解析在命令行中输入的日期,则可能需要查看DateTime::Format::Natural

+2

在CPAN上有很多方法可以做到这一点和很多日期/时间模块,但DateTime是迄今为止用于处理日期和时间的最佳模块。 – 2011-06-07 09:42:38

1

Zeller's congruence会给你星期几。从那里它应该很容易。

+1

这是一篇newspost的新闻邮件。原始发布的替代链接,可读性更好:[''](http://groups.google.com/group/comp.lang.perl/msg/dbd4d19f71ec6b9a) – daxim 2011-06-07 08:50:33

+2

@daxim,更不用说在Perl 5中完全没有必要。'(localtime)[6]'是星期几。 – Axeman 2011-06-07 12:50:25

12

你也可以使用Time :: ParseDate,它理解“上周一”。

一个班轮维护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 
    } 

有两点要注意:如果日期是星期一,那么你得到的以前星期一,这可能会或可能不是你想要的,改变现在只需设置到第二天(每天添加60 * 60 * 24,到$ date_epoch)。然后Time :: ParseDate非常自由,例如2011-23-38会很高兴解析(如2012-12-09)。

+1

虽然'DateTime'是一种在Perl中处理日期和时间的规范方法,'Time :: ParseDate'一直是我对这类事情的最爱。 – Grrrr 2011-06-07 08:49:09

+1

我其实很少需要处理日期,这可能是为什么我找到parsedate(“上周一”,NOW => $ date_epoch);可爱,更重要的是,易于记忆。 – mirod 2011-06-07 09:08:27

3

很简单的东西,使用标准的Perl库。

#!/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,它可能会更简单。

3

本着Perl的精神,有很多方法可以做到这一点。

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; 
2

你可以使用Date::Manip,其中有一个Date_GetPrev功能和理解 “星期一”

$ perl -MDate::Manip -le 'print UnixDate(Date_GetPrev(shift, "Monday", 0), "%Y-%m-%d")' 2011-06-11 
2011-06-06 
1

在本月底,$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。

+0

你对你的偏好进行测试,2011-06-07(星期二)将返回2011-05-30的时间戳。 – 2011-06-07 15:31:51

+0

@ Ven'Tatsu啊,我超过了自己。我测试,发布,然后阅读比较错误,并急匆匆地将其更改为2. – Axeman 2011-06-07 15:36:57

0

如果你是一个像我这样的奴隶,并且必须使用没有库的公司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"; 

希望它可以帮助别人

+0

这不涉及闰秒,http://en.wikipedia.org/wiki/Leap_second – Toto 2014-02-13 16:32:29

+0

你是对的,但它闰秒不重要的许多用途:相信我,没有被允许添加库是地狱,它可以让你的代码成为可笑地增长,你只要找到一个足够好的快速解决方案必需的任务:) – Cristina 2014-05-09 08:17:08

0

有很多方法可以做到这一点在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 
相关问题