I have 2 variables.
GMDCOMTM which stores the date time Tue Oct 1 13:32:40 2013
GMDRRSTM which stores the date time Tue Oct 2 23:35:33 2013
How do I calculate the difference between the 2 variables in hh:mm:ss format and store
it in 3rd variable.? I dont want to use AWK, SED or PERL. I want to use simple shell
script to do it.
Convert dates to %s ---> seconds since 1970-01-01 00:00:00 UTC.
$ date -d"Tue Oct 2 23:35:33 2013" "+%s"
1380749733
So the thing is to get the difference in seconds between both dates using bc as calculator:
$ d1="Tue Oct 1 13:32:40 2013"
$ d2="Tue Oct 2 23:35:33 2013"
$ echo $(date -d"$d2" "+%s") - $(date -d"$d1" "+%s") | bc
122573
Then you can get it into hours, days, with the great function Stéphane Gimenez indicates in UNIX & Linux:
$ displaytime 122573
1 days 10 hours 2 minutes and 53 seconds
C=$(date -d "Tue Oct 1 13:32:40 2013" +%s)
R=$(date -d "Tue Oct 2 23:35:33 2013" +%s)
T=$(date --date=#$((R-C)) +%H:%M:%S)
I'm normal using a custom made function to do the calculations. It may be long way but it will definitely work on all UNIX and Linux based systems. Following the code block.
time_diff(){
foodate1=$1
foodate2=$2
foosecvall=`echo $foodate1 | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'`
foosecval2=`echo $foodate2 | awk -F: '{ print ($1 * 3600) + ($2 * 60) + $3 }'`
foodiffsec=$((foosecvall-foosecval2));
s=$foodiffsec
h=$((s/3600));
s=$((s-$((h*3600))));
m=$((s/60));
s=$((s-$((m*60))));
footmstm=$h":"$m":"$s
}
Place the above code in your script and then call the function like follows.
TIME1="10:12:14"
TIME2="12:15:14"
time_diff $TIME2 $TIME1
echo $footmstm
Related
I'm running AIX with coreutils 5.0. I need to advance an arbitrary date (or time) as given conformative to ISO-8601 format YYYY-MM-DD hh:mm:ss.
For example:
Value of D1 is: 2017-07-08 19:20:01, and I need to add 30 minutes.
In a modern UNIX-system I could probably write something like
date -d "$D1 + 30 minutes" +'%H:%M'
but, alas, I need it to work on an old AIX.
Try
$ date -d "$(date -d "$D1") + 30 minutes" +'%H:%M'
This works in bash, but not in ksh.
The inner call to date will parse D1 to a date, and present it in date's "native" format.
$ date -d "$D1"
Sat Jul 8 19:20:01 CEST 2017
This output will be used with + 30 minutes to create the date that you want, with the outer call to date.
The inner call to date will be expanded so that
$ date -d "$(date -d "$D1") + 30 minutes" +'%H:%M'
will be equivalent to
$ date -d "Sat Jul 8 19:20:01 CEST 2017 + 30 minutes" +'%H:%M'
which will be
19:50
date -d #$(($(date -d "$D1" +%s) + 30 * 60)) +%H:%M
$(date -d "$D1" +%s) echoes the epoch
$((epoch + value)) calculates the wanted time
date -d#epoch +fmt formats it
If you are running AIX from 2003 you are in dire straits, my friend, but if you only need the time, not the full date, as your question implies, I think #RamanSailopal got us half way there.
echo $D1 | awk -F "[: ]" '{
m = $3+30;
h = ($2+int(m/60)) % 24;
printf("%02i:%02i\n", h, m%60)
}'
awk splits the input in different fields, with the splitter pattern given in the -F argument. The pattern denotes : or space .
The input will be split in
$1 = 2017-07-08
$2 = 19
$3 = 20
$4 = 01
Then the script calculates a fake minute value (that can be more than or equal to 60) and stores it in m. From that value it calculates the hour, modulo 24, and the actual minutes, m modulo 60.
This could fail if you hit a leap second, so if you need second precision at all times, you should use some other method.
Awk solution:
awk -F '[-: ]' '{
ram=(mktime($1" "$2" "$3" "$4" "$5" "$6)+(30*60));
print strftime("%Y-%m-%d %T",ram)
}' <<< "$D1"
Convert the date to a date string using awk's mktime function. Add 30 minutes (30*60) and then convert back to a date string with the required format using strftime.
I have an application using its own log file format. Now I want to get all the lines of logs with certain string values such as "Fatal error" within a certain period of time. The log data format is like the following:
Thread-28689296: Thu Aug 25 15:18:41 2016 [ info ]: abcd efddf
Thread-28689296: Thu Aug 25 15:19:01 2016 [ info ]: xvbdfdre dfdfd
Thread-28689296: Thu Aug 25 15:19:11 2016 [ info ]: Fatal error
Thread-28689296: Thu Aug 25 15:19:41 2016 [ info ]: dfdfdfd
If "now" is Aug 25 15:19:41 2016, I want to find between 15:19:41 and 15:17:41 those lines that have "Fatal error" in my log file. So the current time should be from date and x minutes ago should be from "date x minutes ago" to find certain error messages from the application log.
If I use the following command line:
awk -v Date="$(date "+%b %d %H:%M:%S %Y")" -v Date2="$(date -- date="2
minutes ago" "+%b %d %H:%M:%S %Y")" '$5 > Date && $5 < Date2' log_file |
grep "Fatal error"
the variable "$5" in the condition actually gets the value of minute "17" and "19" in my sample log data but it compares with a date value. So this won't work.
How can I construct the value of time in log timestamp from $3 to $7 fields to compare the value of current time. I m not so familiar with shell scripting.
Thanks for your advice and help in advance.
Can you try this:
#!/bin/sh
Date="$(date "+%b %d %H:%M:%S %Y")"
Date2="$(date --date="2 minutes ago" "+%b %d %H:%M:%S %Y")"
first_line=$(grep -n "$Date2" log_file | awk -F ":" '{print $1}')
last_line=$(grep -n "$Date" log_file | awk -F ":" '{print $1}')
sed -n "${first_line},${last_line}p" log_file | grep "Fatal error"
One in Gnu AWK:
$ cat > check.awk
BEGIN {
start=mktime("2016 8 25 15 19 00") # desired start time. If now, use something like:
# end=strftime("%s"); start=end-120
end=mktime("2016 8 25 15 19 12") # end time for this example
# make text months into numbers:
split("Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",mons,",")
for(i in mons)
mons[mons[i]]=i
}
{
atime=mktime($6" "mons[$3]" "$4" "gensub(/:/," ","g",$5)) # your log time format
}
atime<end && atime>start # && add your desired error messages here
$ awk -f check.awk yer.log
Thread-28689296: Thu Aug 25 15:19:01 2016 [ info ]: xvbdfdre dfdfd
Thread-28689296: Thu Aug 25 15:19:11 2016 [ info ]: Fatal error
In nginx access.log we have time format in GMT timezone. using awk command,converting logs to csv file.
awk '{print $4","$7,"$10","$15","$16","$17}' </usr/local/nginx/logs/access.log>access.csv
$4 - displays date in GMT (31/Jul/2015:16:03:07).
Kindly guide how to change it to IST and update in that csv file.
If you have access to GNU awk and GNU date, you could use TZ to easily get time at IST:
$ TZ='Asia/Kolkata' date -d "#1438374787"
Where the '1438374787' value is the seconds since epoch in GMT, also known as systime.
To make a systime out of a date, we could use mktime from (GNU) awk:
Convert the GMT string to epoch time directly in awk:
$ echo "a test date 31/07/2015:16:33:07" | awk '{gsub("[/:]"," ",$4); $0=$0;t=sprintf("%d %d %d %d %d %d 0",$6,$5,$4,$7,$8,$9);print(mktime(t))}'
For that to work, you need all values to be numbers (no jul, sorry). If that is not possible, you need to work out a format for an string that the command date could read correctly (sometimes not an easy task).
Placing all in one script:
#!/bin/bash --
echo "a test date 31/07/2015:16:33:07" | awk '{
split($4,A,"[:/]");
gmtdate=sprintf("%d %d %d %d %d %d",A[3],A[2],A[1],A[4],A[5],A[6]);
print gmtdate;
T1=mktime(gmtdate);
print T1;
pt = sprintf ("TZ=%s%s%s date -d %s%s%s%s","\047","Asia/Kolkata","\047","\042","#",T1,"\042");
print pt;
system(pt);
}'
And, running it:
$ ./stackoverflow-awk-time-test.sh
2015 7 31 16 33 7
1438374787
TZ='Asia/Kolkata' date -d "#1438374787"
Sat Aug 1 02:03:07 IST 2015
Several additional debug values are printed from awk (easy to remove).
I need to somehow use the date command in bash or another utility to print out the date and time, 5 minutes before and 5 minutes after a given value.
For example:
input:
Thu Dec 19 14:10
output:
Thu Dec 19 14:05 Thu Dec 19 14:10 Thu Dec 19 14:15
I see that the date command can be used to do this on the current date/time, can it be used with a passed value, i.e. not the current date/time?
You can achieve this, for the current time, by typing.
$ date --date='5 minutes ago'; date; date --date='5 minutes'
Qui Dez 19 16:09:17 BRST 2013
Qui Dez 19 16:14:17 BRST 2013
Qui Dez 19 16:19:17 BRST 2013
To use a specific date (ex 1978/01/10).
$ date --date='1978-01-10 + 5 minutes'
Ter Jan 10 00:05:00 BRT 1978
With GNU date, you can do a simple form of date/time arithmetic with the argument to the --date option:
$ date --date 'now + 5 minutes'
With BSD date (at least, the version that ships with Mac OS X), the -v option allows you to do something similar:
$ date -v +5M
$ date -v -5M
If you're using bash under linux, you can use the -d parameter to perform date manipulation on an existing date:
Get the EPOCH time for the date in question:
EPOCH=$(date -d 'Thu Dec 19 14:10' '+%s')
This gives you the time, in seconds, since the EPOCH (typically 01/01/1970)
Now you can use simple math to subtract or add 5 minutes (in seconds) to the EPOCH time
NEW_EPOCH=$(($EPOCH - 300))
obviously, there are 300 seconds in 5 minutes
Now convert this NEW_EPOCH back into a human readable date
NEW_DATE=$(date -d "1970-01-01 ${NEW_EPOCH} sec")
NOTE that this only works on unix systems which support the date -d option (i.e. Linux)
If you want to do this for the current time +/-5 minutes and you use Bash 4.2 or newer, you can do it without external tools:
$ printf -v now '%(%s)T'
$ echo "$now"
1516161094
$ f='%a %b %d %R'
$ printf "%($f)T %($f)T %($f)T\n" "$((now-300))" "$now" "$((now+300))"
Tue Jan 16 22:46 Tue Jan 16 22:51 Tue Jan 16 22:56
The %(datefmt)T formatting string of printf allows to print date-time strings. If the argument is skipped (like here) or is -1, the current time is used.
%s formats the time in seconds since the epoch, and -v now stores the output in now instead of printing it.
f is just a convenience variable so I don't have to repeat the formatting string for the output three times.
Since the argument for this usage of printf has to be in seconds since the epoch, you're stuck with external tools to convert an input string like Thu Dec 19 14:10 into that format and you'd replace
printf -v now '%(%s)T'
with, for example, any of
now=$(date '+%s' -d 'Thu Dec 19 14:10') # GNU date
now=$(date -j -f '%a %b %d %T' 'Thu Dec 19 14:10' '+%s') # macOS date
How would you parse a date in bash, with separate fields (years, months, days, hours, minutes, seconds) into different variables?
The date format is: YYYY-MM-DD hh:mm:ss
Does it have to be bash? You can use the GNU coreutils /bin/date binary for many transformations:
$ date --date="2009-01-02 03:04:05" "+%d %B of %Y at %H:%M and %S seconds"
02 January of 2009 at 03:04 and 05 seconds
This parses the given date and displays it in the chosen format. You can adapt that at will to your needs.
I had a different input time format, so here is a more flexible solution.
Convert dates in BSD/macOS
date -jf in_format [+out_format] in_date
where the formats use strftime (see man strftime).
For the given input format YYYY-MM-DD hh:mm:ss:
$ date -jf '%Y-%m-%d %H:%M:%S' '2017-05-10 13:40:01'
Wed May 10 13:40:01 PDT 2017
To read them into separate variables, I'm taking NVRAM's idea, but allowing you to use any strftime format:
$ date_in='2017-05-10 13:40:01'
$ format='%Y-%m-%d %H:%M:%S'
$ read -r y m d H M S <<< "$(date -jf "$format" '+%Y %m %d %H %M %S' "$date_in")"
$ for var in y m d H M S; do echo "$var=${!var}"; done
y=2017
m=05
d=10
H=13
M=40
S=01
In scripts, always use read -r.
In my case, I wanted to convert between timezones (see your /usr/share/zoneinfo directory for zone names):
$ format=%Y-%m-%dT%H:%M:%S%z
$ TZ=UTC date -jf $format +$format 2017-05-10T02:40:01+0200
2017-05-10T00:40:01+0000
$ TZ=America/Los_Angeles date -jf $format +$format 2017-05-10T02:40:01+0200
2017-05-09T17:40:01-0700
Convert dates in GNU/Linux
On a Mac, you can install the GNU version of date as gdate with brew install coreutils.
date [+out_format] -d in_date
where the out_format uses strftime (see man strftime).
In GNU coreutils' date command, there is no way to explicitly set an input format, since it tries to figure out the input format by itself, and stuff usually just works. (For detail, you can read the manual at coreutils: Date input formats.)
For example:
$ date '+%Y %m %d %H %M %S' -d '2017-05-10 13:40:01'
2017 05 10 13 40 01
To read them into separate variables:
$ read -r y m d H M S <<< "$(date '+%Y %m %d %H %M %S' -d "$date_in")"
To convert between timezones (see your /usr/share/zoneinfo directory for zone names), you can specify TZ="America/Los_Angeles" right in your input string. Note the literal " chars around the zone name, and the space character before in_date:
TZ=out_tz date [+out_format] 'TZ="in_tz" in_date'
For example:
$ format='%Y-%m-%d %H:%M:%S%z'
$ TZ=America/Los_Angeles date +"$format" -d 'TZ="UTC" 2017-05-10 02:40:01'
2017-05-09 19:40:01-0700
$ TZ=UTC date +"$format" -d 'TZ="America/Los_Angeles" 2017-05-09 19:40:01'
2017-05-10 02:40:01+0000
GNU date also understands hour offsets for the time zone:
$ TZ=UTC date +"$format" -d '2017-05-09 19:40:01-0700'
2017-05-10 02:40:01+0000
This is simple, just convert your dashes and colons to a space (no need to change IFS) and use 'read' all on one line:
read Y M D h m s <<< ${date//[-:]/ }
For example:
$ date=$(date +'%Y-%m-%d %H:%M:%S')
$ read Y M D h m s <<< ${date//[-: ]/ }
$ echo "Y=$Y, m=$m"
Y=2009, m=57
$ t='2009-12-03 12:38:15'
$ a=(`echo $t | sed -e 's/[:-]/ /g'`)
$ echo ${a[*]}
2009 12 03 12 38 15
$ echo ${a[3]}
12
The array method is perhaps better, but this is what you were specifically asking for:
IFS=" :-"
read year month day hour minute second < <(echo "YYYY-MM-DD hh:mm:ss")
Pure Bash:
date="2009-12-03 15:35:11"
saveIFS="$IFS"
IFS="- :"
date=($date)
IFS="$saveIFS"
for field in "${date[#]}"
do
echo $field
done
2009
12
03
15
35
11
instead of using the shell scripting,incorporate in your scripting itself like below wheever you need:
a=date +%Y
b=date +%S
c=date +%H
a will be year
b will be seconds
c will be hours. and so on.
Another solution to the OP's problem:
IFS=' -:' read y m d h m s<<<'2014-03-26 16:36:41'
Converting a date to another format with BSD date and GNU date:
$ LC_ALL=C date -jf '%a %b %e %H:%M:%S %Z %Y' 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T
2014-03-26 16:36:41
$ gdate -d 'Wed Mar 26 16:36:41 EET 2014' +%F\ %T
2014-03-26 16:36:41
GNU date recognizes Wed and Mar even in non-English locales but BSD date doesn't.
Converting seconds since epoch to a date and time with GNU date and BSD date:
$ gdate -d #1234567890 '+%F %T'
2009-02-14 01:31:30
$ date -r 1234567890 '+%F %T'
2009-02-14 01:31:30
Converting seconds to hours, minutes, and seconds with a POSIX shell, POSIX awk, GNU date, and BSD date:
$ s=12345;printf '%02d:%02d:%02d\n' $((s/3600)) $((s%3600/60)) $((s%60))
05:25:45
$ echo 12345|awk '{printf "%02d:%02d:%02d\n",$0/3600,$0%3600/60,$0%60}'
05:25:45
$ gdate -d #12345 +%T
05:25:45
$ date -r 12345 +%T
05:25:45
Converting seconds to days, hours, minutes, and seconds:
$ t=12345678
$ printf '%d:%02d:%02d:%02d\n' $((t/86400)) $((t/3600%24)) $((t/60%60)) $((t%60))
142:21:21:18
another pure bash
$ d="2009-12-03 15:35:11"
$ d=${d//[- :]/|}
$ IFS="|"
$ set -- $d
$ echo $1
2009
$ echo $2
12
$ echo $#
2009 12 03 15 35 11
have you tried using cut?
something like this:
dayofweek=date|cut -d" " -f1