У меня есть следующий цикл, чтобы вычислить даты текущей недели и распечатать их. Это работает, но я плаваю в сумме возможностей даты/времени в Perl и хочу надеть Ваше мнение, существует ли лучший путь. Вот код, который я написал:
#!/usr/bin/env perl
use warnings;
use strict;
use DateTime;
# Calculate numeric value of today and the
# target day (Monday = 1, Sunday = 7); the
# target, in this case, is Monday, since that's
# when I want the week to start
my $today_dt = DateTime->now;
my $today = $today_dt->day_of_week;
my $target = 1;
# Create DateTime copies to act as the "bookends"
# for the date range
my ($start, $end) = ($today_dt->clone(), $today_dt->clone());
if ($today == $target)
{
# If today is the target, "start" is already set;
# we simply need to set the end date
$end->add( days => 6 );
}
else
{
# Otherwise, we calculate the Monday preceeding today
# and the Sunday following today
my $delta = ($target - $today + 7) % 7;
$start->add( days => $delta - 7 );
$end->add( days => $delta - 1 );
}
# I clone the DateTime object again because, for some reason,
# I'm wary of using $start directly...
my $cur_date = $start->clone();
while ($cur_date <= $end)
{
my $date_ymd = $cur_date->ymd;
print "$date_ymd\n";
$cur_date->add( days => 1 );
}
Как упомянуто, это работает, но действительно ли это является самым быстрым или самым эффективным? Я предполагаю, что быстрота и эффективность не могут обязательно сочетаться, но Ваша обратная связь очень ценится.
Немного улучшенная версия ответа friedo ...
my $start_of_week =
DateTime->today()
->truncate( to => 'week' );
for ( 0..6 ) {
print $start_of_week->clone()->add( days => $_ );
}
Однако здесь предполагается, что понедельник - первый день недели. В воскресенье начните с ...
my $start_of_week =
DateTime->today()
->truncate( to => 'week' )
->subtract( days => 1 );
В любом случае лучше использовать метод truncate
, чем реализовывать его заново, как это сделал Фридо;)
Будет ли это работать:
use strict;
use warnings;
use POSIX qw<strftime>;
my ( $day, $pmon, $pyear, $wday ) = ( localtime )[3..6];
$day -= $wday - 1; # Get monday
for my $d ( map { $day + $_ } 0..6 ) {
print strftime( '%A, %B %d, %Y', ( 0 ) x 3, $d, $pmon, $pyear ), "\n";
}
Я печатаю их только в качестве иллюстрации. Вы можете сохранить их как временные метки, например:
use POSIX qw<mktime>;
my @week = map { mktime(( 0 ) x 3, $day + $_, $pmon, $pyear ) } 0..6;
Вы можете использовать объект DateTime, чтобы получить текущий день недели в виде числа (1-7). Тогда просто используйте это, чтобы найти понедельник текущей недели. Например:
my $today = DateTime->now;
my $start = $today->clone;
# move $start to Monday
$start->subtract( days => ( $today->wday - 1 ) ); # Monday gives 1, so on monday we
# subtract zero.
my $end = $start->clone->add( days => 7 );
Вышеупомянутое не проверено, но идея должна работать.
Это должно сработать:
use POSIX; # for strftime
my $time = time ();
my $seconds = 24*60*60;
my @time = gmtime ();
$time = $time - $time[6] * $seconds;
for my $wday (0..6) {
$time += $seconds;
my @wday = gmtime ($time);
print strftime ("%A %d %B %Y\n", @wday);
}
Дает мне:
$ ./week.pl Monday 24 May 2010 Tuesday 25 May 2010 Wednesday 26 May 2010 Thursday 27 May 2010 Friday 28 May 2010 Saturday 29 May 2010 Sunday 30 May 2010
Если вы хотите, чтобы недели начинались с воскресенья, измените $ time [6]
на ($ time [6] + 1)
.
Предполагается, что вам нужны недели по Гринвичу. Измените gmtime
на localtime
, чтобы получить недели местного часового пояса.