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

StackOverflow https://stackoverflow.com/questions/95492

Вопрос

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

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

Это было полезно?

Решение 2

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

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

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

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

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


Для моей собственной справки, если ничего другого нет, ниже приведена функция, которую я использую для приложения, где я знаю, что даты всегда будут в порядке YMDHMS со всей или частью необязательной части "HMS".Он принимает любые разделители (например, "2009-02-15" или "2009.02.15").Он возвращает соответствующее время unix (секунды с 1970-01-01 00:00:00 GMT) или -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;
}

Другие советы

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

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

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

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

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

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

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

Получить дату::Манипуляция из CPAN, тогда:

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

Редактировать:

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

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

Видишь комментарии авторов.

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

Мой любимый анализатор даты и времени Дата-время::Формат:: ISO8601 Как только у вас это заработает, у вас будет объект DateTime, который можно легко преобразовать в секунды эпохи с помощью epoch()

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

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

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

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

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

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

Если вы ожидаете странных вещей свободной формы, бросьте их в Дата::Разобратьметод str2time(), который выдаст вам значение с момента начала эпохи, с которым вы затем можете поступать по-своему, без накладных расходов на Дата::Манипуляция.

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

martind@whitewater:~$ 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;
}
martind@whitewater:~$ 

Если вы просто ищете утилиту командной строки (т. Е. не то, что будет вызываться из других функций), попробуйте этот скрипт.Это предполагает существование GNU date (присутствует практически в любой системе 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top