我有这个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
为什么?
答案 0 :(得分:2)
根据this documentation,gettimeofday
函数返回自unix时期以来的秒或微秒,即1970年1月1日 UTC 。因为它是UTC格式,所以它根本不受时区的影响。
此外,在原始代码中,您只使用gettimeofday
,它将从现在返回时间戳,而不是从1970年开始。但在您建议的答案中,出于某种原因,你已经设置了时间戳,这对你没有多大帮助。
是的,几乎每个时区都有历史,包括新加坡。 You can see it in the TZDB here。但你错了它在这个时代是+8:30。实际上是+7:30。 You can verify also on this site。但无论如何都没关系,因为就像我说的那样,gettimeofday
严格按UTC工作。
我认为问题在于你如何解释结果。你有最后一行:
print STDOUT $time{'mm:ss.mmm', $stat_perf} . " \n";
但是$stat_perf
是经过的持续时间,而不是您可以视为时间戳的值。您可能不应该将其传递给$time
,因为将使用本地时区并期望完整的时间戳。
此外,您可能希望使用tv_interval
,如图所示in the examples。
我搜索了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";
答案 1 :(得分:0)
anser是......
新加坡现在距离UTC偏离08小时。在1970年,它被抵消了08:30。要求将几秒钟转换为字符串将使我们达到1970年,而不是今天的日期和时区。
通过请求
print STDOUT $time{'mm:ss.mmm', 2} . " \n";
系统调整到1970(epoch)时区偏移。
为了在新加坡取得正确的结果,我们必须转移到1982年之后,当时新加坡改变了最后一个时区。
print STDOUT $time{'mm:ss.mmm', 2 + 1356994800} . " \n";
作为
UNIX_TIMESTAMP('2013-01-01 00:00:00') = 1356994800
我们只关注日期的时间部分,所以这样做。
检查
zdump -v Asia/Singapore
这就是诀窍。
答案 2 :(得分:0)
这是一个模拟$time{}
的脚本,用于将实数转换为表示其整数部分的mm:ss
六十进制转换的字符串,并与格式为微秒的十进制余数连接。
由于这将成为库的一部分,因此可以设置保护措施以避免使用错误的参数调用它。
我希望我没有错过任何东西。
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 (" >> %s\n", µTime ($stat_perf));
print STDOUT sprintf (" == %s\n", $time{'mm:ss.mmm', $stat_perf});