bashスクリプトで経過した時間を計算する方法は?


224

を使用して開始時間と終了時間を出力するとdate +"%T"、次のような結果になります。

10:33:56
10:36:10

これら2つの違いを計算して出力するにはどうすればよいですか?

私は次のようなものを手に入れたいです:

2m 14s

5
別のメモでは、timeコマンドを使用できませんか?
anishsane 2013年

代わりにunix時間を使用しdate +%s、次に減算して秒単位の差を取得します。
roblogic

回答:


476

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でサポートされているすべてのシステムに移植可能です。


59
+1。ちなみに、とdate書くことで、時間の計算を実行させることができますdate -u -d @"$diff" +'%-Mm %-Ss'。(これは$diff、エポック以降の秒として解釈され、分と秒をUTCで計算します。)ただし、これはおそらくこれ以上エレガントではありませんが、難読化されています。:-P
ruakh

13
素敵でシンプル。誰かが時間を必要とする場合:echo "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
chus

6
$(date -u +%s)サマータイムが切り替わる日付での競合状態を防ぐために読んでください。そして、邪悪なうるう秒に注意してください;)
Tino

3
@ daniel-kamil-kozarいい発見。しかし、これは少し壊れやすいです。そのような変数は1つしかないため、パフォーマンスを測定するために再帰的に使用することはできません。さらに悪いことに、unset SECONDSそれがなくなった後はecho $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
Tino

6
@ParthianShot:ごめんなさい。しかし、この答えは、このような質問への答えを探すときにほとんどの人が必要とするものだと思います。時間を計算するのではなく、イベント間に経過した時間を測定するためです。
Daniel Kamil Kozar、2016

99

経過時間(秒単位)を測定するには、次のものが必要です。

  • 経過秒数を表す整数と
  • このような整数を使用可能な形式に変換する方法。

経過秒数の整数値:

  • 経過秒数の整数値を見つけるためのbash内部の方法は2つあります。

    1. 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 ))
    2. 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 $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)"
}

GNUの日付。

書式設定された時間を取得するには、外部ツール(GNU日付)をいくつかの方法で使用して、ナノ秒を含め、ほぼ1年の長さにする必要があります。

日付の中の数学。

外部演算の必要はありません。すべてを1ステップで実行しますdate

date -u -d "0 $FinalDate seconds - $StartDate seconds" +"%H:%M:%S"

はい、0コマンド文字列にゼロが含まれています。それが必要とされています。

これは、date +"%T"コマンドをコマンドに変更してdate +"%s"、値を秒単位で保存(印刷)できることを前提としています。

コマンドは以下に限定されていることに注意してください。

  • $StartDateおよび$FinalDate秒の正の値。
  • の値$FinalDateがより大きい(後で)です$StartDate
  • 24時間未満の時差。
  • 時間、分、秒の出力形式を受け入れます。変更は非常に簡単です。
  • -u UTC時間を使用することは許容されます。「DST」と現地時間の修正を回避するため。

文字列を使用する必要がある場合は10:33:56、まあ、それを秒に変換するだけです。秒
という単語は、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日数から1 を手動で減算する必要があります。日付コマンドは、年の最初の日を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の日付

小さなデバイスで使用されるツール(インストールする実行ファイルは非常に小さい):Busybox。

dateというbusyboxへのリンクを作成します。

$ ln -s /bin/busybox date

次に、これを呼び出して使用しますdate(PATHが含まれているディレクトリに配置します)。

または、次のようなエイリアスを作成します。

$ alias date='busybox date'

Busyboxの日付には素晴らしいオプションがあります:-Dは入力時刻のフォーマットを受け取ります。これは、時間として使用される多くのフォーマットを開きます。-Dオプションを使用すると、時刻10:33:56を直接変換できます。

date -D "%H:%M:%S" -d "10:33:56" +"%Y.%m.%d-%H:%M:%S"

上記のコマンドの出力からわかるように、日は「今日」であると想定されています。エポックで始まる時間を取得するには:

$ 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

また、出力形式はエポックから数秒になることもあります。

$ 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

6
これは、多くのベースをカバーし、詳細な説明を付けた、驚くべき答えです。ありがとうございました!
Devy

bashに統合され%(FORMAT)Tprintfコマンドに渡された文字列を調べる必要がありました。bash-hackers.orgから:strftime(3)のフォーマット文字列として%(FORMAT)T使用FORMATした結果の日時文字列を出力します。関連する引数は、エポック以降の秒数、または-1(現在の時間)または-2(シェルの起動時間)です。対応する引数が指定されていない場合、現在の時刻がデフォルトとして使用されます。それは難解です。この場合、「エポックからの秒数」が%s与えられstrftime(3)ます。
デビッドトンホーファー2018年

35

ここに私がそれをした方法があります:

START=$(date +%s);
sleep 1; # Your stuff
END=$(date +%s);
echo $((END-START)) | awk '{print int($1/60)":"int($1%60)}'

本当に簡単です。最初に秒数を取り、最後に秒数を取り、その差を分:秒で出力します。


6
それは私のソリューションとどのように違うのですか?awkBashは整数演算を同等に処理するため、この場合の呼び出しのメリットは実際にはわかりません。
Daniel Kamil Kozar

1
あなたの答えも正しいです。私のように、bashの不整合よりもawkを使用することを好む人もいます。
ドリアン

2
整数演算に関するBashの不整合について、もう少し詳しく説明してもらえますか?何も知らなかったので、もっと知りたい。
Daniel Kamil Kozar

12
私はこれを探していました。私はこの答えに対する批判を理解していません。問題に対する複数の解決策を見たい。そして、私はawkbashよりもコマンドを好む人です(他に何もない場合、awkは他のシェルで動作するため)。私はこのソリューションがより好きでした。しかし、それは私の個人的な意見です。
rpsml 2014年

4
先行ゼロ:echo $((END-START))| awk '{printf "%02d:%02d \ n"、int($ 1/60)、int($ 1%60)}'
Jon Strayer

17

別のオプションは使用することですdatediffからdateutilshttp://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

も使用できますgawkmawk1.3.4もありstrftimemktimeのが、旧バージョン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

1
私はあなたのGNU date メソッドのようなものを探していました。天才。
Haohmaru 2017

私のコメントを削除してください...申し訳ありません
ビル・ガレ

dateutilsapt経由でインストールした後、datediffコマンドはありませんでした-使用する必要がありましたdateutils.ddiff
スザナ

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"

同じ方法でミリ秒も処理できます。

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"

1
ミリセコンを処理する方法はありますか。例:10:3​​3:56.104
Umesh Rajbhandari 2014年

ミリ秒フィールドがゼロで始まる場合、ミリ秒の処理は正しく動作しません。たとえば、ms = "033"は、msフィールドが8進数として解釈されるため、末尾の数字が「027」になります。"echo" ... "+ ms))"を... "+ $ {ms ## +(0)}))"に変更すると、 "shopt -s extglob"がこの上にある限り、これが修正されます。脚本。おそらく、h、m、sから先行ゼロも削除する必要があります...
Eric Towers

3
echo $(((60*60*$((10#$h)))+(60*$((10#$m)))+$((10#$s))))私が得てから私のために働いたvalue too great for base (error token is "08")
Niklas

6

ここにいくつかの魔法があります:

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

seda :を1/60に変換する数式に置き換えます。次に、bc


5

現在(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

3

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"

3

または少し包みます

alias timerstart='starttime=$(date +"%s")'
alias timerstop='echo seconds=$(($(date +"%s")-$starttime))'

その後、これは機能します。

timerstart; sleep 2; timerstop
seconds=2

3

以下は、date「ago」を使用してコマンド機能のみを使用し、2番目の変数を使用して終了時間を格納しないソリューションです。

#!/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

2
% start=$(date +%s)
% echo "Diff: $(date -d @$(($(date +%s)-$start)) +"%M minutes %S seconds")"
Diff: 00 minutes 11 seconds

6
この回答が他の回答ではできないことを理解することは役に立ちます。
Louis

で許可されている任意の形式で期間を簡単に出力できますdate
ライアンC.トンプソン

2

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 -)


1

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 __name__ == "__main__":
   difftime(sys.argv[1],sys.argv[2])

1

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

1

GNU日付を使用した@nisetamaのソリューションの一般化(信頼できる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

1
#!/bin/bash

START_TIME=$(date +%s)

sleep 4

echo "Total time elapsed: $(date -ud "@$(($(date +%s) - $START_TIME))" +%T) (HH:MM:SS)"
$ ./total_time_elapsed.sh 
Total time elapsed: 00:00:04 (HH:MM:SS)

1

この関数を定義します(〜/ .bashrcなど):

time::clock() {
    [ -z "$ts" ]&&{ ts=`date +%s%N`;return;}||te=`date +%s%N`
    printf "%6.4f" $(echo $((te-ts))/1000000000 | bc -l)
    unset ts te
}

これで、スクリプトの一部の時間を測定できます。

$ cat script.sh
# ... code ...
time::clock
sleep 0.5
echo "Total time: ${time::clock}"
# ... more code ...

$ ./script.sh
Total time: 0.5060

実行のボトルネックを見つけるのに非常に役立ちます。


0

これは古い投稿であることに気づきましたが、ログファイルから日付と時刻を取得して差分を計算するスクリプトを作成しているときに、今日出会いました。以下のスクリプトは確かにやり過ぎです。私のロジックと数学をチェックすることを強くお勧めします。

#!/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.

スクリプトを少し変更してスタンドアロンにしました(つまり、変数値を設定するだけです)が、おそらく一般的なアイデアも出てくるでしょう。負の値をチェックするための追加のエラーチェックが必要になる場合があります。


ジー、たくさんの仕事!!。私の答えを見てください:stackoverflow.com/a/24996647/2350426

0

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 ~]# 

-1

これが私のbash実装です(他のSOからビットを取り出しました;-)

function countTimeDiff() {
    timeA=$1 # 09:59:35
    timeB=$2 # 17:32:55

    # feeding variables by using read and splitting with IFS
    IFS=: read ah am as <<< "$timeA"
    IFS=: read bh bm bs <<< "$timeB"

    # Convert hours to minutes.
    # The 10# is there to avoid errors with leading zeros
    # by telling bash that we use base 10
    secondsA=$((10#$ah*60*60 + 10#$am*60 + 10#$as))
    secondsB=$((10#$bh*60*60 + 10#$bm*60 + 10#$bs))
    DIFF_SEC=$((secondsB - secondsA))
    echo "The difference is $DIFF_SEC seconds.";

    SEC=$(($DIFF_SEC%60))
    MIN=$((($DIFF_SEC-$SEC)%3600/60))
    HRS=$((($DIFF_SEC-$MIN*60)/3600))
    TIME_DIFF="$HRS:$MIN:$SEC";
    echo $TIME_DIFF;
}

$ countTimeDiff 2:15:55 2:55:16
The difference is 2361 seconds.
0:39:21

テストされていません。バグがある可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.