How to reduce 1 sec from the given time? - bash

My shell script is reading time from user say 02:00:00
How do i reduce 1 second from this, ie i require the output as 01:59:59

just tell date you want the time 1s ago:
kent$ str="02:00:00"
kent$ date -d "1 sec ago $str" +%H:%M:%S
01:59:59

One more variant:
$ date +'%H:%M:%S' -d"02:00:00 last second"
01:59:59

M=$(date +%s -d "02:00:00")
M=$(($M - 1))
date +%H:%M:%S -d #$M

Here is the accepted answer but with a slightly better code style:
M=$(date +%s -d '02:00:00')
((M--))
date +%T -d "#$M"
And you can condense it into one line if you want:
date +%T -d "#$(($(date +%s -d '02:00:00')-1))"
But!
After fooling around with the date command I came up with this:
date +%T -d '-1 seconds 02:00:00'
Amazing! Just in one call!

Update: This was a JOKE!
Just run this bash job in the background:
#!/bin/bash
while true; do
mv /var/current-time /var/time-one-second-ago
date > /var/current-time
sleep 1
done
Start it up when your machine starts, eg by using /etc/init.d
When you want the time one second ago, just do
cat /var/time-one-second-ago

Related

Shell script to find the first and last day of the previous month and pass those values as a variable

I have a (separate) curl command and I want to pass it two parameters, the first day of the last month and the last day of the last month. I plan to declare these in a shell script. Could anyone identify how I can get these values using bash? I am almost there, I just need help over the line...
First Part:
If I do this:
firstday=$(date -d "-1 month -$(( $(date +%e) - 1 )) days")
echo $firstday
Then I get:
Fri May 1 16:09:51 AEST 2020
Which is the first day of the last month. However I want this in this format:
2020-05-01
Second Part:
If I do this:
date -d "-$(date +%d) days"
That gives me:
Sun May 31 16:14:59 AEST 2020
However I need this in the format:
2020-05-31
Can someone please help me with how I can do this? I think these two commands will do what I want... it's probably just a format mask I need to get it right.
To control the format of the output date, just add it to each date command: +%Y-%m-%d.
firstday=$(date -d "-1 month -$(( $(date +%e) - 1 )) days" +%Y-%m-%d)
echo $firstday
will output: 2020-05-01
date -d "-$(date +%d) days" +%Y-%m-%d
will output: 2020-05-31

get end of day epoch in shell script bash

I want to get end of day epoch in bash.
Eg:
date +%s
The above command gives current epoch.
I want the end of day epoch of current date.
You can simply specify that with the -d argument.
i.e. date -d "today 23:59:59" +%s
where today 23:29:59 is used to get the end of the current day
Edit : #Toby propose the following approach to handle correctly leap seconds -d 'tomorrow 0 -1second
If you want the beginning of the day use
date -d "today 0" +%s
Using BSD date, you can use the -v to adjust the time properly.
% date
Tue May 22 09:21:50 EDT 2018
% date -v 23H -v 59M -v 59S
Tue May 22 23:59:59 EDT 2018
Slightly longer, but saving you from having to remember how many hours are in a day, minutes in an hour, etc, by going to midnight tomorrow, then subtracting one second.
% date -v +1d -v 0H -v 0M -v -0S -v -1S
^ ^ ^ ^ ^
| | | | |
| +-----+------+ subtract one second
| |
| reset to midnight
|
go to tomorrow
(It's a shame -v can't take a combination. date -v+1d0H0MS-1S would be nice to type. It's not terribly readable or obvious, but easy to parse if you know how -v works. Whitespace would make it better: date -v "+1d 0H 0M 0S -1S". #wishfulthinking)
A simple but fragile approach is to just round up to the nearest multiple of 86400:
$ now=$(date +%s)
$ end_of_day=$(( now - now%86400 + 86399))
but this won't take daylight savings into account for the two days where it may be relevant.

subtracting two lists of timestamps from each other in bash

I have a script that checks my logs for the timestamps of when the application has gone down and back up (availability of the app).
I want to find the difference between a list of timestamps then add up all of those difference so I know a total amount of time the app has been down. So the downtime.txt file has a list like this:
04:55:51
05:41:51
and the uptime.txt has a list like the same format:
04:56:59
05:42:21
If I didn't need to convert the timestamps into numbers for arithmetic I think I could
paste downtime.txt uptime.txt | awk '{print $1 - $2}'>timedown.txt
or something like that. How can I read the timestamps, convert it to a number, subtract the matching lines from the two files, then add up all the sums from those lines?
You can use the date command to convert timestamps. It's unfortunate your timestamps don't have dates on them, not sure what happens when you roll over past midnight, but assuming you don't have that problem, you can choose the fixed date "01-Jan-1970 UTC" for calculation purposes.
Here is your code:
paste downtime.txt uptime.txt | while read d u; do echo $(( $(date -d "01-Jan-1970 UTC $u" +%s) - $(date -d "01-Jan-1970 UTC $d" +%s) )); done
Explanation: The date command converts the timestamps into seconds. The -d option means, act on the following date instead of "now". So we give it a date using your input files, assuming that the times specified are from midnight. Since date works on the basis of seconds since 01 Jan 1970 UTC 00:00:00, we add that date to simplify the result. The +%s parameter means, tell me how many seconds it is since 01-Jan-1970. This is where the conversion comes in. Since we specified -d, it uses the timestamp you specified instead of "now". So the value of $(date -d "01-Jan-1970 UTC $u" +%s) is the number of seconds since midnight for the uptime. Then we subtract the downtime seconds from the uptime seconds using $(( ... )) to get the number of seconds between the two timestamps. (If your bash doesn't have that function, you can use $(expr $(date -d "01-Jan-1970 UTC $u" +%s) - $(date -d "01-Jan-1970 UTC $d" +%s) ) instead).
UPDATE: I should finish the job. To accumulate and count the total time, you can add | awk '{total=total+$1} END {print $total}'. To convert this back into hours and minutes, use date again; use the -u option to prevent conversion to local time, the -d option with # to specify number of seconds (again we are using 01-Jan-1970 as a base, that's what # means), and +%T to convert into hours and minutes, though if it's more than 24 hours you'll lose the extra days.
date -u -d #$(paste downtime.txt uptime.txt | while read d u; do echo $(( $(date -d "01-Jan-1970 UTC $u" +%s) - $(date -d "01-Jan-1970 UTC $d" +%s) )); done | awk '{total=total+$1} END {print total}') +%T

Taking date and time of last 5 days

I know that I can take date and time of yesterday by writing
dt=`date +"%d-%m-%Y" -d "-1 day"`
Similarly I want to find -2 day, -3 day and so on. When I put this command in loop, and write it as
dt=`date +"%d-%m-%Y" -d "-$i day"`
it didn't worked. Am I wrong somewhere or there is some another way to do such stuff.

What does the at-sign # mean in the bash command: date --date #...?

Searching the internet I found explanations only for '$#', meaning 'expand to positional parameters'. But I couldn't find anything about the # sign by itself.
I stumbled over it in the third snipped of the accepted answer to this question:
https://superuser.com/questions/611538/is-there-a-way-to-display-a-countdown-or-stopwatch-timer-in-a-terminal
Specifically:
date -u --date #$((`date +%s` - $date1)) +%H:%M:%S
In the context you show, the # is in the beginning of the --date argument to the date command:
date -u --date #$((`date +%s` - $date1)) +%H:%M:%S
In that case it means that the argument should be treated as the number of seconds since epoch, see an example in man date:
Convert seconds since the epoch (1970-01-01 UTC) to a date
$ date --date='#2147483647'
or:
$ date -u -d #0
Thu Jan 1 00:00:00 UTC 1970
This meaning of # is defined by the date utility alone and not by bash.

Resources