如何在Perl中将epoch时间转换为普通时间?

6
我正在尝试编写一个Perl脚本,用于解析日志文件,其中每行的第二个值是日期。该脚本接受三个参数:输入日志文件、开始时间和结束时间。开始和结束时间用于解析出在这两个时间之间的每行中的某个值。但为了正确运行此脚本,我将开始和结束时间转换为纪元时间。我遇到的问题是将循环中的'i'值转换回正常时间以与日志文件进行比较。在运行localtime($i)后,我打印该值,只看到了一个引用而不是实际值。

以下是我目前拥有的脚本(它仍在不断完善):

#!/usr/bin/perl
use strict;
use warnings;
use Time::Local;
use Time::localtime;
use File::stat;

my $sec = 0;
my $min = 0;
my $hour = 0;
my $mday = 0;
my $mon = 0;
my $year = 0;
my $wday = 0;
my $yday = 0;
my $isdst = 0;

##########################
# Get the engine log date
##########################
my $date = `grep -m 1 'Metric' "$ARGV[0]" | awk '{print \$2}'`;
($year,$mon,$mday) = split('-', $date);
$mon--;

#########################################
# Calculate the start and end epoch time
#########################################
($hour,$min,$sec) = split(':', $ARGV[1]);
my $startTime = timelocal($sec,$min,$hour,$mday,$mon,$year);
($hour,$min,$sec) = split(':', $ARGV[2]);
my $endTime = timelocal($sec,$min,$hour,$mday,$mon,$year);


my $theTime = 0;
for (my $i = $startTime; $i <= $endTime + 29; $i++) {
        #print "$startTime   $i \n";

        $theTime = localtime($i);

        #my $DBInstance0 = `grep "$hour:$min:$sec" "$ARGV[0]"`;# | grep 'DBInstance-0' | awk '{print \$9}'`;
        #print "$DBInstance0\n";
        print "$theTime\n";
}
print "$startTime   $endTime \n";

输出结果如下:
Time::tm=ARRAY(0x8cbbd40)
Time::tm=ARRAY(0x8cbc1a0)
Time::tm=ARRAY(0x8cbbe80)
Time::tm=ARRAY(0x8cbc190)
Time::tm=ARRAY(0x8bbb170)
Time::tm=ARRAY(0x8cbc180)
Time::tm=ARRAY(0x8cbbf30)
Time::tm=ARRAY(0x8cbc170)
Time::tm=ARRAY(0x8cbc210)
Time::tm=ARRAY(0x8cbc160)
1275760356   1275760773

我只能访问核心的Perl模块,无法安装其他模块。


2
@Ether,@Peter - 有些人为比初创公司更大的公司工作,使用未经测试的代码所带来的收益远远大于使用它所面临的风险。当你因错误的代码而损失数十亿时,你的观点会变得更加谨慎。因此,基于这个原因对某人不礼貌不仅不能帮助你赢得Perl转换者,而且是非常不公平的。 - DVK
5
@Ether - 我并不是假设这种情况。我假设“先使用再请求原谅”的态度在小公司中可能是可以接受的——出于好或坏的原因——但通常情况下,在大公司中,无论个别开发人员对此持什么看法以及我个人喜欢牛仔的方式,出于好的原因,这种做法是不可接受的。 - DVK
3
在我看来,SO Perl标签上经常出现的“找另一份工作”的条件反射反应是完全错误的。能够做任何你认为必要并且不在乎后果,并不总是人们想要为特定公司工作的主要原因,也很少是最重要的原因。 - DVK
6
让我解释一下为什么我不能使用未经测试的代码。我在世界上最大的交易所之一工作。如果我使用一个未经测试的模块,导致某个人损失数百万或数十亿美元,那将不可饶恕。我们采取这种“偏执狂”的做法,因为太多东西可能会丢失,并可能使许多国家陷入萧条。DVK是正确的,不是每个人都可以“先使用它,然后再请求原谅”。虽然我只能使用核心Perl模块,但我喜欢我的工作。在这些模块测试之前,我的工作会变得更加困难,但这对我来说没问题。 - Matt Pascoe
2
@Ether - 以Archive::Tar为特定例子,我记得它曾经因为非常棘手的内存泄漏导致Web服务器耗尽内存。除了进行长达3个月的测试运行,没有人会发现这个问题...而且由于Web服务器崩溃而导致数万亿美元的资产无法管理,因为数百个主要金融客户无法使用他们的系统,这绝不是我认为缩短CPAN模块的上市时间所应该做出的良好权衡。 - DVK
显示剩余8条评论
2个回答

3
您可以使用ctime,根据您对“普通时间”的定义而定:
示例代码:
use Time::Local; 
use Time::localtime; 
my $time=timelocal(1,2,3,24,6,2010);
print "$time\n"; 
$theTime = ctime($time); 
print "$theTime\n";

结果:

1279954921
Sat Jul 24 03:02:01 2010

此外,您无需使用Time::Localtime(这就是为什么您会得到来自Perl内部的Time::tm而不是标准数组/字符串):(此处提供了Time::Localtime的文档链接)
use Time::Local; 
my $time=timelocal(1,2,3,24,6,2010); 
print "$time\n"; 
$theTime = localtime($time); 
print "$theTime\n";

1279954921
Sat Jul 24 03:02:01 2010

2
不要忘记从年份中减去1900!
请记住,在标量上下文中,localtimegmtime返回一个格式为ctime的字符串,因此您可以像以下示例中那样使用它。如果这不适用,您可能需要使用POSIX模块中的strftime
#! /usr/bin/perl

use warnings;
use strict;

use Time::Local;

my $start = "01:02:03";
my $end   = "01:02:05";
my $date  = "2010-02-10";

my($year,$mon,$mday) = split /-/, $date;
$mon--;
$year -= 1900;

my($startTime,$endTime) =
  map { my($hour,$min,$sec) = split /:/;
        timelocal $sec,$min,$hour,$mday,$mon,$year }
  $start, $end;

for (my $i = $startTime; $i <= $endTime + 29; $i++) {
  print scalar localtime($i), "\n";
}

print "$startTime   $endTime \n";

输出结果如下:

输出的尾部:

2010年2月10日星期三 01:02:26
2010年2月10日星期三 01:02:27
2010年2月10日星期三 01:02:28
2010年2月10日星期三 01:02:29
2010年2月10日星期三 01:02:30
2010年2月10日星期三 01:02:31
2010年2月10日星期三 01:02:32
2010年2月10日星期三 01:02:33
2010年2月10日星期三 01:02:34
1265785323   1265785325

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接