在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。
非常感谢任何帮助。
答案 0 :(得分:5)
关于时区的Perl DateTime FAQ有很好的背景知道为什么在大多数转换中不能使用EDT和EST。问题是其他国家的东部时区也有相同的3个字母缩写。 EST EDT模糊不清,没有其他线索。
您可以查看other modules,或者只是假设“EDT”与“EST5EDT”相同,如果这是真的。
答案 1 :(得分:5)
如果您知道如何消除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);
}
答案 2 :(得分:3)
如果您使用的是Date :: Time :: Strptime,则可以使用%O
作为Olson时区名称,并在解析之前进行手动修复。
即。如果您知道输入中的EDT意味着America / New_York,请执行以下操作:
$time_in =~ s{EDT}{America/New_York};
而不是
%a %b %d %T %Z %Y
用于您的时区规范使用
%a %b %d %T %O %Y
答案 3 :(得分:1)
我总是发现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
似乎是你正在寻找的东西。
答案 4 :(得分:0)
我有点迟到,但GNU date
本身擅长解析日期:
$ date -u -d 'Thu Oct 14 01:17:00 EDT 2010'
Thu Oct 14 05:17:00 UTC 2010
我不知道它是如何解决EDT歧义的。
答案 5 :(得分:0)
我同意Jander on date命令。 -d和-u非常棒,可以节省很多代码行。