Я получаю даты в формате% dd.% Mm.% YYYY, и я пытаюсь вычитать один месяц, используя Perl.perl вычесть один месяц с даты
примеры: 12.07.2013 -> 12.06.2013, 30.09.2013 -> 31.08.2013
Должен ли я использовать Дата :: Calc? Есть идеи?
Благодаря
Я получаю даты в формате% dd.% Mm.% YYYY, и я пытаюсь вычитать один месяц, используя Perl.perl вычесть один месяц с даты
примеры: 12.07.2013 -> 12.06.2013, 30.09.2013 -> 31.08.2013
Должен ли я использовать Дата :: Calc? Есть идеи?
Благодаря
Вы можете использовать Time::Piece
, который является основным модулем, так как Perl v5.9.5.
use strict;
use warnings;
use Time::Piece;
use Time::Seconds;
my $t = Time::Piece->strptime(shift, "%d.%m.%Y");
$t -= ONE_MONTH;
print $t->strftime("%d.%m.%Y");
Учитывая аргументы 12.07.2013
и 30.09.2013
этот код печатает 11.06.2013
и 30.08.2013
соответственно.
Функция strptime
анализирует строку в соответствии с шаблоном в объекте Time::Piece
. Затем мы можем просто добавить/вычесть объект, чтобы манипулировать датой. Здесь я использую константу из модуля Time::Seconds
, соответствующего одному месяцу.
Это все взято из документации для Time::Piece
.
'12.07.2013' минус' ONE_MONTH' равен 11.06.2013' этим способом. Очевидно, что многое зависит от определения OP * месяца *, но я ожидал бы от примеров до сих пор, мы говорим о расчетах календарного месяца, а не о фиксированном количестве дней (или секунд). –
'Time :: Piece' имеет метод' add_months', который дает здесь 12.06.2013 (при использовании с '-1' в качестве аргумента). Тем не менее, все еще интересно, что ожидает OP, если «невозможными» датами станут результаты операции, например. 30.02.2013. –
@SlavenRezic 'add_months', похоже, ничего не делает, он просто производит ту же дату. Возможно, это небольшая нерегулярная функция в модуле. – TLP
DateTime поддерживает привязку к концу месяца, которую вы ищете. Опция end_of_month
задокументирована в разделе Adding a Duration to a Datetime. Я также предоставил решение для Date::Calc, которое показывает логику. Результат для обоих решений одинаковый.
use DateTime;
my @dates = qw(
01.01.2013
28.02.2013
12.07.2013
30.09.2013
);
foreach my $string (@dates) {
my %p; @p{qw(day month year)} = split /\./, $string;
my $dt = DateTime->new(%p);
for my $n (-1, 1) {
my $res = $dt->clone->add(months => $n, end_of_month => 'preserve');
printf "%s %+d month => %s\n", $string, $n, $res->strftime('%d.%m.%Y');
}
}
use Date::Calc qw[Days_in_Month Decode_Date_EU];
my @dates = qw(
01.01.2013
28.02.2013
12.07.2013
30.09.2013
);
sub Add_Months {
@_ == 4 || die q/Usage: Add_Months($year, $month, $day, $delta)/;
my ($y, $m, $d, $delta) = @_;
my $ultimo = ($d == Days_in_Month($y, $m));
use integer;
$m += $delta;
$y += $m/12;
$m %= 12;
if ($m < 1) {
$y--, $m += 12;
}
my $dim = Days_in_Month($y, $m);
if ($d > $dim || $ultimo) {
$d = $dim;
}
return ($y, $m, $d);
}
foreach my $string (@dates) {
for my $n (-1, 1) {
printf "%s %+d month => %.2d.%.2d.%.4d\n",
$string, $n, reverse(Add_Months(Decode_Date_EU($string), $n));
}
}
Выход:
01.01.2013 -1 month => 01.12.2012
01.01.2013 +1 month => 01.02.2013
28.02.2013 -1 month => 31.01.2013
28.02.2013 +1 month => 31.03.2013
12.07.2013 -1 month => 12.06.2013
12.07.2013 +1 month => 12.08.2013
30.09.2013 -1 month => 31.08.2013
30.09.2013 +1 month => 31.10.2013
Вычитая один месяц с 30 сентября и с 31 Август будет * необычным * для родового «отнимать один месяц» (хотя обратный сценарий, начинающийся месяц с 31 июля и заканчивающийся 30 июня, будет считаться нормальным). Вы уверены, что это то, что нужно? Пожалуйста, поставьте еще несколько примеров и любой код Perl, который вы уже пробовали. –