Быстро добраться до ГГГГ-мм-дд ЧЧ: ММ: СС в Перл
При написании скриптов Perl я часто нахожу необходимость получить текущее время, представленное в виде строки, отформатированной как YYYY-mm-dd HH:MM:SS
(скажем 2009-11-29 14:28:29
).
При этом я нахожу себя в этом довольно громоздком пути:
-
man perlfunc
-
/localtime
для поиска по местному времени - повторите пять раз (/
+ \n
), чтобы перейти к соответствующему разделу manpage
- Скопируйте строку
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
с man-страницы на мой script.
- Попробуйте
my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year, $mon, $mday, $hour, $min, $sec);
- Помните, что gotcha # 1: нужно добавить от 1900 до $года, чтобы получить текущий год.
- Попробуйте
my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon, $mday, $hour, $min, $sec);
- Помните, что gotcha # 2: нужно добавить от 1 до $mon, чтобы получить текущий месяц.
- Попробуйте
my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
- Кажется, все в порядке. Готово!
В то время как описанный выше процесс работает, он далеко не оптимален. Я уверен, что есть более умный способ, поэтому мой вопрос просто:
Каков самый простой способ получить YYYY-mm-dd HH:MM:SS
текущей даты/времени в Perl?
Где "легко" охватывает как "легко записываемые", так и "легко запоминаемые".
Ответы
Ответ 1
Используйте strftime
в стандартном модуле POSIX
. Аргументы strftime
в привязке Perls были разработаны для выравнивания с возвращаемыми значениями из localtime
и gmtime
. сравнить
strftime(fmt, sec, min, hour, mday, mon, year, wday = -1, yday = -1, isdst = -1)
с
my ($sec,$min,$hour,$mday,$mon,$year,$wday, $yday, $isdst) = gmtime(time);
Пример использования командной строки
$ perl -MPOSIX -le 'print strftime "%F %T", localtime $^T'
или из исходного файла, как в
use POSIX;
print strftime "%F %T", localtime time;
Некоторые системы не поддерживают сокращения %F
и %T
, поэтому вам придется явно указать
print strftime "%Y-%m-%d %H:%M:%S", localtime time;
или же
print strftime "%Y-%m-%d %H:%M:%S", gmtime time;
Обратите внимание, что time
возвращает текущее время при вызове, тогда как $^T
фиксируется во время запуска вашей программы. С gmtime
возвращаемое значение является текущим временем в GMT. Получить время в вашей временной зоне с localtime
.
Ответ 2
Что не использует модуль DateTime
для выполнения грязной работы? Легко писать и запоминать!
use strict;
use warnings;
use DateTime;
my $dt = DateTime->now; # Stores current date and time as datetime object
my $date = $dt->ymd; # Retrieves date as a string in 'yyyy-mm-dd' format
my $time = $dt->hms; # Retrieves time as a string in 'hh:mm:ss' format
my $wanted = "$date $time"; # creates 'yyyy-mm-dd hh:mm:ss' string
print $wanted;
Как только вы знаете, что происходит, вы можете избавиться от темпов и сохранить несколько строк кода:
use strict;
use warnings;
use DateTime;
my $dt = DateTime->now;
print join ' ', $dt->ymd, $dt->hms;
Ответ 3
Попробуйте следующее:
use POSIX qw/strftime/;
print strftime('%Y-%m-%d',localtime);
Метод strftime
делает работу эффективно для меня. Очень простой и эффективный.
Ответ 4
Time:: Piece (в ядре, так как Perl 5.10) также имеет функцию strftime и по умолчанию перегружает localtime и gmtime для возврата объектов Time:: Piece:
use Time::Piece;
print localtime->strftime('%Y-%m-%d');
или без переопределенного локального времени:
use Time::Piece ();
print Time::Piece::localtime->strftime('%F %T');
Ответ 5
Я сделал небольшой тест (Perl v5.20.1 под FreeBSD в VM), вызывающий следующие блоки: 1.000.000 раз каждый:
А
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $now = sprintf("%04d-%02d-%02d %02d:%02d:%02d", $year+1900, $mon+1, $mday, $hour, $min, $sec);
В
my $now = strftime('%Y%m%d%H%M%S',localtime);
С
my $now = Time::Piece::localtime->strftime('%Y%m%d%H%M%S');
со следующими результатами:
A: 2 секунды
B: 11 секунд
C: 19 секунд
Это, конечно, не тщательный тест или бенчмарк, но, по крайней мере, он воспроизводится для меня, поэтому, хотя это сложнее, я бы предпочел первый метод, если генерация datetimestamp требуется очень часто.
Вызов (например, под FreeBSD 10.1)
my $now = `date "+%Y%m%d%H%M%S" | tr -d "\n"`;
может не быть такой хорошей идеей, потому что она не зависит от ОС и занимает довольно много времени.
С уважением,
Хольгер
Ответ 6
Time::Piece::datetime()
может устранить T
.
use Time::Piece;
print localtime->datetime(T => q{ });
Ответ 7
если вы просто хотите, чтобы человекочитаемая строка времени, а не точный формат:
$t = localtime;
print "$t\n";
печатает
Mon Apr 27 10:16:19 2015
или все, что настроено для вашей локали.
Ответ 8
Короткий и сладкий, никаких дополнительных модулей не требуется:
my $toDate = `date +%m/%d/%Y" "%l:%M:%S" "%p`;
Результат, например, будет: 25.04.2012 9:30:33 AM
Ответ 9
Во многих случаях необходимое "текущее время" - это скорее $ ^ T, то есть время, в которое скрипт начал работать, в целых секундах (при условии, что только 60 секунд), начиная с эпохи UNIX.
Это предотвращает использование в ранней части сценария другой даты (или статуса перехода на летнее время), чем в более поздней части сценария, например, в условиях запроса и других производных значениях.
Для этого варианта "текущего времени" можно использовать константу, а также документировать, что она была заморожена во время компиляции: use constant YMD_HMS_AT_START => POSIX::strftime( "%F %T", localtime $^T );
Альтернативное время запуска с более высоким разрешением: 0+ [ Time::HiRes::stat("/proc/$$") ]->[10]