Time calculation in bash - bash

We have a little issue with a time calculation in Bash.
Lets give you a little explaination about the situation up here.
We download every 5 minutes one file from an FTP server. This file contains time information about the data in this file. But the timeformat of the file is in UTC, and our local time is UTC+2. The files contains information about the past 5 minutes from local time. Now we have the following code:
TIMESTAMP=$(echo "$(TZ=UTC date "+%Y%m%d%H%M") - ($(date +%M)%5)-5" | bc)
That works well for several hours but after 55 minutes it becomes a problem. So we dont able to get the files with the 55 minutes, 60 minutes.
So if local time is: 19:47
The file with time 17:40 (utc) is available on the server at 19:45 local time
The time the files are available on the server are not constant too bad...
19:00, 19:05, 19:10 etc... but sometimes the file is one minute later....
This is my crontab file:
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/kbroeren/cronscripts
*/1 * * * * /home/kbroeren/cronscripts/radar >> /home/kbroeren/radar_log.txt 2>&1
*/5 * * * * sudo /usr/bin/python /home/kbroeren/cronscripts/radar_plot.py >>/home/kbroeren/out.txt 2>&1
Is there a better and correct way to do this ?

You seem to be looking for %s:
date +%s
This returns:
%s seconds since 1970-01-01 00:00:00 UTC
You'd need to change the arithmetic a bit, though.

The date command can convert to and from a number of date and time formats. If you want to do arithmetic with dates and times, it's probably easiest to convert to “seconds since the unix epoch”, do the arithmetic, and convert back to the time format of your choice.
You might consider something like:
date --date="#$(echo $(TZ=UTC date +%s) - $(date +%s)'%(5*60)-(5*60)' | bc)"

Related

How to find 30 days older epoch time in ms from current time in shell script?

How do I find epoch time of 30 days from current time in shell script? If my current time is X in epoch milliseconds.Then I need epoch milliseconds of 30 days older in shell script
#!/bin/sh
current=$(date +'%s%3N')
echo $current
oldtimestamp=$((current - 30*24*60*60))
echo "old is $oldtimestamp"
This doesnt seem to give 30 days old epoch ms. Please let me know how to get it. Thanks in advance
The date command supports some natural language expressions:
date +'%s%3N' --date='30 days ago'
Of course, this will be some milliseconds off when compared to ${current} because of the time it takes to execute these commands themselves, but perhaps it's close enough for you.
Otherwise, the correct arithmetic expression is what Jonathan Leffler wrote:
oldtimestamp=$((current - 30*24*60*60*1000))
but note that things like leap seconds may throw you off in that approach.

How can I get the timestamp in days in awk?

I have a file "file_XYZ_18548".
Here the name's ending 18548 is a timestamp in days, and it is changing day by day, like "file_XYZ_18550".
I would like to get this date via variable but I couldn't find a date command to get the timestamp in days.
I can get the date result but I can't get the timestamp in reverse.
timeinday=18550
timestp=timeinday*86400
datetm=$(echo $timestp | gawk '{print(strftime("%Y-%m-%d %H:%M:%S", $0))}')
echo $datetm
2020-10-14 10:09:10
How can I get this with date command in bash scripting? Is there any way of this via awk/gawk etc..?
Given that 2020-10-14 - 18548 days corresponds to 1970-01-03, it is reasonable to guess that the 'epoch' for the day count is 1970-01-01. It is likely that day 1 was 1970-01-01, so day zero was 1969-12-31.
Converting day count to date
You can use the GNU date command like this:
daycount=18548
date -u -d "#$(( ($daycount-1) * 86400 ))" +"%Y-%m-%d %H:%M:%S"
That yields the result 2020-10-12 00:00:00. You can drop the time component of the format if you wish (you probably do; midnight isn't very exciting when it is always midnight). You can calibrate the -1 to resolve exactly what day should correspond to 18548. Just in case it isn't obvious, there are 86,400 seconds in a day (24 hours • 60 minutes per hour • 60 seconds per minute).
The $(( … )) notation is Bash's Arithmetic Expansion notation.
Converting current time to day count
If you want to convert the current time to the day offset, then you can use the %s specifier to get the seconds since 1970-01-01 00:00:00Z and divide by 86400 to get the number of days:
echo $(( $(date +'%s') / 86400 ))
which (at 2020-10-14 23:30 -06:00, aka 1602739800 seconds since the Unix Epoch) yields the result:
18550
Again, if need be, you can adjust the value of the division to account for when day 1 was in this scheme. Shell arithmetic in Bash is integer arithmetic, which is exactly what is wanted. You might need to use -u to get UTC as the time zone (as I did earlier), and so on.

Best way to compare Timestamps in Linux shell/bash script? [duplicate]

This question already has answers here:
Bash script compare two date variables [duplicate]
(5 answers)
Closed 1 year ago.
I have to read a epoch timestamp (in seconds) from a directory /usr/local/healthcheck.txt on my Red Hate Enterprise Linux machine every ~10 minutes (polling). I need perform a comparison on the time to check if the timestamp in the healthcheck.txt file is OLDER than 50 minutes from the current time/timestamp OR if the healthcheck.txt is non-existent, to throw an error. The timestamp in the healthcheck.txt file generally looks like this (its in seconds, as stated above) :
1591783065
I was using date -d #1591783065 to convert the timestamp to Human Readable and get something like this:
Tue Jun 9 16:22:57 UTC 2020
What would be the best approach to compare the current timestamp to this timestamp in the file and check if its older than 50 minutes?
In Java , we have a Date package , and can just use compareTo to compare the times/dates, is there a simple way to do this with shell/bash scripts?
Why don't you stick with epoch-time? You can get the current time as seconds since epoch by
date +%s, so you just have to compare
if (( (healthcheck_time + 50*60) < $(date +%s) ))
then
# .... healthcheck older than 50 minutes
fi

Deriving URLs from date

I would like to automate a download of an image from a third party server with a CRON job and then upload the image to my website.
I have 2 issues:
First, the third party site changes the image name every day using the following logic:
http://thirdpartysite.com/ImageFinder.aspx?ReportID=FILENAME
where FILENAME is 26601 +14 for each day after 6 Oct 2014 (so 7 Oct would be 26615, 8 Oct would be 26629 etc).
How do I build this into a simple Linux bash script for use with wget?
Second, how do I upload this to my site via FTP (or similar) with the same script.
NOTE: I have permission to host the file on my site and have linked the original site / placed credit for the image.
Following the suggestions of #Abhay, first get the timestamp of Oct 6, let's store it in the variable $d0:
d0=$(date +%s -d 20141006)
Then store the timestamp of a target date, say Oct 8 and store it in $d1:
d1=$(date +%s -d 20141008)
Then you can calculate the difference and apply the required arithmetic operations in $((...)), like this:
echo $((26601 + 14 * (d1 - d0) / 60 / 60 / 24))
# outputs: 26629
The date command has one very good format: %s, which prints number of seconds since "epoch", which is the fixed date 1 January 1970, 00:00 UTC. I'll call it "timestamp". In combination with this, you can use the -d date-string, so that it prints the given date as number of seconds. Now you can take today's timestamp, subtract the timestamp of "6 Oct 2014" from it, and you get number of seconds between the two times. Now you can divide it by (60 * 60 * 24) to get it in number of days, and do further arithmetic to get the desired number, and make a file name out of it.
The date string formats that -d option takes are flexible, but as of now I am not sure whether it takes "6 Oct 2014" as is. Try a few permutations, or better, check the "info" page.

Text-Message Gateways & Incrementing Bash Variable Daily

I have a bash script that is sending me a text daily, for 100 days.
#! /bin/bash
EMAIL="my-phone-gateway#address.net"
MESSAGE="message_content.txt"
mail $EMAIL < $MESSAGE
Using crontab, I can have the static $MESSAGE sent to me every day.
Other than hard-coding 100 days of texts ;)
How could I implement a variable counter such that I can have my texts say:
"Today is Day #1" on the first day, "Today is Day #2" on the second day, etc. ?
Note: The location of the requested text within the $MESSAGE file doesn't matter. Last line, first line, middle, etc.
The only requirement for an answer here is that I know what day it is relative to the first, where the first day is the day the script was started.
Of course, bonus awesome points for the cleanest, simplest, shortest solution :)
For our nightly build systems, I wrote a C program that does the calculation (using local proprietary libraries that store dates as a number of days since a reference date). Basically, given a (non-changing) reference date, it reports the number of days since the reference date. So, the cron script would have a hard-wired first day in it, and the program would report the number of days since then.
The big advantage of this system is that the reference date doesn't change (very often), so the script doesn't change (very often), and there are no external files to store information in.
There probably are ways to achieve the same effect with standard Unix tools, but I've not sat down and worked out the portable solution. I'd probably think it terms of using Perl. (The C program only works up to 2999 CE; I left a note in the code for people to contact me about 50 years before it becomes a problem for the Y3K fix. It is probably trivial.)
You could perhaps work in terms of Unix timestamps...
Create a script 'days_since 1234567890' which treats the number as the reference date, gets the current time stamp (from date with appropriate format specification; on Linux, date '+%s' would do that job, and it works on Mac OS X too), takes the difference and divides by 86,400 (the number of seconds in a day).
refdate=1234567890
bc <<EOF
scale=0
($(date '+%s') - $refdate) / 86400
EOF
An example:
$ timestamp 1234567890
1234567890 = Fri Feb 13 15:31:30 2009
$ timestamp
1330027280 = Thu Feb 23 12:01:20 2012
$ refdate=1234567890
$ bc <<EOF
> scale=0
> ($(date '+%s') - $refdate) / 86400
> EOF
1104
$
So, if the reference date was 13th Feb 2009, today is day 1104. (The program bc is the calculator; its name has nothing to do with Anno Domini or Before Christ. The program timestamp is another homebrew of mine that prints timestamps according to a format that can be specified; it is a specialized variant of date originally written in the days before date had the functionality, by which I mean in the early 1980s.)
In a Perl one-liner (assuming you specify the reference date in your script):
perl -e 'printf "%d\n", int((time - 1234567890)/ 86400)'
or:
days=$(perl -e 'printf "%d\n", int((time - 1234567890)/ 86400)')
The only way to accomplish this would be to store the date in a file, and read from that file each day. I would suggest storing the epoch time.
today=$(date +%s)
time_file="~/.first_time"
if [[ -f $time_file ]]; then
f_time=$(< "$time_file")
else
f_time=$today
echo "$f_time" > "$time_file"
fi
printf 'This is day: %s\n' "$((($today - $f_time) / 60 / 60 / 24))"
Considering that your script is running only once a day, something like this should work:
#!/bin/bash
EMAIL="my-phone-gateway#address.net"
MESSAGE="message_content.txt"
STFILE=/tmp/start.txt
start=0
[ -f $STFILE ] && start=$(<$STFILE)
start=$((start+1))
MESSAGE=${MESSAGE}$'\n'"Today is Day #${start}"
echo "$start" > $STFILE
mail $EMAIL < $MESSAGE
A simple answer would be to export the current value to an external file, and read that back in again later.
So, for example, make a file called "CurrentDay.dat" that has the number 1 in it.
Then, in your bash script, read in the number and increment it.
e.g. your bash script could be:
#!/bin/bash
#Your stuff here.
DayCounter=$(<CurrentDay.dat)
#Use the value of DayCounter (i.e. $DayCounter) in your message.
DayCounter=$((DayCounter + 1))
echo $DayCounter > CurrentDay.dat
Of course, you may need to implement some additional checks to avoid something going wrong, but that should work as is.

Resources