rplee
rplee

Reputation: 203

Calculate the difference between two timestamps in bash

I want to find out total system boot time by subtracting two timestamps. First I use this command to get the start time and end time:

sudo journalctl | grep "Logs begin at" | awk '{print $6" "$7" "$12" "$13}'

which gets me the following output:

2020-05-21 05:52:47 2020-05-28 19:37:36

(The first two fields being the start time and the last two fields being the end time)

Now I want to find the difference between the start time and end time, preferably in the format:

"0 year(s), 0 month(s), 7 day(s), HH:MM:SS"

Upvotes: 10

Views: 19606

Answers (4)

Trevor Boyd Smith
Trevor Boyd Smith

Reputation: 19223

when the datetime string is printed on each line and you need millisecond or microsecond time delta i use python:

placeholder | sed 's/.*\(regex\).*/\1/g' | python3 -c "
import datetime
import sys
contents = sys.stdin.read().strip()
lines = contents.splitlines()
# remove nanoseconds and 'Z'
lines = [line[:-4] for line in lines]
fmt = '%Y-%m-%dT%H:%M:%S.%f'
dtimes = [datetime.datetime.strptime(line) for line in lines]
deltas = [(dt1 - dt0) in zip(dtimes[1:], dtimes[0:-1])]
import pprint
pprint.pprint(deltas)
"

Upvotes: 0

JesusValera
JesusValera

Reputation: 647

Same version as @chemaclass but this time for Ubuntu (16.04 LTS).

#!/usr/bin/env bash
echo "BASH_VERSION:" $BASH_VERSION 

line="2020-05-21 05:52:47;2020-05-28 19:37:36"
IFS=';' read -a dates <<< $line
startDatetime=${dates[0]}
endDatetime=${dates[1]}

echo "| dates -> " ${dates[@]}
echo "|> startDatetime -> ${startDatetime}"
echo "|> endDatetime -> ${endDatetime}"


startTime=$(date -d "${startDatetime}" +%s)
endTime=$(date -d "${endDatetime}" +%s)
diffSeconds="$(($endTime-$startTime))"

echo "Diff in seconds: $diffSeconds"
# at this point you have the diff in seconds and you can parse it however you want :)

diffTime=$(date -d @${diffSeconds} +"%H:%M:%S" -u)
echo "Diff time(H:M:S): $diffTime"

Output:

BASH_VERSION: 5.0.0(1)-release
| dates ->  2020-05-21 05:52:47 2020-05-28 19:37:36
|> startDatetime -> 2020-05-21 05:52:47
|> endDatetime -> 2020-05-28 19:37:36
Diff in seconds: 654289
Diff time(H:M:S): 13:44:49

I updated the bash to version 5.0.0 following this tutorial. With the default bash version (4.4.20) doesn't work. You will get an error message like: redirection unexpected on line 3 because of the <<< symbol.

Upvotes: 5

Chemaclass
Chemaclass

Reputation: 2011

What about this?

#!/usr/bin/env bash
echo "BASH_VERSION:" $BASH_VERSION 

line="2020-05-21 05:52:47;2020-05-28 19:37:36"
IFS=';' read -a dates <<< $line
startDatetime=${dates[0]}
endDatetime=${dates[1]}

echo "| dates -> " ${dates[@]}
echo "|> startDatetime -> ${startDatetime}"
echo "|> endDatetime -> ${endDatetime}"

startTime=$(date -jf "%Y-%m-%d %H:%M:%S" "${startDatetime}" +%s)
endTime=$(date -jf "%Y-%m-%d %H:%M:%S" "${endDatetime}" +%s)
diffSeconds="$(($endTime-$startTime))"

echo "Diff in seconds: $diffSeconds"
# at this point you have the diff in seconds and you can parse it however you want :)

diffTime=$(gdate -d@${diffSeconds} -u +%H:%M:%S) # you'll need `brew install coreutils`
echo "Diff time(H:M:S): $diffTime"

Output:

BASH_VERSION: 5.0.17(1)-release
| dates ->  2020-05-21 05:52:47 2020-05-28 19:37:36
|> startDatetime -> 2020-05-21 05:52:47
|> endDatetime -> 2020-05-28 19:37:36
Diff in seconds: 654289
Diff time(H:M:S): 13:44:49

To install the latest bash I found this medium post.

Note: If this doesn't work because some version incompatibilities with the date function, for example, the idea should be pretty similar and you could find a workaround that adapts to your current version, I'm sure. Logically, the easiest solution I see is:

1st) Split the string into two: one for each DateTimes.

2nd) Transform each DateTime from string to dates.

3rd) Apply a diff between these dates: using the seconds from each.

4th) Having the diff seconds you can display it as you want (year, days, minutes, seconds)

Upvotes: 9

U880D
U880D

Reputation: 12008

A possible approach could be

#!/bin/bash

strSTARTTIME="2020-05-21 05:52:47"
strENDTIME="2020-05-28 19:37:36"

STARTTIME=$(date -d "${strSTARTTIME}" +%s)
ENDTIME=$(date -d "${strENDTIME}" +%s)

RUNTIME=$((ENDTIME-STARTTIME))

echo "Seconds ${RUNTIME} in sec"

Further calculation and formatting I'll leave at your side.

Upvotes: 2

Related Questions