Проблема преобразования времени эпохи в стандартное соглашение в Perl - PullRequest
0 голосов
/ 07 января 2012

В 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;.$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 будет делать это, потому что, когда я нахожу остаток через деление длинной руки, у меня нет этой проблемы?Я понимаю, что мог бы использовать дату и время, чтобы, возможно, найти часы и минуты для этого вычисления, но мне все равно было бы интересно определить, что не так с моими вычислениями, чтобы можно было надеяться избежать подобных проблем в будущем при использовании % вPerl.

Ответы [ 3 ]

11 голосов
/ 07 января 2012

Зачем изобретать велосипед, если вы можете использовать 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
7 голосов
/ 07 января 2012

Этого можно достичь, просто используя основные инструменты: POSIX strftime в сочетании с localtime.

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 голосов
/ 07 января 2012

Вот простая версия, которая использует две встроенные функции Perl:

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

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

...