Multiple dates are not working with epoch comparison in bash - bash

printf "%s\n" "$EXPDATES"
Jul 12 2019 12:00:00
Jul 12 2019 12:00:00
Jul 12 2019 12:00:00
Jun 18 2019 12:00:00
Aug 8 2019 12:00:00
May 8 2018 00:00:00
The above o/p I'm getting from "for loop" and passing all the dates (including one empty line) in same format to another "for loop" to convert and compare with current "epoch".
curr_epoch=$(date +%s)
for expdate in "${EXPDATES[#]}"; do
exp_epoch=$(date +%s -d "$expdate")
if (( curr_epoch > exp_epoch )); then
echo "$expdate in future."
else
echo "$expdate in past."
fi
done
Here I'm not getting proper output for all the dates. "$expdate" in echo line doesn't return anything.
I'm not sure whether for-loop is comparing all the dates.
Can anyone please tell me how to compare all the dates and show output with all the dates compared?

You are missing ending quotes for the echo lines in your code. This will work:
for expdate in "${EXPDATES[#]}"; do
exp_epoch=$(date +%s -d "$expdate")
if (( curr_epoch > exp_epoch )); then
echo "$expdate in future."
else
echo "$expdate in past."
fi
done

Related

How to compare dates formatted as `Tue Aug 30 12:01:37 GMT 2022` in BusyBox/Alpine

In shell (no bash because of Alpine) using BusyBox, how can I compare two dates both formatted as Tue Aug 30 12:01:37 GMT 2022?
I want to know which one comes first. date doesn't support this input format. I'm only interested in whole days. The time isn't interesting for me. So two dates on the same day but a different time are equal to me.
Of course I could put all the names of the months in a lookup table and use the index of the month as its integer value (to be able to compare) but I have the feeling I shouldn't be the one programming that out...
Update:
/opt/scripts $ a="Tue Aug 30 12:01:37 GMT 2022"
/opt/scripts $ date -d "$a" +%s
date: invalid date 'Tue Aug 30 12:01:37 GMT 2022'
/opt/scripts $ date --help
BusyBox v1.34.1 (2022-04-04 10:19:27 UTC) multi-call binary.
Usage: date [OPTIONS] [+FMT] [[-s] TIME]
Display time (using +FMT), or set time
-u Work in UTC (don't convert to local time)
[-s] TIME Set time to TIME
-d TIME Display TIME, not 'now'
-D FMT FMT (strptime format) for -s/-d TIME conversion
-r FILE Display last modification time of FILE
-R Output RFC-2822 date
-I[SPEC] Output ISO-8601 date
SPEC=date (default), hours, minutes, seconds or ns
Recognized TIME formats:
#seconds_since_1970
hh:mm[:ss]
[YYYY.]MM.DD-hh:mm[:ss]
YYYY-MM-DD hh:mm[:ss]
[[[[[YY]YY]MM]DD]hh]mm[.ss]
'date TIME' form accepts MMDDhhmm[[YY]YY][.ss] instead
/opt/scripts $
Install dateutils https://pkgs.alpinelinux.org/package/edge/community/x86/dateutils . Use strptime to convert the date to seconds. Compare seconds.
apk add dateutils
a=$(strptime -f %s -i "%a %b %d %T %Z %Y" "Tue Aug 30 12:01:37 GMT 2022")
b=$(strptime -f %s -i "%a %b %d %T %Z %Y" "Tue Aug 30 12:01:38 GMT 2022")
[ "$a" -lt "$b")
You may have to rely on awk:
/ # cat /etc/alpine-release
3.16.0
/ # echo $a
Tue Aug 30 12:01:37 GMT 2022
/ # TZ=GMT awk -v a="$a" 'BEGIN {
> split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec", months)
> split(a, date)
> gsub(/:/, " ", date[4])
>
> for (i=1; i<=12; i++) {
> if (date[2] == months[i]) {
> timestamp = date[6] " " i " " date[3] " " date[4]
> print mktime(timestamp)
> exit
> }
> }
>
> print "hmm, " date[2] " is an unknown month"
> exit 1
> }'
1661860897
Ok, my alpine busybox copy of date doesn't recognize strings as month either.
You want "slick", stick with Glenn's awk solution, so long as the time functions work for you. I hacked out the least-slick kluge using just echo, date, read, if's, and a lot of tempfiles - it's an ugly mess, but it works, and it was a fun exercise in using only the most basic stuff.
/tmp $ ./script
#! /bin/sh
cat "$0"
cd /tmp
echo "01">Jan
echo "02">Feb
echo "03">Mar
echo "04">Apr
echo "05">May
echo "06">Jun
echo "07">Jul
echo "08">Aug
echo "09">Sep
echo "10">Oct
echo "11">Nov
echo "12">Dec
echo "Tue Aug 30 12:01:37 GMT 2022">a_raw
read -r a_raw<a_raw
echo "Fri Jun 3 09:26:55 CDT 2022">b_raw
read -r b_raw<b_raw
read -r _ Mon DD tim z YYYY<a_raw
read -r MM<"$Mon"
date -d "$YYYY-$MM-$DD" +"%s">a_epoch
read -r a_epoch<a_epoch
read -r _ Mon DD tim z YYYY<b_raw
read -r MM<"$Mon"
date -d "$YYYY-$MM-$DD" +"%s">b_epoch
read -r b_epoch<b_epoch
if [ "$a_epoch" -lt "$b_epoch" ]
then echo "$a_raw ($a_epoch) is before $b_raw ($b_epoch)"
else if [ "$a_epoch" -gt "$b_epoch" ]
then echo "$a_raw ($a_epoch) is after $b_raw ($b_epoch)"
else if [ "$a_epoch" -eq "$b_epoch" ]
then echo "$a_raw ($a_epoch) is same as $b_raw ($b_epoch)"
fi
fi
fi
rm Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec a_raw b_raw a_epoch b_epoch
Tue Aug 30 12:01:37 GMT 2022 (1661817600) is after Fri Jun 3 09:26:55 CDT 2022 (1654214400)
original
What do you mean "date doesn't support this input format"?
Something like this ought to work in sh, though I confess I don't have an alpine handy...
a="Tue Aug 30 12:01:37 GMT 2022"
b="Fri Jun 3 09:26:55 CDT 2022"
a_epoch=`date -d "$a" +%s`
b_epoch=`date -d "$b" +%s`
echo "A: [$a] ($a_epoch)"
echo "B: [$b] ($b_epoch)"
if [ "$a_epoch" -lt "$b_epoch" ]; then echo "$a is before $b"; fi
if [ "$a_epoch" -gt "$b_epoch" ]; then echo "$a is after $b"; fi
if [ "$a_epoch" -eq "$b_epoch" ]; then echo "$a is same as $b"; fi
Should say something like
A: [Tue Aug 30 12:01:37 GMT 2022] (1661860897)
B: [Fri Jun 3 09:26:55 CDT 2022] (1654266415)
Tue Aug 30 12:01:37 GMT 2022 is after Fri Jun 3 09:26:55 CDT 2022
There are cleaner ways, but this should get you started.
Lemme spin up a container and try there, brb...

cutting out the hour part (not in 24 hour time) of a date?

My problem is with cutting the hour portion of the date out.
I am not allowed to use date commands only cut!!!!!
Suppose the date command at that time reads
Tues Apr 26 17:07:49 PDT 2017
then it should print out
5:07
I am having a lot of trouble because it is not recognizing a read on an int but rather a string. Been bugging me a long time now...
Here is my code thus far:
today=$(date)
echo The date right now is "$today"
echo "The time right now is $(printf '%s\n' "$today" | cut -c 11-19)"
let hour=${today:11:2}
let minute=${today:13:2}
if [[ ${hour} -ge 43200 ]]
then
let answer=hour-12
echo "The correct time is $answer:$minute pm"
fi
I calculated 43200 from the number of seconds at 12:00pm
Current output is:
The date right now is Wed Apr 26 21:47:39 PDT 2017
The time right now is 21:47:39
let hour=${today:11:2}
let minute=${today:13:2}
You have the following string format (with positions):
1 2
0123456789012345678901234567
Wed Apr 26 21:47:39 PDT 2017
^ ^
That means the two characters at offset 11 are 17 (correct) but the minute is being extracted at offset 13, which is :0. The correct extraction for minute would be ${today:14:2}.

How to change the date format by storing the input in a variable in unix? [duplicate]

This question already has answers here:
How to convert date format for two datetime in bash?
(2 answers)
Closed 6 years ago.
My Input is
./file \[10\/04\/16 01:02:03 BST\] \[06\/08\/16 05:02:08 BST\]
I want to convert \[10\/04\/16 01:02:03 BST\] to Apr 10 16 01:02:03
I am using the following code,
echo '\[10\/04\/16 01:02:03 BST\]' | awk -F'[][/: \\\\]+' 'BEGIN{split("Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec",m,/ /)} {print m[$3+0],$2,$4,$5":"$6":"$7}'
Is it possible to extract the result by storing \[10\/04\/16 01:02:03 BST\] in a variable like $StartTime and use it in the code? Also now I am using only one date. Is it possible to use two dates?
You can use this date conversion script called script.sh:
#!/bin/bash
mydt() {
IFS='/' read -ra arr <<< "${1//[\[\]\\]}"
TZ=':Europe/London' date -d "${arr[1]}/${arr[0]}/${arr[2]}" '+%b %d %y %T'
}
var1="$(mydt "$1")"
var2="$(mydt "$2")"
echo "$var1"
echo "$var2"
Then call it as:
bash script.sh '\[10\/04\/16 01:02:03 BST\]' '\[06\/08\/16 05:02:08 BST\]'
Output:
Apr 10 16 01:02:03
Aug 06 16 05:02:08

I want to convert 18-Aug-2015 date format to '2015-08-18' using shell script

I want to convert 18-Aug-2015 date format to '2015-08-18' using shell script
Try this formatting:
$ date +"%Y-%m-%d"
http://www.cyberciti.biz/faq/linux-unix-formatting-dates-for-display/
The -d option is GNU specific.
Here, you don't need to do date calculation, just rewrite the string which already contains all the information:
a=$(printf '%s\n' "$Prev_date" | awk '{
printf "%04d-%02d-%02d\n", $6, \
(index("JanFebMarAprMayJunJulAugSepOctNovDec",$2)+2)/3,$3}')
Without awk, assuming your initial date is in $mydate:
IFS=- d=($mydate)
months=(Zer Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
z=1
while [[ ${months[$z]} != ${d[1]} ]]; do z=$((z+1)); done
printf "%s-%02d-%s\n" ${d[2]} $z ${d[0]}

date comparison not working properly in shell script

I want to compare dates in shell script.
The logic I am using as below :
$date_1="Tue Nov 25 23:50:01 CST 2014"
$date_2=$(date)
if [ $date_2 -eq $date_1 ] ; then
echo "$date2 is equal to $date_1"
else
echo "$date2 is not equal to $date_1"
fi
However when I am executing the script using crontab for every minute,
I got the below message in log which is not correct :
Tue Nov 25 23:50:01 CST 2014 is not equal to Tue Nov 25 23:50:01 CST 2014
Could you please help me out of this embarrassing situation?
Assuming this job is running every minute. You can do:
date_1="Tue Nov 25 23:50:01 CST 2014"
dt1=$(date -d "$date_1" '+%Y%m%d%H%M')
dt2=$(date '+%Y%m%d%H%M')
if [ "$dt1" -eq "$dt2" ]; then
echo "$dt2 is equal to $date_1"
else
echo "$dt2 is not equal to $date_1"
fi
Best thing would be to format your date strings to look like numbers, starting with year, then month, etc. You probably would want to code a greater than or equal, or less than or equal, in case cron skips a second now or then:
date_1=$(date +%Y%m%d%H%M%S)
sleep 10
date_2=$(date +%Y%m%d%H%M%S)
if [ $date_2 -ge $date_1 ] ; then
echo "$date_2 is greater than or equal to $date_1"
else
echo "$date_2 is less than $date_1"
fi
Output:
20141126063044 is greater than or equal to 20141126063034
Beware you don't want the $ in front of the variable when you are setting it!

Resources