Как получить вчерашнюю дату, используя местное время?

Как мне настроить это, чтобы получить вчерашнюю дату, используя местное время?

use strict;

sub spGetCurrentDateTime;
print spGetCurrentDateTime;

sub spGetCurrentDateTime {
my ($sec, $min, $hour, $mday, $mon, $year) = localtime();
my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my $currentDateTime = sprintf "%s %02d %4d", $abbr[$mon], $mday, $year+1900; #Returns => 'Aug 17 2010' 
return $currentDateTime;
}

~


person jdamae    schedule 17.08.2010    source источник


Ответы (7)


Проблему летнего времени можно обойти, взяв 3600 с полудня сегодняшнего дня вместо текущего времени:

#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;

sub spGetYesterdaysDate;
print spGetYesterdaysDate;

sub spGetYesterdaysDate {
my ($sec, $min, $hour, $mday, $mon, $year) = localtime();
my $yesterday_midday=timelocal(0,0,12,$mday,$mon,$year) - 24*60*60;
($sec, $min, $hour, $mday, $mon, $year) = localtime($yesterday_midday);
my @abbr = qw( Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec );
my $YesterdaysDate = sprintf "%s %02d %4d", $abbr[$mon], $mday, $year+1900;
return $YesterdaysDate;
}

В свете «неуказанного» задокументированного поведения решения strftime, предложенного Часом, этот подход может быть лучше, если вы не можете протестировать ожидаемые, но не гарантированные результаты на нескольких платформах.

person bigiain    schedule 18.08.2010

use DateTime qw();
DateTime->now->subtract(days => 1); 

Выражение во второй строке возвращает объект DateTime.

person daxim    schedule 17.08.2010
comment
Это работает, я только что проверил. Возможно, вы просто забыли установить атрибут time_zone в конструкторе или забыли вызвать set_time_zone метод? Возможно, у вас устаревшая версия дистрибутива DateTime::TimeZone? - person daxim; 16.10.2012

Как бы ни было заманчиво просто вычесть дневные секунды из текущего времени, бывают случаи, когда это даст неверный ответ (високосные секунды, летнее время и, возможно, другие). Мне проще просто позволить strftime (доступен в базовом модуле Perl 5 POSIX) выполнять заботиться обо всем этом для меня.

#!/usr/bin/perl

use strict;
use warnings;

use Time::Local;
use POSIX qw/strftime/;

#2010-03-15 02:00:00
my ($s, $min, $h, $d, $m, $y) = (0, 0, 0, 15, 2, 110);

my $time      = timelocal $s, $min, $h, $d, $m, $y;    
my $today     = strftime "%Y-%m-%d %T", localtime $time;
my $yesterday = strftime "%Y-%m-%d %T", $s, $min, $h, $d - 1, $m, $y;
my $oops      = strftime "%Y-%m-%d %T", localtime $time - 24*60*60;
print "$today -> $yesterday -> $oops\n";
person Chas. Owens    schedule 17.08.2010
comment
Таким образом, если значение «день» меньше 1, strftime отсчитывает день назад + 1 день в предыдущем месяце (и, возможно, в год). Является ли это поведение задокументированной частью POSIX или зависит от платформы? - person Grant McLean; 18.08.2010
comment
@Grant Mclean Это может быть нестандартно для POSIX (или SUS), но стандартно для Perl 5. В документации указано arguments are made consistent as though by calling "mktime()" before calling your system's "strftime()". - person Chas. Owens; 19.08.2010
comment
Вкратце: perl -MPOSIX -le '@t=localtime;--$t[3];print strftime "%Y%m%d",@t' - person theglauber; 22.08.2013
comment
Это единственное правильное решение, о котором я знаю сейчас, которое использует только стандартные (основные) модули. - person theglauber; 22.08.2013

используйте Time::Piece.

use strict;
use warnings;
use 5.010;

# These are core modules in Perl 5.10 and newer
use Time::Piece;
use Time::Seconds;

my $yesterday = localtime() - ONE_DAY;
say $yesterday->strftime('%b %d %Y');

Обратите внимание, что это может пойти не так в некоторых пограничных случаях, таких как переход на летнее время. Следующая версия ведет себя правильно в таких случаях:

use strict;
use warnings;
use 5.010;

# These are core modules in Perl 5.10 and newer
use Time::Piece;
use Time::Seconds;

my $now = localtime();
my $yesterday = $now - ONE_HOUR*($now->hour + 12);
say $yesterday->strftime('%b %d %Y');

В качестве альтернативы вы можете использовать модуль DateTime, как описано в другом ответе. Однако это не основной модуль.

person mscha    schedule 17.08.2010
comment
Та же проблема перехода на летнее время скрывается за причудливым API. - person daxim; 18.08.2010
comment
Хороший вопрос, даксим. Я добавил версию, в которой нет этой проблемы. - person mscha; 18.08.2010
comment
Time::Piece и Time::Seconds не добавлялись в ядро ​​до Perl 5.10 (ну, 5.9.5, но кто использует версии для разработчиков?). - person Chas. Owens; 19.08.2010

Решение, предложенное большинством пользователей, неверно!

localtime(time() - 24*60*60)

Худшее, что вы можете сделать, это предположить, что 1 день = 86400 секунд.

Пример: часовой пояс — America/New_York, дата — понедельник, 3 апреля, 00:30:00 2006 г.

timelocal дает нам 1144038600

местное время (1144038600 - 86400) = суббота, 1 апреля, 23:30:00 по восточному поясному времени 2006 г.

ой!

Правильное и единственное решение — позволить системной функции нормализовать значения.

$prev_day = timelocal(0, 0, 0, $mday-1, $mon, $year);

Или пусть фреймворки datetime (DateTime, Class::Date, etc) сделают то же самое.

Вот и все.

person Pronin Oleg    schedule 18.12.2013

person    schedule
comment
Существует пограничный случай вокруг летнего времени. Я не советую этот метод, если вам нужно, чтобы он работал все время. - person Chas. Owens; 18.08.2010
comment
Крайний случай DST можно обойти, см. пример кода в другом ответе. - person bigiain; 18.08.2010

person    schedule
comment
Это может привести к сбою в начале летнего времени по причинам, объясненным в других ответах. - person nobody; 02.07.2014