在Perl中将纪元时间转换为标准约定的问题

时间:2012-01-06 21:19:17

标签: perl time epoch

在Perl中我试图使用以下代码将包含毫秒纪元时间变量$adjSendTime的变量转换为标准约定:

$timeLabel = sprintf("%02d:%02d:%02d", (($adjSendTime/3600000) % 24), (($adjSendTime/60000) % 60), $currentSecond);

问题在于,无论何时达到第59秒,时间的一小部分时间都将高于应有的时间。输出看起来像

11:58:57
11:58:58
11:59:59
11:59:00
11:59:01

$adjSendTime的计算如下:

# Determine number of hours between local time and UTC.
# This code is needed to compare timestamps in local time with those in epoch time.
# This code only works in time zones with current time less than UTC time.
@timeArray = gmtime();
$utcHour = $timeArray[2];
@timeArray = localtime();
$localHour = $timeArray[2];
# calculate number of milliseconds between current time and UTC time
$utcShift = ($utcHour - $localHour + 24) % 24;
$utcShift = $utcShift*60*60*1000;

...

if ($field[$i] =~ /^\[29997]=/) {
  $sendTimestamp = $field[$i];
  $sendTimestamp =~ s/.*=(\d*).*/$1/;
  # convert send time to local time.
  $adjSendTime = $sendTimestamp - $utcShift;
}

$currentSecond的计算在代码的两个不同部分。第一部分是$FIRST = 1;时第一次通过循环。执行此if语句后,$FIRST永远不会重置为1。

$second = ($adjSendTime/1000) % 60;
if ($FIRST) {
  $currentSecond = $second;
  $prevSeqId = $seqId;
  $FIRST = 0;
}

并在子例程resetCounters中,其中脚本中计算的每个值都重新初始化为0.调用此子例程在输入日志文件中每隔一秒开始时调用。

sub resetCounters
# -----------------------------------------------------------
# resets all metrics counters
# -----------------------------------------------------------
{
  $tps = 0;
  $mps = 0;
  $batch = 0;
  $maxBatch = 0;
  $avgBatch = 0;
  $latency = 0;
  $latencySum = 0;
  $maxLatency = 0;
  $avgLatency = 0;
  $overThreshold = 0;
  $percentOver = 0;
  $zeroLatencyCount = 0;
  $currentSecond = $second;
  @latencies = ();
}

任何人都可以帮我弄清楚为什么Perl会这样做,因为当我通过长手划分找到剩余部分时我没有这个问题吗?我意识到我可以使用datetime来计算这个计算的小时和分钟,但是我仍然有兴趣确定我的计算有什么问题,以便我可以在将来使用{{1}时避免这样的问题。在Perl。

3 个答案:

答案 0 :(得分:11)

为什么在使用DateTime时重新发明轮子?

use strict;
use warnings;
use DateTime;

my $epoch=1254121251.352329;

my $dt = DateTime->from_epoch(epoch=>$epoch,time_zone => "America/Chicago");

print $dt->ymd . " " . $dt->hms . "\n";

输出结果为:

2009-09-28 02:00:51

答案 1 :(得分:7)

只需使用核心工具即可实现这一点:POSIXstrftimelocaltime结合使用。

use POSIX qw( strftime );
say strftime('%H:%M:%S', localtime( $mstime/1000 ));

DateTime是一个很棒的模块,但是对于这项工作来说这是不必要的慢。而且更加啰嗦。

use DateTime qw( );
my $dt = DateTime->from_epoch(epoch => $mstime/1000, time_zone => 'local');
say $dt->strftime('%H:%M:%S');

答案 2 :(得分:2)

这是一个使用两个内置perl函数的简单版本:

my $timeLabel = sprintf "%02d:%02d:%02d", (localtime($adjSendTime/1000))[2,1,0];

对于比这更复杂的事情,我可能会使用一个外部模块,但我觉得这样做并没有太多意义。