Формат с 00
для отсутствующего дня / месяца хорошо определен, но он кодирует особые случаи, которые не соответствуют формату yyyymmdd
.Я не вижу, как может быть подход, который избегает явных тестов для этих особых случаев, когда день / месяц просто пропущен.
Я хотел бы предложить не выбирать дату и время с помощью регулярного выражения, так как для этой работы есть хорошие модули.Даже если этот пример прост, как указано, рабочие места имеют тенденцию развиваться;Кроме того, нет ничего плохого в использовании хорошего инструмента даже в простом случае.
Использование модуля ядра Time :: Piece
use warnings;
use strict;
use feature 'say';
use Time::Piece;
my $d = shift || '20180712';
my $date = fmt_date($d);
say $date;
sub fmt_date {
my ($date) = @_;
my ($yr, $mm, $dd) = grep { $_ != 0 } unpack "A4A2A2", $date;
my $d_fmt;
if ($yr and $mm and $dd) {
$d_fmt = Time::Piece
->strptime($date, "%Y%m%d")
->strftime("%d %B %Y");
}
elsif (not $dd and $mm) {
$d_fmt = Time::Piece
->strptime($yr.$mm.'01', "%Y%m%d")
->strftime("%B %Y");
}
elsif (not $mm) {
$d_fmt = $yr
}
return $d_fmt;
}
Я фильтрую списоквозвращается распаковать , чтобы не иметь дело с 00
строк ;таким образом, соответствующие переменные будут undef
, что можно проверить более просто.
strptime
возвращает объект Time::Piece
, для которого напрямую вызывается метод strftime
, возвращая строку вжелаемый формат.Если с этими датами есть больше работы, вы, конечно, можете сохранить объект в переменной, затем сформировать строку из нее и вернуть оба.
Но возникает вопрос дизайна: какой это будет дата, когда день / понедельник не указан?При работе с датами решение часто заключается в том, чтобы установить их на 01
, и тогда приложение может использовать только ту часть, которую оно хочет. †
Это можно сделать более компактной и, возможно, "более приятной"."но я бы посоветовал не беспокоиться об элегантности, когда вы должны выбрать список тестов.
Другой, более крупный и гораздо более округлый вариант для обработки даты и времени - это DateTime module.
† Например,
sub fmt_date {
my ($date) = @_;
my ($yr, $mm, $dd) = grep { $_ != 0 } unpack "A4A2A2", $date;
my $dt_obj = Time::Piece->strptime(
$yr . ($mm // '01') . ($dd // '01'), "%Y%m%d" # legit format
);
my $d_fmt = do {
if ($yr and $mm and $dd) { $dt_obj->strftime("%d %B %Y") }
elsif (not $dd and $mm) { $dt_obj->strftime("%B %Y") }
elsif (not $mm) { $dt_obj->strftime("%Y") } # or, $yr
};
return wantarray ? ($d_fmt, $dt_obj) : $d_fmt;
}
, где wantarray знает вызывающий context , и поэтому это можеттеперь может называться либо
my ($date, $obj) = fmt_date($d);
, либо
my $date = fmt_date($d);
в зависимости от того, хочет ли вызывающий объект для дальнейшей работы или нет.