![计算两个日期之间的时间差](https://linux22.com/image/160392/%E8%AE%A1%E7%AE%97%E4%B8%A4%E4%B8%AA%E6%97%A5%E6%9C%9F%E4%B9%8B%E9%97%B4%E7%9A%84%E6%97%B6%E9%97%B4%E5%B7%AE.png)
我有这个愚蠢的脚本来跟踪我的 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,您可以使用%N
with%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()