我使用打印开始和结束时间date +"%T"
,结果如下:
10:33:56
10:36:10
Run Code Online (Sandbox Code Playgroud)
我怎么能计算和打印这两者之间的差异?
我想得到类似的东西:
2m 14s
Run Code Online (Sandbox Code Playgroud)
Dan*_*zar 428
Bash有一个方便的SECONDS
内置变量,用于跟踪自shell启动以来经过的秒数.此变量在分配时保留其属性,赋值后返回的值是自分配后的秒数加上指定的值.
因此,您可以SECONDS
在启动定时事件之前设置为0,只需SECONDS
在事件之后读取,并在显示之前执行时间算术.
SECONDS=0
# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."
Run Code Online (Sandbox Code Playgroud)
由于此解决方案不依赖于date +%s
(它是GNU扩展),因此它可以移植到Bash支持的所有系统.
小智 83
要测量我们需要的经过时间(以秒为单位):
有两种bash内部方法可以找到经过的秒数的整数值:
Bash变量SECONDS(如果未设置SECONDS,则会丢失其特殊属性).
将SECONDS的值设置为0:
SECONDS=0
sleep 1 # Process to execute
elapsedseconds=$SECONDS
Run Code Online (Sandbox Code Playgroud)SECONDS
在开始时存储变量的值:
a=$SECONDS
sleep 1 # Process to execute
elapsedseconds=$(( SECONDS - a ))
Run Code Online (Sandbox Code Playgroud)Bash printf选项%(datefmt)T
:
a="$(TZ=UTC0 printf '%(%s)T\n' '-1')" ### `-1` is the current time
sleep 1 ### Process to execute
elapsedseconds=$(( $(TZ=UTC0 printf '%(%s)T\n' '-1') - a ))
Run Code Online (Sandbox Code Playgroud)bash内部printf
可以直接执行此操作:
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45
Run Code Online (Sandbox Code Playgroud)
同样
$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34
Run Code Online (Sandbox Code Playgroud)
但这会持续超过24小时,因为我们实际打印的是挂钟时间,而不是真正的持续时间:
$ hours=30;mins=12;secs=24
$ elapsedseconds=$(( ((($hours*60)+$mins)*60)+$secs ))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
06:12:24
Run Code Online (Sandbox Code Playgroud)
对于细节爱好者,来自bash-hackers.org:
%(FORMAT)T
输出使用FORMAT作为格式字符串的日期时间字符串strftime(3)
.关联参数是自Epoch以来的秒数,或-1(当前时间)或-2(shell启动时间).如果未提供相应的参数,则将当前时间用作默认值.
所以,你可能只想调用textifyDuration $elpasedseconds
哪里textifyDuration
是持续印刷的又一实施:
textifyDuration() {
local duration=$1
local shiff=$duration
local secs=$((shiff % 60)); shiff=$((shiff / 60));
local mins=$((shiff % 60)); shiff=$((shiff / 60));
local hours=$shiff
local splur; if [ $secs -eq 1 ]; then splur=''; else splur='s'; fi
local mplur; if [ $mins -eq 1 ]; then mplur=''; else mplur='s'; fi
local hplur; if [ $hours -eq 1 ]; then hplur=''; else hplur='s'; fi
if [[ $hours -gt 0 ]]; then
txt="$hours hour$hplur, $mins minute$mplur, $secs second$splur"
elif [[ $mins -gt 0 ]]; then
txt="$mins minute$mplur, $secs second$splur"
else
txt="$secs second$splur"
fi
echo "$txt (from $duration seconds)"
}
Run Code Online (Sandbox Code Playgroud)
为了获得格式化时间,我们应该以几种方式使用外部工具(GNU日期)来获得近一年的长度,包括纳秒.
无需外部算术,只需一步即可完成所有操作date
:
date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
Run Code Online (Sandbox Code Playgroud)
是的,0
命令字符串中有一个零.这是必需的.
假设您可以将date +"%T"
命令更改为命令,date +"%s"
以便以秒为单位存储(打印)值.
请注意,该命令仅限于:
$StartDate
和$FinalDate
秒.$FinalDate
比(更晚的时间)更大$StartDate
.如果你必须使用10:33:56
字符串,那么,只需将其转换为秒,
也可以将单词seconds缩写为sec:
string1="10:33:56"
string2="10:36:10"
StartDate=$(date -u -d "$string1" +"%s")
FinalDate=$(date -u -d "$string2" +"%s")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S"
Run Code Online (Sandbox Code Playgroud)
请注意,秒时间转换(如上所示)是相对于"this"日(今天)的开始.
这个概念可以扩展到纳秒,如下所示:
string1="10:33:56.5400022"
string2="10:36:10.8800056"
StartDate=$(date -u -d "$string1" +"%s.%N")
FinalDate=$(date -u -d "$string2" +"%s.%N")
date -u -d "0 $FinalDate sec - $StartDate sec" +"%H:%M:%S.%N"
Run Code Online (Sandbox Code Playgroud)
如果需要计算更长(最多364天)的时差,我们必须使用(某些)年份的开头作为参考和格式值%j
(年份中的日期编号):
相近:
string1="+10 days 10:33:56.5400022"
string2="+35 days 10:36:10.8800056"
StartDate=$(date -u -d "2000/1/1 $string1" +"%s.%N")
FinalDate=$(date -u -d "2000/1/1 $string2" +"%s.%N")
date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N"
Output:
026 days 00:02:14.340003400
Run Code Online (Sandbox Code Playgroud)
遗憾的是,在这种情况下,我们需要1
从天数中手动减去ONE.日期命令查看一年的第一天为1.没那么困难......
a=( $(date -u -d "2000/1/1 $FinalDate sec - $StartDate sec" +"%j days %H:%M:%S.%N") )
a[0]=$((10#${a[0]}-1)); echo "${a[@]}"
Run Code Online (Sandbox Code Playgroud)
使用长秒数是有效的,并在此处记录:https:
//www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
用于较小设备的工具(要安装的非常小的可执行文件):Busybox.
要么设置一个名为datebox的busybox链接:
$ ln -s /bin/busybox date
Run Code Online (Sandbox Code Playgroud)
然后通过调用它date
(将它放在PATH包含的目录中)使用它.
或者创建一个别名:
$ alias date='busybox date'
Run Code Online (Sandbox Code Playgroud)
Busybox日期有一个很好的选择:-D接收输入时间的格式.这开辟了许多格式作为时间使用.使用-D选项我们可以直接转换时间10:33:56:
date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"
Run Code Online (Sandbox Code Playgroud)
正如您从上面命令的输出中看到的那样,假设这一天是"今天".要获得从纪元开始的时间:
$ string1="10:33:56"
$ date -u -D "%Y.%m.%d-%H:%M:%S" -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
Run Code Online (Sandbox Code Playgroud)
Busybox日期甚至可以在没有-D的情况下收到时间(格式如上):
$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
Run Code Online (Sandbox Code Playgroud)
从纪元开始,输出格式甚至可能是秒.
$ date -u -d "1970.01.01-$string1" +"%s"
52436
Run Code Online (Sandbox Code Playgroud)
对于这两个时间,以及一点点bash数学(busybox无法进行数学运算):
string1="10:33:56"
string2="10:36:10"
t1=$(date -u -d "1970.01.01-$string1" +"%s")
t2=$(date -u -d "1970.01.01-$string2" +"%s")
echo $(( t2 - t1 ))
Run Code Online (Sandbox Code Playgroud)
或格式化:
$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14
Run Code Online (Sandbox Code Playgroud)
Dor*_*ian 34
我是这样做的:
START=$(date +%s);
sleep 1; # Your stuff
END=$(date +%s);
echo $((END-START)) | awk '{print int($1/60)":"int($1%60)}'
Run Code Online (Sandbox Code Playgroud)
非常简单,在开始时采用秒数,然后在结束时采用秒数,并以分钟为单位打印差异:秒.
nis*_*ama 14
另一种选择是使用datediff
由dateutils
(http://www.fresse.org/dateutils/#datediff):
$ datediff 10:33:56 10:36:10
134s
$ datediff 10:33:56 10:36:10 -f%H:%M:%S
0:2:14
$ datediff 10:33:56 10:36:10 -f%0H:%0M:%0S
00:02:14
Run Code Online (Sandbox Code Playgroud)
你也可以用gawk
.mawk
1.3.4也有strftime
,mktime
但旧版本mawk
和nawk
不.
$ TZ=UTC0 awk 'BEGIN{print strftime("%T",mktime("1970 1 1 10 36 10")-mktime("1970 1 1 10 33 56"))}'
00:02:14
Run Code Online (Sandbox Code Playgroud)
或者这是GNU的另一种方式date
:
$ date -ud@$(($(date -ud'1970-01-01 10:36:10' +%s)-$(date -ud'1970-01-01 10:33:56' +%s))) +%T
00:02:14
Run Code Online (Sandbox Code Playgroud)
Zsk*_*dan 12
我想提出另一种避免召回date
命令的方法.如果您已经以%T
日期格式收集了时间戳,则可能会有所帮助:
ts_get_sec()
{
read -r h m s <<< $(echo $1 | tr ':' ' ' )
echo $(((h*60*60)+(m*60)+s))
}
start_ts=10:33:56
stop_ts=10:36:10
START=$(ts_get_sec $start_ts)
STOP=$(ts_get_sec $stop_ts)
DIFF=$((STOP-START))
echo "$((DIFF/60))m $((DIFF%60))s"
Run Code Online (Sandbox Code Playgroud)
我们甚至可以用同样的方式处理毫秒数.
ts_get_msec()
{
read -r h m s ms <<< $(echo $1 | tr '.:' ' ' )
echo $(((h*60*60*1000)+(m*60*1000)+(s*1000)+ms))
}
start_ts=10:33:56.104
stop_ts=10:36:10.102
START=$(ts_get_msec $start_ts)
STOP=$(ts_get_msec $stop_ts)
DIFF=$((STOP-START))
min=$((DIFF/(60*1000)))
sec=$(((DIFF%(60*1000))/1000))
ms=$(((DIFF%(60*1000))%1000))
echo "${min}:${sec}.$ms"
Run Code Online (Sandbox Code Playgroud)
这是一个仅使用date
使用“ago”的命令功能的解决方案,而不使用第二个变量来存储完成时间:
#!/bin/bash
# Save the current time
start_time=$( date +%s.%N )
# Tested program
sleep 1
# The current time after the program has finished
# minus the time when we started, in seconds.nanoseconds
elapsed_time=$( date +%s.%N --date="$start_time seconds ago" )
echo elapsed_time: $elapsed_time
Run Code Online (Sandbox Code Playgroud)
这给出:
$ ./time_elapsed.sh
elapsed_time: 1.002257120
Run Code Online (Sandbox Code Playgroud)
这里有一些魔力:
time1=14:30
time2=$( date +%H:%M ) # 16:00
diff=$( echo "$time2 - $time1" | sed 's%:%+(1/60)*%g' | bc -l )
echo $diff hours
# outputs 1.5 hours
Run Code Online (Sandbox Code Playgroud)
sed
用:
公式替换a 转换为1/60.然后是时间计算bc
继 Daniel Kamil Kozar 的回答之后,显示小时/分钟/秒:
echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"
Run Code Online (Sandbox Code Playgroud)
所以完整的脚本将是:
date1=$(date +"%s")
date2=$(date +"%s")
DIFF=$(($date2-$date1))
echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"
Run Code Online (Sandbox Code Playgroud)
截至目前(GNU coreutils)7.4,您现在可以使用-d进行算术运算:
$ date -d -30days
Sat Jun 28 13:36:35 UTC 2014
$ date -d tomorrow
Tue Jul 29 13:40:55 UTC 2014
Run Code Online (Sandbox Code Playgroud)
您可以使用的单位是天,年,月,小时,分钟和秒:
$ date -d tomorrow+2days-10minutes
Thu Jul 31 13:33:02 UTC 2014
Run Code Online (Sandbox Code Playgroud)