计算两个日期之间的时间差

计算两个日期之间的时间差

我有这个愚蠢的脚本来跟踪我的 cron 作业的执行时间,以了解脚本何时启动和停止。

start=$(date +'%Y-%m-%d %H:%M:%S') # This line converts to 2019-09-10 00:50:48
echo "$start"

./actual_script_runs_here

stop=$(date +'%Y-%m-%d %H:%M:%S')
echo "$stop"

这个方法有效。但我必须自己计算运行脚本所需的时间。可以在 bash 中计算吗?

或者我可以使用time命令。但它返回了 3 个不同的时间并包含 3 个新行。我希望看到时间结果与我的脚本结果一起出现在一行中。

答案1

您可以使用它date +%s来获取可以轻松进行数学计算的日期格式(自 1970 年 1 月 1 日 00:00:00Z 以来的秒数[带警告])。您还可以使用date -d "$start" +%s.它并不理想,不仅因为转换回来时存在夏令时问题,而且如果有人在程序运行时更改了时间,或者像 ntp 这样的东西,那么您将得到错误的答案。可能是一个非常错误的。

闰秒会给你一个稍微错误的答案(相差一秒)。

不幸的是,检查时间的源代码,它似乎time遇到了使用挂钟时间(而不是“单调”时间)的相同问题。值得庆幸的是,Perl 几乎随处可用,并且可以访问单调计时器:

start=$(perl -MTime::HiRes=clock_gettime,CLOCK_MONOTONIC -E 'say clock_gettime(CLOCK_MONOTONIC)')

这将获得自过去任意点以来的秒数(在 Linux 上,自启动以来,不包括机器挂起的时间)。即使时钟发生变化,它也会计算秒数。由于在 shell 中处理实数(非整数)有些困难,因此您可以在 Perl 中完成整个操作:

#!/usr/bin/perl
use warnings qw(all);
use strict;

use Time::HiRes qw(clock_gettime CLOCK_MONOTONIC);

my $cmd   = $ARGV[0];
my $start = clock_gettime(CLOCK_MONOTONIC);

system $cmd @ARGV; # this syntax avoids passing it to "sh -c"

my $exit_code = $?;
my $end       = clock_gettime(CLOCK_MONOTONIC);
printf STDERR "%f\n", $end - $start;

exit($exit_code ? 127 : 0);

我将其命名为“单调时间”;它的用法就像“时间”一样(没有任何自己的参数)。所以:

$ monotonic-time sleep 5
5.001831                 # appeared ≈5s later
$ monotonic-time fortune -s
Good news is just life's way of keeping you off balance.
0.017800

答案2

在 Bash 中,你还可以使用魔法变量SECONDS

SECONDS
每次引用此参数时,都会返回自 shell 调用以来的秒数。

所以:

bash -c 'a=$SECONDS; sleep 5; b=$SECONDS; printf "%d seconds passed\n" "$((b-a))"'

输出5 seconds passed

SECONDS虽然只有整秒粒度,但date +"... %S".对于 GNU date,您可以使用%Nwith%s来获取以纳秒为单位的时间。

a=$(date +%s%N)
sleep 1.234
b=$(date +%s%N)
diff=$((b-a))
printf "%s.%s seconds passed\n" "${diff:0: -9}" "${diff: -9:3}"

印刷:

1.237 seconds passed

Bash 无法对浮点数进行算术运算,因此您需要使用外部实用程序来进行计算,或者像我上面那样以小于秒的单位进行计算。 (这些数字不适合 32 位,因此可能无法在 32 位系统上工作。我不确定 Bash 是否使用 64 位进行算术,即使在 32 位系统上也是如此。)

SECONDS如果在测量期间修改系统时间也会出现错误,但实际上您应该只在启动期间设置一次时间,然后让 NTP 调整时钟以保持准时。

答案3

惊讶的是没有人说要使用Python!例如,5 天前为 yyyymmdd:

MYDATE=$( python -c 'from datetime import date, timedelta; 
    print( ( date.today() - timedelta(days=5) ).strftime("%Y%m%d"))' )

如果您想使用比天更小的单位进行操作,请导入datetime并可能使用datetime.now()

相关内容