date +"%T"
を使用して開始時間と終了時間を表示します。その結果、次のようになります。
10:33:56
10:36:10
これら2つの違いを計算して印刷する方法を教えてください。
私は何かを手に入れたいです。
2m 14s
Bashはシェルが起動してから経過した秒数を追跡する便利なSECONDS
組み込み変数を持っています。この変数は、割り当てられたときにそのプロパティを保持し、割り当て後に返される値は、割り当てから割り当てられた値を加えた時間からの秒数です。
したがって、時限イベントを開始する前にSECONDS
を0に設定し、イベントの後で単にSECONDS
を読み取り、表示する前に時間演算を実行するだけです。
SECONDS=0
# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."
このソリューションはdate +%s
(これはGNU拡張子です)には依存しないため、Bashがサポートするすべてのシステムに移植できます。
経過時間(秒)を測定するには、次のものが必要です。
経過秒数の整数値を見つけるには、2つのbash内部方法があります。
Bash変数SECONDS(SECONDSが設定されていない場合、その特別な性質を失います)。
SECONDSの値を0に設定します。
SECONDS=0
sleep 1 # Process to execute
elapsedseconds=$SECONDS
最初に変数SECONDS
の値を格納する:
a=$SECONDS
sleep 1 # Process to execute
elapsedseconds=$(( SECONDS - a ))
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 ))
Bash内部のprintf
は直接それを行うことができます。
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' 12345
03:25:45
同様に
$ elapsedseconds=$((12*60+34))
$ TZ=UTC0 printf '%(%H:%M:%S)T\n' "$elapsedseconds"
00:12:34
しかしこれは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
詳細の愛好家のために、 bash-hackers.org から:
%(FORMAT)T
は、FORMATを使用した結果の日時文字列をstrftime(3)
のフォーマット文字列として出力します。関連する引数は Epoch 以降の秒数、または-1(現在時刻)または-2(シェル起動時刻)です。対応する引数が指定されていない場合は、現在時刻がデフォルトとして使用されます。
ですから、textifyDuration
がデュレーション印刷のもう1つの実装であるtextifyDuration $elpasedseconds
を呼び出すだけでよいでしょう。
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)"
}
形式化された時間を取得するには、Nanosecondsを含めて、ほぼ1年の長さに達するためのいくつかの方法で外部ツール(GNU date)を使用する必要があります。
外部演算は必要ありません。date
内で1ステップですべて実行します。
date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"
はい、コマンド文字列に0
ゼロがあります。それが必要とされています。
これは、date +"%T"
コマンドをdate +"%s"
コマンドに変更して、値が秒単位で格納(印刷)されることを前提としています。
コマンドは以下に制限されていることに注意してください。
$StartDate
および$FinalDate
秒の正の値.$FinalDate
の値は、$StartDate
よりも大きい(時間が遅い)。あなたが10:33:56
文字列を使わなければならないならば、それを秒に変換してください。
また、Wordの秒は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"
秒の時間変換(上記のとおり)は、「この」日の始まり(今日)からの相対時間です。
この概念は、次のようにナノ秒まで拡張できます。
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"
より長い(最大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
残念ながら、この場合は、日数から手動で1
ONEを引く必要があります。 dateコマンドは、年の最初の日を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[@]}"
長い秒数の使用は有効であり、ここに文書化されています。
https://www.gnu.org/software/coreutils/manual/html_node/Examples-of-date.html#Examples-of-date
小型のデバイスで使用されるツール(インストールするための非常に小さい実行可能ファイル):Busybox。
Dateというbusyboxへのリンクを作成します。
$ ln -s /bin/busybox date
それからこれをdate
を呼び出して使用します(PATHを含むディレクトリに置きます)。
あるいは、エイリアスを次のようにします。
$ alias date='busybox date'
Busyboxの日付にはNiceオプションがあります。-Dは入力時刻のフォーマットを受け取ります。それは時間として使われるべき多くのフォーマットを開く。 -Dオプションを使用すると、時間10:33:56を直接変換できます。
date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"
そしてあなたが上の司令部の出力からわかることができるように、日は「今日」であると仮定されます。 Epochの開始時間を取得するには:
$ 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
Busyboxの日付は-Dなしでも時間を受け取ることができます(上の形式で)。
$ date -u -d "1970.01.01-$string1" +"%Y.%m.%d-%H:%M:%S"
1970.01.01-10:33:56
そして、出力フォーマットはEpochから数秒になる可能性さえあります。
$ date -u -d "1970.01.01-$string1" +"%s"
52436
両方の時間のために、そして少し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 ))
またはフォーマット:
$ date -u -D "%s" -d "$(( t2 - t1 ))" +"%H:%M:%S"
00:02:14
これが私のやり方です。
START=$(date +%s);
sleep 1; # Your stuff
END=$(date +%s);
echo $((END-START)) | awk '{print int($1/60)":"int($1%60)}'
非常に簡単で、最初に秒数を取り、次に最後に秒数を取り、その差を分:秒で表示します。
別の選択肢は、datediff
( http://www.fresse.org/dateutils/#datediff )からdateutils
を使用することです。
$ 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
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
あるいは、これを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
私は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"
ミリセカンドを同じように扱うことさえできます。
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"
ここにいくつかの魔法があります:
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
sed
は、:
を1/60に変換する式に置き換えます。それからbc
によって行われる時間計算
現在の日付(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
使用できる単位は、日、年、月、時間、分、秒です。
$ date -d tomorrow+2days-10minutes
Thu Jul 31 13:33:02 UTC 2014
Daniel Kamil Kozarの答えから、時間/分/秒を表示します
echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"
そのため、完全なスクリプトは次のようになります。
date1=$(date +"%s")
date2=$(date +"%s")
diff=$(($date2-$date1))
echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"
またはそれを少しまとめて
alias timerstart='starttime=$(date +"%s")'
alias timerstop='echo seconds=$(($(date +"%s")-$starttime))'
それからこれはうまくいきます。
timerstart; sleep 2; timerstop
seconds=2
これは、 "before"を使用し、終了時刻を格納するために2番目の変数を使用しないで、date
コマンドの機能のみを使用するソリューションです。
#!/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
これは与える:
$ ./time_elapsed.sh
elapsed_time: 1.002257120
GNU units
の場合:
$ units
2411 units, 71 prefixes, 33 nonlinear units
You have: (10hr+36min+10s)-(10hr+33min+56s)
You want: s
* 134
/ 0.0074626866
You have: (10hr+36min+10s)-(10hr+33min+56s)
You want: min
* 2.2333333
/ 0.44776119
date
はあなたに違いを与えそしてあなたのためにそれをフォーマットすることができます(OS Xオプションが示されています)
date -ujf%s $(($(date -jf%T "10:36:10" +%s) - $(date -jf%T "10:33:56" +%s))) +%T
# 00:02:14
date -ujf%s $(($(date -jf%T "10:36:10" +%s) - $(date -jf%T "10:33:56" +%s))) \
+'%-Hh %-Mm %-Ss'
# 0h 2m 14s
いくつかの文字列処理はそれらの空の値を削除することができます
date -ujf%s $(($(date -jf%T "10:36:10" +%s) - $(date -jf%T "10:33:56" +%s))) \
+'%-Hh %-Mm %-Ss' | sed "s/[[:<:]]0[hms] *//g"
# 2m 14s
これより早い時間を最初に設定した場合、これは機能しません。これを処理する必要がある場合は、$(($(date ...) - $(date ...)))
を$(echo $(date ...) - $(date ...) | bc | tr -d -)
に変更してください。
% start=$(date +%s)
% echo "Diff: $(date -d @$(($(date +%s)-$start)) +"%M minutes %S seconds")"
Diff: 00 minutes 11 seconds
GNU dateを使って@ nisetamaの解を一般化する(trusty Ubuntu 14.04 LTS):
start=`date`
# <processing code>
stop=`date`
duration=`date -ud@$(($(date -ud"$stop" +%s)-$(date -ud"$start" +%s))) +%T`
echo $start
echo $stop
echo $duration
収量:
Wed Feb 7 12:31:16 CST 2018
Wed Feb 7 12:32:25 CST 2018
00:01:09
mencoder
(その--endpos
は相対パス)で使用するための時差スクリプトが必要でした、そして私の解決策はPythonスクリプトを呼び出すことです:
$ ./timediff.py 1:10:15 2:12:44
1:02:29
秒の端数もサポートされています。
$ echo "diff is `./timediff.py 10:51.6 12:44` (in hh:mm:ss format)"
diff is 0:01:52.4 (in hh:mm:ss format)
200と120の差は1時間20分です。
$ ./timediff.py 120:0 200:0
1:20:0
そして、任意の(おそらく小数の)秒数、分数、または時間数をhh:mm:ssに変換できます。
$ ./timediff.py 0 3600
1:00:0
$ ./timediff.py 0 3.25:0:0
3:15:0
timediff.py :
#!/usr/bin/python
import sys
def x60(h,m):
return 60*float(h)+float(m)
def seconds(time):
try:
h,m,s = time.split(':')
return x60(x60(h,m),s)
except ValueError:
try:
m,s = time.split(':')
return x60(m,s)
except ValueError:
return float(time)
def difftime(start, end):
d = seconds(end) - seconds(start)
print '%d:%02d:%s' % (d/3600,d/60%60,('%02f' % (d%60)).rstrip('0').rstrip('.'))
if __== "__main__":
difftime(sys.argv[1],sys.argv[2])
私はこれが古い投稿であることを認識していますが、ログファイルから日付と時刻を取得して差分を計算するスクリプトを作成しながら、今日それを見つけました。以下のスクリプトは確かにやり過ぎであり、私は自分の論理と数学をチェックすることを強く勧めます。
#!/bin/bash
dTime=""
tmp=""
#firstEntry="$(head -n 1 "$LOG" | sed 's/.*] \([0-9: -]\+\).*/\1/')"
firstEntry="2013-01-16 01:56:37"
#lastEntry="$(tac "$LOG" | head -n 1 | sed 's/.*] \([0-9: -]\+\).*/\1/')"
lastEntry="2014-09-17 18:24:02"
# I like to make the variables easier to parse
firstEntry="${firstEntry//-/ }"
lastEntry="${lastEntry//-/ }"
firstEntry="${firstEntry//:/ }"
lastEntry="${lastEntry//:/ }"
# remove the following lines in production
echo "$lastEntry"
echo "$firstEntry"
# compute days in last entry
for i in `seq 1 $(echo $lastEntry|awk '{print $2}')`; do {
case "$i" in
1|3|5|7|8|10|12 )
dTime=$(($dTime+31))
;;
4|6|9|11 )
dTime=$(($dTime+30))
;;
2 )
dTime=$(($dTime+28))
;;
esac
} done
# do leap year calculations for all years between first and last entry
for i in `seq $(echo $firstEntry|awk '{print $1}') $(echo $lastEntry|awk '{print $1}')`; do {
if [ $(($i%4)) -eq 0 ] && [ $(($i%100)) -eq 0 ] && [ $(($i%400)) -eq 0 ]; then {
if [ "$i" = "$(echo $firstEntry|awk '{print $1}')" ] && [ $(echo $firstEntry|awk '{print $2}') -lt 2 ]; then {
dTime=$(($dTime+1))
} Elif [ $(echo $firstEntry|awk '{print $2}') -eq 2 ] && [ $(echo $firstEntry|awk '{print $3}') -lt 29 ]; then {
dTime=$(($dTime+1))
} fi
} Elif [ $(($i%4)) -eq 0 ] && [ $(($i%100)) -ne 0 ]; then {
if [ "$i" = "$(echo $lastEntry|awk '{print $1}')" ] && [ $(echo $lastEntry|awk '{print $2}') -gt 2 ]; then {
dTime=$(($dTime+1))
} Elif [ $(echo $lastEntry|awk '{print $2}') -eq 2 ] && [ $(echo $lastEntry|awk '{print $3}') -ne 29 ]; then {
dTime=$(($dTime+1))
} fi
} fi
} done
# substract days in first entry
for i in `seq 1 $(echo $firstEntry|awk '{print $2}')`; do {
case "$i" in
1|3|5|7|8|10|12 )
dTime=$(($dTime-31))
;;
4|6|9|11 )
dTime=$(($dTime-30))
;;
2 )
dTime=$(($dTime-28))
;;
esac
} done
dTime=$(($dTime+$(echo $lastEntry|awk '{print $3}')-$(echo $firstEntry|awk '{print $3}')))
# The above gives number of days for sample. Now we need hours, minutes, and seconds
# As a bit of hackery I just put the stuff in the best order for use in a for loop
dTime="$(($(echo $lastEntry|awk '{print $6}')-$(echo $firstEntry|awk '{print $6}'))) $(($(echo $lastEntry|awk '{print $5}')-$(echo $firstEntry|awk '{print $5}'))) $(($(echo $lastEntry|awk '{print $4}')-$(echo $firstEntry|awk '{print $4}'))) $dTime"
tmp=1
for i in $dTime; do {
if [ $i -lt 0 ]; then {
case "$tmp" in
1 )
tmp="$(($(echo $dTime|awk '{print $1}')+60)) $(($(echo $dTime|awk '{print $2}')-1))"
dTime="$tmp $(echo $dTime|awk '{print $3" "$4}')"
tmp=1
;;
2 )
tmp="$(($(echo $dTime|awk '{print $2}')+60)) $(($(echo $dTime|awk '{print $3}')-1))"
dTime="$(echo $dTime|awk '{print $1}') $tmp $(echo $dTime|awk '{print $4}')"
tmp=2
;;
3 )
tmp="$(($(echo $dTime|awk '{print $3}')+24)) $(($(echo $dTime|awk '{print $4}')-1))"
dTime="$(echo $dTime|awk '{print $1" "$2}') $tmp"
tmp=3
;;
esac
} fi
tmp=$(($tmp+1))
} done
echo "The sample time is $(echo $dTime|awk '{print $4}') days, $(echo $dTime|awk '{print $3}') hours, $(echo $dTime|awk '{print $2}') minutes, and $(echo $dTime|awk '{print $1}') seconds."
以下のように出力されます。
2012 10 16 01 56 37
2014 09 17 18 24 02
The sample time is 700 days, 16 hours, 27 minutes, and 25 seconds.
スクリプトをスタンドアロンにするためにスクリプトを少し変更しました(つまり、変数値を設定するだけです)が、一般的な考え方も同様に思いつくでしょう。あなたは負の値のためにいくつかの追加のエラーチェックを望むかもしれません。
私はmcaleaaの答えにコメントすることはできませんので、私はこれをここに投稿します。 "diff"変数は小文字にする必要があります。これが一例です。
[root@test ~]# date1=$(date +"%s"); date
Wed Feb 21 23:00:20 MYT 2018
[root@test ~]#
[root@test ~]# date2=$(date +"%s"); date
Wed Feb 21 23:00:33 MYT 2018
[root@test ~]#
[root@test ~]# diff=$(($date2-$date1))
[root@test ~]#
前の変数が小文字で宣言されました。これは大文字が使われたときに起こったことです。
[root@test ~]# echo "Duration: $(($DIFF / 3600 )) hours $((($DIFF % 3600) / 60)) minutes $(($DIFF % 60)) seconds"
-bash: / 3600 : syntax error: operand expected (error token is "/ 3600 ")
[root@test ~]#
だから、迅速な修正はこのようになります
[root@test ~]# echo "Duration: $(($diff / 3600 )) hours $((($diff % 3600) / 60)) minutes $(($diff % 60)) seconds"
Duration: 0 hours 0 minutes 13 seconds
[root@test ~]#