Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何用Perl将多个时区的unix日期输出转换为UTC?_Perl_Date_Timezone - Fatal编程技术网

如何用Perl将多个时区的unix日期输出转换为UTC?

如何用Perl将多个时区的unix日期输出转换为UTC?,perl,date,timezone,Perl,Date,Timezone,在Perl中,在考虑时区的情况下,如何有效地解析unix的date命令的输出,并将其转换为UTC 我读过许多关于stackoverflow的类似问题,但似乎很少有人考虑解析多个时区。相反,他们似乎手动设置时区,并假设它保持不变 # Example Input Strings: my @inputs = ( 'Tue Oct 12 06:31:48 EDT 2010', 'Tue Oct 12 07:49:54 BST 2010',

在Perl中,在考虑时区的情况下,如何有效地解析unix的date命令的输出,并将其转换为UTC

我读过许多关于stackoverflow的类似问题,但似乎很少有人考虑解析多个时区。相反,他们似乎手动设置时区,并假设它保持不变

# 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 date命令作为时间戳的各种源的遗留日志。理想情况下,我希望将所有时间戳转换为UTC

任何帮助都将不胜感激。

时区上的Perl DateTime有一个很好的背景,说明为什么EDT和EST不能用于大多数转换。问题是其他国家也有一个东部时区,其缩写为3个字母。EST EDT在没有其他线索的情况下模棱两可


如果是真的,您可以查看或假设“EDT”与“EST5EDT”相同。

如果您知道如何消除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);
}

我总是发现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";
}

这似乎正是您想要的。

我在这方面有点晚了,但GNU
date
本身擅长解析日期:

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

不过我不知道它是如何解决EDT的歧义的。

如果您使用的是Date::Time::Strptime,您可以使用
%O
作为奥尔森时区名称,并在解析之前进行手动修复

i、 e.如果您知道您输入的EDT表示美国/纽约,请执行以下操作:

$time\u in=~s{EDT}{美国/纽约}

而不是

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

为您的时区规范使用


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

我同意詹德的日期命令-d和-u非常好,可以节省大量代码行。

这里的基本问题是,3个字母的时区缩写不是唯一的。“EST”的含义取决于您所在的国家。感谢您指出其中的歧义。我可以将我知道的替换为正确的长名称(对于该日志,EST5EDT是正确的)。但是,如果不编写自定义代码提取时区,然后在我选择的模块中手动设置时区(DateTime看起来很不错),我仍然不知道如何捕获时区,希望映射到正确的字符串。在调用strTime之前,我添加了“$input=~s/EDT/EST5EDT/;”,但是strtime仍然无法解析字符串。此外,我仍然认为Time::Piece是不够的,因为它不存储时区,它只“允许”通过格式字符串传递:(非常感谢您指出短时区名称的模糊性!@vlee:您可能需要使用另一个模块。
DateTime::Format::*
组中有许多CPAN模块。DateTime::Format::strtime看起来特别有希望。我很快会尝试,并真的希望它捕获到%Z而不是Time::Piece。谢谢,您的代码绝对正确。)有效。但是,现在我对%Z标识符更困惑了。在您的代码中,为EDT(EST5EDT)和BST(+0100)时区创建了一个新的DateTime::Format::StrTime,而不是使用相同的对象并使用parse_DateTime解析整个字符串。我尝试了使用默认对象的“2010年10月12日星期二08:00:00 GMT”。但是,当我尝试时“UTC”或“EST5EDT”默认对象会发出“我不认识时区”的声音"。我猜这是预期的行为,但我不确定原因。我想知道%Z的可识别/可接受的时区字符串是什么。strtime解析器会获取一个字符串,如果该字符串包含时区,解析器会尝试将其传递到DateTime::timezone。如果该字符串不包含时区,则解析器构造函数需要
时区
参数。我也很难找到合适的、不含糊的时区名称。基本上,任何形式的“[-+]\d{4}”都可以工作。希望这能有所帮助。你知道这些格式在哪里记录的吗?你是如何得到它们的?
$ date -u -d 'Thu Oct 14 01:17:00 EDT 2010'
Thu Oct 14 05:17:00 UTC 2010