Просто использование POSIX::strftime()
имеет проблемы, которые уже были указаны в других ответах и комментариях к ним:
- Он не будет работать с MS-DOS, также называемой Windows, которая генерирует строки типа «Стандартное время Европы» вместо «+0200», как требуется RFC822 для спецификации преобразования
%z
.
- Он напечатает сокращенные названия месяца и дня в текущей локали вместо английского, что опять-таки требуется для RFC822 .
Переключение локали на "POSIX" соотв. «C» решает последнюю проблему, но потенциально дорого, даже больше для хорошо работающего кода, который позже переключается обратно на предыдущую локаль.
Но это также не полностью потокобезопасно. Хотя временное переключение локали будет работать без проблем в потоках интерпретатора Perl, бывают гонки, когда сам интерпретатор Perl запускается внутри потока ядра. Это может быть в случае, когда интерпретатор Perl встроен в сервер (например, mod_perl , работающий в многопоточном Apache MPM).
Следующая версия не имеет таких ограничений, поскольку не использует никаких зависящих от локали функций:
sub rfc822_local {
my ($epoch) = @_;
my @time = localtime $epoch;
use integer;
my $tz_offset = (Time::Local::timegm(@time) - $now) / 60;
my $tz = sprintf('%s%02u%02u',
$tz_offset < 0 ? '-' : '+',
$tz_offset / 60, $tz_offset % 60);
my @month_names = qw(Jan Feb Mar Apr May Jun
Jul Aug Sep Oct Nov Dec);
my @day_names = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
return sprintf('%s, %02u %s %04u %02u:%02u:%02u %s',
$day_names[$time[6]], $time[3], $month_names[$time[4]],
$time[5] + 1900, $time[2], $time[1], $time[0], $tz);
}
Но следует отметить, что преобразование из секунд с эпохи в нерабочее время и наоборот - довольно сложные и дорогостоящие операции, даже больше, когда речь идет не о GMT / UTC, а о местном времени. Последнее требует проверки данных zoneinfo, содержащих текущие и исторические настройки летнего времени и часового пояса для текущего часового пояса. Он также подвержен ошибкам, поскольку эти параметры зависят от политических решений, которые могут быть возвращены в будущем . Из-за этого код, основанный на данных zoneinfo, является хрупким и может сломаться, если система не обновляется регулярно.
Однако цель спецификаций даты и времени, соответствующих RFC822, состоит не в том, чтобы информировать другие серверы о настройках часового пояса «вашего» сервера, а в том, чтобы дать представление о текущей дате и времени независимым от часового пояса способом. Вы можете сохранить много циклов ЦП (их можно измерить в выбросе CO2) как на отправляющей, так и на принимающей стороне, просто используя UTC вместо местного времени:
sub rfc822_gm {
my ($epoch) = @_;
my @time = gmtime $epoch;
my @month_names = qw(Jan Feb Mar Apr May Jun
Jul Aug Sep Oct Nov Dec);
my @day_names = qw(Sun Mon Tue Wed Thu Fri Sat Sun);
return sprintf('%s, %02u %s %04u %02u:%02u:%02u +0000',
$day_names[$time[6]], $time[3], $month_names[$time[4]],
$time[5] + 1900, $time[2], $time[1], $time[0]);
}
Путем жесткого кодирования часового пояса в +0000
вы избегаете всех вышеперечисленных проблем, оставаясь при этом полностью совместимыми со стандартами, оставаясь в покое быстрее. Используйте это решение, когда производительность может быть проблемой для вас. Используйте первое решение, когда ваши пользователи жалуются на то, что программное обеспечение сообщает о «неправильном» часовом поясе.