我有这个Perl脚本,需要在其中监视DBI调用的执行时间。
在欧洲(法国),我没有问题:据报道,2秒的执行时间是2秒。
在新加坡的一台计算机上运行的相同脚本报告为30分2秒。
为什么?
use strict;
use Time::Format qw(%time);
use Time::HiRes qw(gettimeofday);
my $time_start = gettimeofday();
sleep 2; # some action goes here
my $stat_perf = gettimeofday() - $time_start;
print STDOUT $time{'mm:ss.mmm', $stat_perf} . " n";
法国的产量是
00:02.000
在新加坡运行的相同脚本产生:
30:02.001
为什么?
根据本文档,gettimeofday
函数返回自unix epoch(1970年1月1日)以来的秒或微秒UTC。因为它在UTC,所以完全不受时区的影响。
此外,在您的原始代码中,您只是使用gettimeofday
,它将返回现在的时间戳,而不是1970年的时间戳。但在你建议的答案中,出于某种原因,你已经硬设置了时间戳,这对你没有多大帮助。
是的,几乎每个时区都有历史,包括新加坡。您可以在TZDB中看到它。但是你说的时间是+8:30是不对的。实际上是+7:30。您也可以在此网站上进行验证。但这并不重要,因为正如我所说,gettimeofday
在UTC中严格工作。
我认为问题在于你如何解读结果。你的最后一行是:
print STDOUT $time{'mm:ss.mmm', $stat_perf} . " n";
但是$stat_perf
是经过的持续时间,而不是一个可以作为时间戳的值。您可能不应该将其传递给$time
,因为将使用本地时区,并且需要完整的时间戳。
此外,您可能希望使用tv_interval
,如示例所示。
更新
我搜索了CPAN档案,我确信某个地方有一个用于格式化经过的时间的模块,但我似乎找不到。无论如何,自己写这篇文章并不太难。在这里,这应该有效:
my $min = $stat_perf / 60;
my $sec = ($stat_perf * 1000 % 60000) / 1000;
my $elapsed = sprintf("%02u:%06.3f", $min, $sec);
print STDOUT $elapsed . "n";
anser是。。。
新加坡现在距离UTC偏移08h00。1970年,它被抵消了08h30。要求将几秒钟转换成字符串会让我们回到1970年,而不是今天的日期和时区。
通过请求
print STDOUT $time{'mm:ss.mmm', 2} . " n";
系统调整到1970(历元)时区偏移。
为了在新加坡取得正确的结果,我们必须转移到1982年之后,当时新加坡进行了最后一次时区更改。
print STDOUT $time{'mm:ss.mmm', 2 + 1356994800} . " n";
作为
UNIX_TIMESTAMP('2013-01-01 00:00:00') = 1356994800
我们只关心日期的时间部分,所以这样做了
使用检查
zdump -v Asia/Singapore
这就是诀窍。
这里有一个脚本,它模拟$time{}
将实数转换为表示整数部分的mm:ss
sexagesimal转换的字符串,并与格式化为微秒的十进制余数连接。
由于这将是库的一部分,因此设置了一些保护措施,以避免使用错误的参数调用它。
我希望我没有错过什么。
use strict;
use Time::Format qw(%time);
# ----------------------------------------------------------
# A substitute to $time{} as we have issues with TZ offsets at epoch days in some part of the World
# A real to sexagesimal converter
# Format will be set to match $time{'mm:ss.mmm', $stat_perf};
sub microTime {
return '' unless (my ($intertime) = @_);
return '' unless (ref ($intertime) eq '');
return '' unless (sprintf("%s", $intertime) =~ m/^(?:[d]+)(?:.(?:[d]+))?$/);
my $intNum = int($intertime);
"a" =~ /a/; # Resets regex buffers
sprintf ("%.03f", $intertime - $intNum) =~ m,.([d]+),;
my $intDec = $1; # It's always defined
my $intUnder = $intNum % 3600;
my $intMin = int($intUnder / 60);
my $intSec = $intUnder % 60;
return sprintf ("%02d:%02d.%03d", $intMin, $intSec, $intDec);
}
my $stat_perf;
$stat_perf = 345.987;
$stat_perf = 345;
$stat_perf = 3945.987;
$stat_perf = 0;
$stat_perf = 3945.918733;
print STDOUT sprintf (" >> %sn", µTime ($stat_perf));
print STDOUT sprintf (" == %sn", $time{'mm:ss.mmm', $stat_perf});