बैश स्क्रिप्ट में बीते हुए समय की गणना कैसे करें?


224

मैं प्रारंभ और समाप्ति समय का उपयोग करके प्रिंट करता हूं date +"%T", जिसके परिणामस्वरूप कुछ इस तरह होता है:

10:33:56
10:36:10

मैं इन दोनों के बीच अंतर की गणना और प्रिंट कैसे कर सकता हूं?

मैं कुछ प्राप्त करना चाहूंगा:

2m 14s

5
एक और नोट पर, क्या आप timeकमांड का उपयोग नहीं कर सकते थे ?
ऐशसेन

इसके बजाय यूनिक्स समय का उपयोग करें date +%s, फिर सेकंड में अंतर प्राप्त करने के लिए घटाएं।
4

जवाबों:


476

बैश में एक आसान बनाया गया SECONDSचर है जो शेल शुरू होने के बाद से गुजरने वाले सेकंड की संख्या को ट्रैक करता है। असाइन किए जाने पर यह चर अपने गुणों को बरकरार रखता है, और असाइनमेंट के बाद लौटाया गया मान असाइन किए गए प्लस के बाद से सेकंड की संख्या है।

इस प्रकार, आप SECONDSसमयबद्ध घटना को शुरू करने से पहले बस 0 पर सेट कर सकते हैं , बस SECONDSघटना के बाद पढ़ सकते हैं , और प्रदर्शित होने से पहले समय अंकगणित कर सकते हैं।

SECONDS=0
# do some work
duration=$SECONDS
echo "$(($duration / 60)) minutes and $(($duration % 60)) seconds elapsed."

चूंकि यह समाधान निर्भर नहीं करता है date +%s(जो कि एक GNU एक्सटेंशन है), यह बैश द्वारा समर्थित सभी प्रणालियों के लिए पोर्टेबल है।


59
+1। संयोग से, आप dateलिखकर, आपके लिए समय अंकगणितीय प्रदर्शन कर सकते हैं date -u -d @"$diff" +'%-Mm %-Ss'। (यह $diffसेकंड-ए-द-युग के रूप में व्याख्या करता है, और यूटीसी में मिनटों और सेकंडों की गणना करता है।) यह शायद कोई और अधिक सुरुचिपूर्ण नहीं है, हालांकि, बस बेहतर रूप से निषिद्ध है। :-P
23

13
अच्छा और सरल। कोई घंटे की जरूरत है:echo "$(($diff / 3600)) hours, $((($diff / 60) % 60)) minutes and $(($diff % 60)) seconds elapsed."
Chus

6
यह $(date -u +%s)उन तारीखों पर एक दौड़ की स्थिति को रोकने के लिए पढ़ना चाहिए जहां दिन के समय की बचत स्विच की जाती है। और दुष्ट छलांग सेकंड से सावधान रहें;)
टीनो

3
@ डानियल-कामिल-कोजार अच्छा लगता है। हालांकि यह थोड़ा नाजुक है। केवल एक ऐसा वैरिएबल है, इसलिए इसे प्रदर्शन को मापने के लिए पुनरावर्ती रूप से उपयोग नहीं किया जा सकता है, और इससे भी खराब होने के बाद, unset SECONDSयह खत्म हो गया है:echo $SECONDS; unset SECONDS; SECONDS=0; sleep 3; echo $SECONDS
टीनो

6
@ParthianShot: मुझे खेद है कि आप ऐसा सोचते हैं। हालांकि, मेरा मानना ​​है कि यह उत्तर वही है, जो ज्यादातर लोगों को इस तरह के एक प्रश्न के उत्तर की खोज करते समय चाहिए: यह मापने के लिए कि घटनाओं के बीच कितना समय बीत गया, समय की गणना करने के लिए नहीं।
डैनियल कामिल कोजार

99

सेकंड

बीते हुए समय (सेकंड में) को मापने के लिए हमें चाहिए:

  • एक पूर्णांक जो बीते हुए सेकंड की गिनती का प्रतिनिधित्व करता है और
  • इस तरह के पूर्णांक को एक प्रयोग करने योग्य प्रारूप में बदलने का तरीका।

बीता हुआ सेकंड का पूर्णांक मान:

  • बीते हुए सेकंड की संख्या के लिए पूर्णांक मान ज्ञात करने के लिए दो बाश आंतरिक तरीके हैं:

    1. बैश वैरिएबल 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. बैश प्रिंटफ विकल्प %(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 ))

ऐसे पूर्णांक को एक प्रयोग करने योग्य प्रारूप में बदलें

बैश आंतरिक 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)। संबद्ध तर्क ईपॉच , या -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 दिनांक) का उपयोग कई तरीकों से करना चाहिए, लगभग एक साल की लंबाई तक और नैनोकंडों सहित।

तारीख के अंदर गणित।

बाहरी अंकगणित की कोई आवश्यकता नहीं है, यह सब एक चरण में करें date:

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

हां, 0कमांड स्ट्रिंग में एक शून्य है। इसकी जरूरत है।

यह मानकर कि आप date +"%T"कमांड को कमांड में बदल सकते हैं date +"%s"इसलिए मान सेकंड में संग्रहीत (मुद्रित) होंगे।

ध्यान दें कि कमांड निम्न तक सीमित है:

  • $StartDateऔर $FinalDateसेकंड के सकारात्मक मूल्य ।
  • मान $FinalDateइससे बड़ा (बाद में समय में) है $StartDate
  • 24 घंटे से कम समय का अंतर।
  • आप घंटे, मिनट और सेकंड के साथ एक आउटपुट स्वरूप स्वीकार करते हैं। बदलना बहुत आसान है।
  • यह यू यूटीसी समय का उपयोग करने के लिए स्वीकार्य है। "डीएसटी" और स्थानीय समय सुधार से बचने के लिए।

आप तो चाहिए का उपयोग 10:33:56स्ट्रिंग, ठीक है, बस इसे सेकंड, में बदलने का
भी, शब्द सेकंड सेकंड के रूप में संक्षिप्त किया जा सकता है:

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 के रूप में देखें। यह मुश्किल नहीं है ...

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


बिजीबॉक्स डेट

छोटे उपकरणों में उपयोग किया जाने वाला एक उपकरण (स्थापित करने के लिए एक बहुत छोटा निष्पादन योग्य): बिजीबॉक्स।

या तो व्यस्त समय की तारीख के लिए एक लिंक बनाएं:

$ ln -s /bin/busybox date

फिर इसे कॉल करके date(इसे PATH शामिल निर्देशिका में रखें) का उपयोग करें।

या एक उपनाम बनाएं जैसे:

$ alias date='busybox date'

बिजीबॉक्स डेट का एक अच्छा विकल्प है: -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

बिजीबॉक्स की तारीख भी समय प्राप्त कर सकते हैं (ऊपर प्रारूप में) बिना -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

दोनों समय के लिए, और थोड़ा बैश गणित (बिजीबॉक्स गणित नहीं कर सकता, फिर भी):

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
यह एक ऐसा अद्भुत जवाब है जिसमें बहुत सारे आधार शामिल हैं और ठीक व्याख्याओं के साथ। धन्यवाद!
देवी जु

मुझे बैश में एकीकृत कमांड %(FORMAT)Tको दिए गए स्ट्रिंग को देखना था printf। से bash-hackers.org : %(FORMAT)Tउत्पादन तिथि-समय स्ट्रिंग का उपयोग से उत्पन्न FORMATstrftime (3) के लिए एक प्रारूप स्ट्रिंग के रूप में। संबद्ध तर्क एपोच के बाद से सेकंड की संख्या है, या -1 (वर्तमान समय) या -2 (शेल स्टार्टअप समय)। यदि कोई संगत तर्क आपूर्ति नहीं करता है, तो वर्तमान समय का उपयोग डिफ़ॉल्ट के रूप में किया जाता है । यह गूढ़ है। इस मामले में, %sजैसा strftime(3)कि "युग के बाद से सेकंड की संख्या" है।
डेविड टोनहोफर

35

यहाँ देखें कि मैंने यह कैसे किया:

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

वास्तव में सरल, शुरू में सेकंड की संख्या लें, फिर अंत में सेकंड की संख्या लें, और मिनट: सेकंड में अंतर प्रिंट करें।


6
यह मेरे समाधान से कैसे अलग है? मैं वास्तव awkमें इस मामले में कॉल करने से लाभ नहीं देख सकता , क्योंकि बैश पूर्णांक अंकगणित को समान रूप से संभालता है।
डैनियल कामिल कोजार

1
आपका उत्तर भी सही है। कुछ लोग, मेरी तरह, बैश विसंगतियों की तुलना में जाग के साथ काम करना पसंद करते हैं।
डोरियन

2
क्या आप पूर्णांक अंकगणितीय के बारे में बैश में विसंगतियों के बारे में कुछ और बता सकते हैं? मैं इसके बारे में अधिक जानना चाहता हूं, क्योंकि मुझे किसी की जानकारी नहीं थी।
डैनियल कामिल कोजार

12
मैं बस यही ढूंढ रहा था। मुझे इस उत्तर की आलोचना समझ में नहीं आती। मैं एक समस्या का एक से अधिक समाधान देखना पसंद करता हूं। और, मैं वह हूं जो awkबैश करने की आज्ञा देता है (यदि कुछ और नहीं, क्योंकि अन्य गोले में awk काम करता है)। मुझे यह समाधान बेहतर लगा। लेकिन यह मेरी निजी राय है।
आरपीएस

4
अग्रणी शून्य: प्रतिध्वनि $ ((END-START)) | awk '{printf "% 02d:% 02d \ n", int ($ 1/60), int ($ 1% 60)}'
जॉन स्ट्रायर

17

एक अन्य विकल्प ( http://www.fresse.org/dateutils/#datediff ) 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

आप भी इस्तेमाल कर सकते हैं gawkmawk1.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

1
मैं आपके GNU date मेथड की तरह कुछ ढूंढ रहा था । प्रतिभा।
होहमारू

कृपया मेरी टिप्पणी हटाएं ... क्षमा करें
बिल आंधी

Apt के dateutilsमाध्यम से स्थापित करने के बाद , कोई 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: 33: 56.104
उमेश

यदि मिलीसेकंड फ़ील्ड शून्य से शुरू होती है, तो मिलीसेकंड हैंडलिंग दुर्व्यवहार करता है। उदाहरण के लिए ms = "033" "027" का अनुगामी अंक देगा क्योंकि ms क्षेत्र को अष्टक के रूप में व्याख्या किया जा रहा है। "इको" ... "+ एमएस))" से ... "+ $ {एमएस ## + (0)}))" जब तक "शॉप-एक्स एक्सग्लोब" तब तक इसे ठीक कर देगा, तब तक यह कहीं से भी ऊपर दिखाई देगा। स्क्रिप्ट। एक को शायद 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")
निकलस

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

sed:1/60 में बदलने के सूत्र के साथ बदलता है । फिर समय गणना जो द्वारा की जाती हैbc


5

दिनांक (GNU कोरुटिल्स) 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

डैनियल कामिल कोजार के जवाब के बाद, घंटे / मिनट / सेकंड दिखाने के लिए:

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"पहले" का उपयोग करके केवल कमांड क्षमताओं का उपयोग करके समाधान है , और अंतिम समय को संग्रहीत करने के लिए दूसरे चर का उपयोग नहीं किया गया है:

#!/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
यह जानना उपयोगी होगा कि यह उत्तर क्या करता है कि अन्य उत्तर क्या नहीं करते हैं।
लुई

यह आपको आसानी से किसी भी प्रारूप में अवधि की अनुमति देता है date
रयान सी। थॉम्पसन

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सापेक्ष) उपयोग के लिए एक समय अंतर स्क्रिप्ट की आवश्यकता थी , और मेरा समाधान पायथन स्क्रिप्ट को कॉल करना है:

$ ./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 के बीच का अंतर 1h 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 दिनांक (भरोसेमंद Ubuntu 14.04 LTS) का उपयोग कर @ nisetama के समाधान को सामान्य बनाना:

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 के उत्तर पर टिप्पणी नहीं कर सकता, इसलिए मैं यहां यह पोस्ट करता हूं। "भिन्न" चर छोटे मामले पर होना चाहिए। यहाँ एक उदाहरण है।

[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

यहाँ मेरा बैश इम्प्लीमेंटेशन है (दूसरे 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

परीक्षण नहीं, छोटी गाड़ी हो सकती है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.