Как я могу преобразовать вывод даты Unix через несколько часовых поясов в UTC, в Perl? - PullRequest
5 голосов
/ 12 октября 2010

Как в Perl эффективно анализировать выходные данные команды date unix с учетом часового пояса, а также конвертировать в UTC?

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

# Example Input Strings:
my @inputs = (
              'Tue Oct 12 06:31:48 EDT 2010',
              'Tue Oct 12 07:49:54 BST 2010',
             );

Я попробовал следующее безрезультатно:

foreach my $input ( @inputs ) {
  my $t = Time::Piece->strptime( $input,
                                 '%a %b %d %T %Z %Y' );
  print $t->cdate, "\n";
}

Кажется, проблема в часовом поясе (% Z). Кроме того, в Time :: Piece, похоже, отсутствует поле часового пояса, что потребовало бы от меня написания пользовательского кода для преобразования в UTC, что кажется ... неправильным.

Контекст: Я пытаюсь проанализировать устаревшие журналы из различных источников, которые используют команду даты unix для отметок времени. В идеале я хотел бы преобразовать все временные метки в UTC.

Любая помощь будет принята с благодарностью.

Ответы [ 6 ]

5 голосов
/ 13 октября 2010

Если вы знаете, как устранить неоднозначность TZ, просто вставьте их в таблицу отправки:

use strict; use warnings;
use DateTime::Format::Strptime ();

my @inputs = (
    'Tue Oct 12 06:31:48 EDT 2010',
    'Tue Oct 12 07:49:54 BST 2010',
);

my %tz_dispatch = (
    EDT => build_parser( 'EST5EDT' ),
    BST => build_parser( '+0100' ),
    # ... etc
    default => build_parser( ),
);

for my $input (@inputs) {
    my ($parser, $date) = parse_tz( $input, %tz_dispatch );
    print $parser->parse_datetime( $date ), "\n";
}

sub build_parser {
    my ($tz) = @_;

    my %conf = (
        pattern   => '%a %b %d %T %Z %Y',
        on_error  => 'croak',
    );
    @conf{qw/time_zone pattern/} = ($tz, '%a %b %d %T %Y')
    if $tz;

    return DateTime::Format::Strptime->new( %conf );
}

sub parse_tz {
    my ($date, %tz_dispatch) = @_;
    my (@date) = split /\s/, $date;

    my $parser = $tz_dispatch{splice @date, 4, 1};

    return $parser
    ? ($parser, join ' ', @date)
    : ($tz_dispatch{default}, $date);
}
5 голосов
/ 12 октября 2010

Perl DateTime FAQ на часовых поясах имеет хорошее представление о том, почему EDT и EST нельзя использовать в большинстве преобразований.Проблема в том, что в других странах также есть восточный часовой пояс с такой же трехбуквенной аббревиатурой.EST EDT неоднозначен без других подсказок.

Вы можете посмотреть другие модули или просто предположить, что "EDT" совпадает с "EST5EDT", если это правда.

3 голосов
/ 25 марта 2011

Если вы используете Date :: Time :: Strptime, вы можете использовать %O для имени часового пояса Олсона и выполнить ручную фиксацию перед синтаксическим анализом.

, т.е. если вы знаете что EDT в вашем вводе означает America / New_York, сделайте это:

$time_in =~ s{EDT}{America/New_York};

и вместо

%a %b %d %T %Z %Y

для вашего времениспецификация зоны использования

%a %b %d %T %O %Y

1 голос
/ 14 октября 2010

Я всегда считал, что Date :: Manip :: ParseDate подходит для подобных ситуаций.

use strict;
use warnings qw<FATAL all>;
use Date::Manip qw<ParseDate UnixDate>;

my @inputs = (
    q<Tue Oct 12 06:31:48 EDT 2010>,
    q<Tue Oct 12 07:49:54 BST 2010>,
);

sub date2epoch($) {
    my $user_string = shift();
    my $timestamp   = ParseDate($user_string);
    my $seconds     = UnixDate($timestamp, "%s");
    return $seconds;
}

sub epoch2utc($) {
    my $seconds = shift();
    return gmtime($seconds) . q< UTC>;
}

for my $random_date (@inputs) {
    my $epoch_seconds = date2epoch($random_date);
    my $normal_date   = epoch2utc($epoch_seconds);
    print "$random_date == $normal_date\n";
}

При запуске это выдает:

Tue Oct 12 06:31:48 EDT 2010 == Tue Oct 12 10:31:48 2010 UTC
Tue Oct 12 07:49:54 BST 2010 == Tue Oct 12 06:49:54 2010 UTC

что, кажется, то, что вы ищете.

0 голосов
/ 31 декабря 2012

Я согласен с Джандером по дате команды. -d и -u великолепны и сохраняют много строк кода.

0 голосов
/ 14 октября 2010

Я немного опоздал с этим, но сама GNU date хорошо разбирает даты:

$ date -u -d 'Thu Oct 14 01:17:00 EDT 2010'
Thu Oct 14 05:17:00 UTC 2010

Я не знаю, как это разрешает двусмысленность EDT.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...