Подтвердить что ты не робот

Как конвертировать дату/время в эпоху (ака unix time - секунды с 1970 года) в Perl?

Учитывая дату/время в виде массива (год, месяц, день, час, минута, секунда), как бы вы преобразовали его в эпоху, т.е. количество секунд с 1970-01-01 00:00: 00 GMT?

Бонусный вопрос: если задана дата/время в виде строки, как бы вы сначала проанализировали ее в массиве (y, m, d, h, m, s)?

4b9b3361

Ответ 1

Это самый простой способ получить unix-время:

use Time::Local;
timelocal($second,$minute,$hour,$day,$month-1,$year);

Обратите внимание на обратный порядок аргументов, а январь - на месяц 0. Для многих других опций см. Модуль DateTime из CPAN.

Что касается разбора, см. модуль Date::Parse от CPAN. Если вам действительно нужно получить представление о синтаксисе даты, может оказаться полезным Date::Manip, хотя его собственная документация предупреждает вас об этом, поскольку она переносит много багажа (например, он знает такие вещи, как обычные деловые праздники), а другие решения намного быстрее.

Если вам что-то известно о формате даты/времени, который вы будете разбирать, тогда может быть достаточно простого регулярного выражения, но вам, вероятно, лучше использовать соответствующий модуль CPAN. Например, если вы знаете, что даты всегда будут в заказе YMDHMS, используйте модуль CPAN DateTime::Format::ISO8601.


Для моей справки, если ничего более, ниже - это функция, которую я использую для приложения, где я знаю, что даты всегда будут в заказе YMDHMS со всей частью или частью части HMS. Он принимает любые разделители (например, "2009-02-15" или "2009.02.15" ). Он возвращает соответствующее время unix (секунды с 1970-01-01 00:00:00 по Гринвичу) или -1, если он не смог разобрать его (это означает, что вам лучше быть уверенным, что вам никогда не придется законно анализировать дату 1969 года - 12-31 23:59:59). Он также предполагает двузначные годы XX до "69", см. "20XX", в противном случае "19XX" (например, "50-02-15" означает 2050-02-15, но "75-02-15" означает 1975- 02-15).

use Time::Local;

sub parsedate { 
  my($s) = @_;
  my($year, $month, $day, $hour, $minute, $second);

  if($s =~ m{^\s*(\d{1,4})\W*0*(\d{1,2})\W*0*(\d{1,2})\W*0*
                 (\d{0,2})\W*0*(\d{0,2})\W*0*(\d{0,2})}x) {
    $year = $1;  $month = $2;   $day = $3;
    $hour = $4;  $minute = $5;  $second = $6;
    $hour |= 0;  $minute |= 0;  $second |= 0;  # defaults.
    $year = ($year<100 ? ($year<70 ? 2000+$year : 1900+$year) : $year);
    return timelocal($second,$minute,$hour,$day,$month-1,$year);  
  }
  return -1;
}

Ответ 2

Если вы используете модуль DateTime, вы можете вызвать epoch() в объекте DateTime, так как это то, что вы считаете временем unix.

Использование DateTimes позволяет вам легко конвертировать из объектов эпохи, на сегодняшний день.

Альтернативно, localtime и gmtime преобразует эпоху в массив, содержащий день месяца и год, а timelocal и timegm из Time:: Local module будет делать обратное, преобразуя массив элементов времени (секунды, минуты,..., дни, месяцы и т.д.), в эпоху.

Ответ 3

Чтобы проанализировать дату, просмотрите Date::Parse в CPAN.

Ответ 4

$ENV{TZ}="GMT";
POSIX::tzset();
$time = POSIX::mktime($s,$m,$h,$d,$mo-1,$y-1900);

Ответ 5

Получить Date:: Manip из CPAN, затем:

use Date::Manip;
$string = '18-Sep-2008 20:09'; # or a wide range of other date formats
$unix_time = UnixDate( ParseDate($string), "%s" );

изменить:

Дата:: Манип большой и медленный, но очень гибкий в разборе, и это чистый perl. Используйте его, если вы спешите, когда пишете код, и вы знаете, что не спешите, когда вы его запустите.

например. Используйте его для разбора параметров командной строки один раз при запуске, но не используйте его для синтаксического анализа больших объемов данных на занятом веб-сервере.

См. комментарии авторов.

(Спасибо автору первого комментария ниже)

Ответ 6

Я знаю, что это старый вопрос, но я подумал, что дам еще один ответ.

Time::Piece - это ядро ​​с Perl 5.9.5

Это позволяет анализировать время в произвольных форматах с помощью метода strptime.

например:.

my $t = Time::Piece->strptime("Sunday 3rd Nov, 1943",
                              "%A %drd %b, %Y");

Полезная часть - потому что это перегруженный объект, вы можете использовать его для числовых сравнений.

например.

if ( $t < time() ) { #do something }

Или если вы получите доступ к нему в контексте строки:

print $t,"\n"; 

Вы получаете:

Wed Nov  3 00:00:00 1943

Там есть куча методов доступа, которые позволяют использовать некоторые другие полезные преобразования, основанные на времени. https://metacpan.org/pod/Time::Piece

Ответ 7

Мой любимый парсер datetime DateTime::Format::ISO8601 Как только у вас это получится, у вас будет объект DateTime, который легко конвертируется в epoch секунд с epoch()

Ответ 8

Возможно, один из лучших примеров "Больше, чем один способ сделать это", с помощью или без помощи CPAN.

Если у вас есть контроль над тем, что вы получили в качестве "даты/времени", я бы предложил перейти на DateTime маршрут, либо используя определенный подкласс Date:: Time:: Format, либо используя DateTime:: Format:: Strptime, если нет поддержки вашего дурацкого формата даты (см. часто задаваемые вопросы). В общем, Date:: Time - это путь, если вы хотите сделать что-то серьезное с результатом: несколько классов на CPAN довольно анально-ретентивные и одержимо точные.

Если вы ожидаете weird freeform stuff, бросьте его в Date:: Parse метод str2time(), который даст вам секунд-после-эпохи, вы можете иметь свой злой способ, без накладных расходов Date::Manip.

Ответ 9

В CPAN имеется много модулей обработки данных. Моим любимым является DateTime, и вы можете использовать strptime modules, чтобы анализировать даты в произвольных форматах. Также есть много модулей DateTime:: Format в CPAN для обработки специализированных форматов дат, но strptime является наиболее общим.

Ответ 10

Для дополнительной справки - один вкладыш, который может быть применен, например, в сценариях !#/bin/sh.

EPOCH="`perl -e 'use Time::Local; print timelocal('${SEC}','${MIN}','${HOUR}','${DAY}','${MONTH}','${YEAR}'),\"\n\";'`"

Не забывайте избегать восьмеричных значений!

Ответ 11

Фильтр, преобразующий любые даты в различных форматах, связанных с ISO (и кто будет использовать что-либо еще после чтения писем Могучего Куна?) на стандартном входе в секундах, так как время на стандартном выходе может служить для иллюстрации обеих частей:

[email protected]:~$ cat `which isoToEpoch`
#!/usr/bin/perl -w
use strict;
use Time::Piece;
# sudo apt-get install libtime-piece-perl
while (<>) {
  # date --iso=s:
  # 2007-02-15T18:25:42-0800
  # Other matched formats:
  # 2007-02-15 13:50:29 (UTC-0800)
  # 2007-02-15 13:50:29 (UTC-08:00)
  s/(\d{4}-\d{2}-\d{2}([T ])\d{2}:\d{2}:\d{2})(?:\.\d+)? ?(?:\(UTC)?([+\-]\d{2})?:?00\)?/Time::Piece->strptime ($1, "%Y-%m-%d$2%H:%M:%S")->epoch - (defined ($3) ? $3 * 3600 : 0)/eg;
  print;
}
[email protected]:~$ 

Ответ 12

Если вы просто ищете утилиту командной строки (т.е. не то, что вызывается из других функций), попробуйте этот script. Он предполагает существование даты GNU (присутствует практически в любой системе Linux):

#! /usr/bin/perl -w

use strict;

$_ = (join ' ', @ARGV);
$_ ||= <STDIN>;

chomp;

if (/^[\d.]+$/) {
    print scalar localtime $_;
    print "\n";
}
else {
    exec "date -d '$_' +%s";
}

Вот как это работает:

$ Time now
1221763842

$ Time yesterday
1221677444

$ Time 1221677444
Wed Sep 17 11:50:44 2008

$ Time '12:30pm jan 4 1987'
536790600

$ Time '9am 8 weeks ago'
1216915200