Shell add day to date saved in parameter - shell

Hoping someone can help me work out what on earth is happening here.
I've got a script which receives a date as a parameter in this format "2016-09-01 00:00:00" and should create another variable containing the date for one day in the future, code is below
currentDate=$1
currentDate=$(date +"%Y-%m-%d %H:%M:%S" -d "$currentDate")
nextDate=$(date +"%Y-%m-%d %H:%M:%S" -d "$currentDate + 1 day")
echo $currentDate
echo $nextDate
Sometimes this works perfectly fine for example
2016-09-01 00:00:00 - date given as parameter
2016-09-02 00:00:00 - output for next day
But sometimes it'll only add 23 hours depending on the date provided
2016-02-01 00:00:00 - date given as parameter
2016-02-01 23:00:00 - output for next day
if I change the nextDay variable to add three days as below
nextDate=$(date +"%Y-%m-%d %H:%M:%S" -d "$currentDate + 3 day")
it gives the output as below adding only 21 hours instead of 3 days
2016-02-01 00:00:00 - date given as parameter
2016-02-01 21:00:00 - output for next day
Could someone help me understand why this is happening, is it related to timezones?

The reason appears to be how difficult it is to do free-form date parsing:
A baseline date: (I'm in the America/Toronto time zone)
$ date -d "2016-11-06 01:00:00" "+%F %T%z"
2016-11-06 01:00:00-0400
Try adding a day
$ date -d "2016-11-06 01:00:00 + 1 day" "+%F %T%z"
2016-11-06 19:00:00-0500
Hmm, that's strange, looks like it's adding a day but then expressing it as midnight, then subtracting 5 hours.
Let's try adding a day to just the date part
$ date -d "2016-11-06 + 1 day 01:00:00" "+%F %T%z"
2016-11-07 01:00:00-0500
That looks better.
In your script try this:
read current_date current_time < <(date -d "$1" +"%F %T%z")
echo "$current_date $current_time"
next_day=$(date -d "$current_date + 1 day $current_time" +"%F %T%z")
echo "$next_day"
three_days=$(date -d "$current_date + 3 day $current_time" +"%F %T%z")
echo "$three_days"

Related

The date command appears to convert timezones the wrong way?

I'm working on a script where I need to convert the current time, in UTC to something else:
fmt="%Y-%m-%d %H:%M:%S"
tzone=America/Detroit
nowinutc=$(TZ=UTC date +"$fmt");echo $nowinutc
nowintz=$(date -d "TZ=\"$tzone\" $nowinutc" +"$fmt");echo $nowintz
yestintz=$(date -d "$nowintz - 1 day" +"$fmt");echo $yestintz
I know America/Detroit is 5 hours behind UTC, so 08:00:00 should become 03:00:00, but:
$ fmt="%Y-%m-%d %H:%M:%S"
$ tzone=America/Detroit
$ nowinutc=$(TZ=UTC date +"$fmt");echo $nowinutc
2022-02-11 08:49:51
$ nowintz=$(date -d "TZ=\"$tzone\" $nowinutc" +"$fmt");echo $nowintz
2022-02-11 13:49:51
$ yestintz=$(date -d "$nowintz - 1 day" +"$fmt");echo $yestintz
2022-02-12 14:49:51
It's probably not the date command that gets it wrong, but what am I doing wrong here? It looks like everything works the opposite way of expected. Not only does the timezone conversion add 5 hours, but subtracting 1 day adds 25 hours - what is going on here?
so 08:00:00 should become 03:00:00
Then the input is in UTC and you are in Detroit.
TZ=America/Detroit date -d "08:00:00 UTC" +%H:%M:%S
TZ=America/Detroit date -d "TZ=\"UTC\" 08:00:00" +%H:%M:%S
TZ=America/Detroit date -d "08:00:00+00:00" +%H:%M:%S
From man date examples:
Show the time on the west coast of the US (use tzselect(1) to find TZ)
$ TZ='America/Los_Angeles' date
Show the local time for 9AM next Friday on the west coast of the US
$ date --date='TZ="America/Los_Angeles" 09:00 next Fri'

Round current time up and down

I'm trying to figure out how to get the current hour rounded down to start of the hour and the next hour in bash?
For example, if I run my script:
./printHour.sh
and let's say the current time at execution is 13:04:12 - it would print
current hour is: 13:00:00
next hour is: 14:00:00
Progress so far: (but this gives 1hour ago so it does not work) - any ideas?
lastHour=$(date -d '1 hour ago' "+%H:%M:%S")
echo "current hour is: "$lastHour
You can use this utility function:
hrdt() { date -d "${1?} hour ago" '+%H:00:00'; }
Testing:
> hrdt
bash: 1: parameter not set
> hrdt 0
08:00:00
> hrdt 1
07:00:00
> hrdt 2
06:00:00
> hrdt 3
05:00:00
Could you please try following, written and tested as per shown samples, my date is GNU date version.
cat script.bash
#!/bin/bash
currentHour=$(date "+%H:00:00")
nextHour=$(date -d '+1 hour' "+%H:00:00")
echo "current hour is: $currentHour"
echo "next hour is: $nextHour"
When I run above script I get as follows:
current hour is: 06:00:00
next hour is: 07:00:00
Seems like you don't need anything special so this should do it:
date -d '1 hour ago' "+%H:00:00"
Why bother when you want exactly the hour where both %M and %S are expected to be zero?
You don't need date in this case; as seen below, built-in printf can generate formatted date-time strings too. Here -1 represents current time, and EPOCHSECONDS is a dynamic variable that expands to the number of seconds since epoch.
$ printf 'current hour is: %(%H)T:00:00\n' -1
current hour is: 17:00:00
$
$ printf 'next hour is: %(%H)T:00:00\n' $((EPOCHSECONDS + 3600))
next hour is: 18:00:00
Using awk,
$ awk ' BEGIN { st=systime();
print "current hour=" strftime("%F %H:00:00",st);
print "next hour=" strftime("%F %H:00:00",st+(60*60)) } '
current hour=2020-12-26 23:00:00
next hour=2020-12-27 00:00:00
$

Reading date with hour and incrementing it in shell script

I have a file with date '2015-06-01-12', how can I get it to increment the hour in shell script? The result I want is '2015-06-01-13'. If its the 23rd hour it has to move forward a date and get 00 as hour.
I was able to do it to date but have so far had not any luck with incrementing hours.
currDate=2015-06-02
nextDate=`date '+%Y-%m-%d' -d "$currDate+1 days"`
echo $nextDate
It is reasonably easy if you keep your date as an epoch (number of seconds since January 1, 1970):
$ currDate=$( date +%s -d "2015-06-02 23:00:00" )
$ echo $currDate
1433300400
$ date +%Y-%m-%d-%H -d #$currDate
2015-06-02-23
$ nextDate=$(( $currDate + 3600 )) #adding an hour's worth of seconds
$ date +%Y-%m-%d-%H -d #$nextDate
2015-06-03-00

bash loop comparing date strings

Given a start date, I set the date to the end of the month of the previous year, and then try to loop 12m using a bash while loop.
The following loop never exits, and the date eventually skips from the end of the month to the beginning of the next one.
startdate="2014-06-22"
cod=${startdate:0:7}-01
echo $cod
cod=$( date --date "$cod -1 year +1 month -1 day " +"%Y-%m-%d" )
echo "$cod , $startdate "
while [ "$cod" < "$startdate" ];
do
echo $cod
cod=$( date --date "$cod +1 month" +"%Y-%m-%d" )
echo $cod
done
What I'm expecting is
2013-06-30
2013-07-31
2013-08-31
2013-09-30
2013-10-31
2013-11-30
2013-12-31
2014-01-31
2014-02-28
2014-03-31
2014-04-30
2014-05-31
So what you want is the last day of each month, but you are trying to get it by taking the first "last day of the month" and adding one month each time. That doesn't work because you get January 30th and then March 2nd rather than February 28th, because February is weird and "+1 month" is weird :-)
$ date -d '2014-01-30'
Thu Jan 30 00:00:00 GMT 2014
$ date -d '2014-01-30 +1 month'
Sun Mar 2 00:00:00 GMT 2014
To get the last day of each month you need to repeat the trick you use on the first date - find the first day of the following month and then -1 day from it.
#!/bin/bash
startdate="2014-06-22"
cod=${startdate:0:7}-01
cod=$( date --date "$cod -1 year +1 month -1 day " +"%Y-%m-%d" )
for i in $(seq 1 12); do
echo $cod
cod=$( date --date "$(date --date "$cod +32 day" +"%Y-%m-01") -1 day" +"%Y-%m-%d" )
done
Which outputs:
$ ./twelve_months.sh
2013-06-30
2013-07-31
2013-08-31
2013-09-30
2013-10-31
2013-11-30
2013-12-31
2014-01-31
2014-02-28
2014-03-31
2014-04-30
2014-05-31
Note that I also changed the loop to a straight 1 .. 12 instead of a while loop with a logic check. The while loop seemed needlessly complicated when you know you always want twelve dates.
< is getting executed by the shell. You need to escape it or use the [[ keyword for lexicographic comparison.
while [ "$cod" \< "$startdate" ];
or
while [[ "$cod" < "$startdate" ]];
I don't think you can compare date strings, but I am sure you can convert date strings to epoch and compare them as integer
Epoch is time in seconds since 1/1/1970 00:00:00+000
example:
startdate="2014-06-22"
epoch_start=$(date -d "$startdate" +%s)
cod=$startdate
cod=$( date --date "$cod -1 year +1 month -1 day " +%s )
while [ "$cod" -lt "$epoch_start" ];
do
date=$(date -d "#${cod}" +%Y-%m-%d)
date -d "#${cod}" +%Y-%m-%d
cod=$(date --date "${date} +1 month" +%s)
done
date -d "#${cod}" +%Y-%m-%d
Output:
bash test4.sh
2013-07-21
2013-08-21
2013-09-21
2013-10-21
2013-11-21
2013-12-21
2014-01-21
2014-02-21
2014-03-21
2014-04-21
2014-05-21
2014-06-21
2014-07-21
I hope that helps you.

Date calculation using GNU date

Using the GNU date command line utility, I know:
how to substract 3 days from any given date:
date -d "20110405 -3 days" "+%Y%m%d"
20110402
how to get the last Friday from today:
date -d "last friday" "+%Y%m%d"
20110408
But I don't know how to get the last Friday from any given date:
date -d "20110405 last friday" "+%Y%m%d"
Simply returns the given date:
20110405
Any ideas on how to do this? If a one-liner is not possible a few lines of script would also be helpful.
Ugly, but one line:
date -d "20110405 -2 days -$(date -d '20110405' '+%w') days" "+%Y%m%d"
EDIT: See comments.
date -d "20110405 -$(date -d "20110405 +2 days" +%u) days" "+%Y%m%d"
Explanation:
%w returns day of the week. Friday = 5 so take off 2 more days to get the right offset.
Works out as "20110405 -x days", where x is the number of days back to last Friday.
I don't like that it repeats the date string, but hopefully it goes some way to helping.
Script example (based on the accepted answer)
DT="20170601"
# get the Friday before $DT
# expected value is 20170526
date -d "$DT -`date -d "$DT +2 days" +%u` days" "+%Y%m%d"
Further examples, using undocumented features of GNU date (from unix.com)
# assign a value to the variable DT for the examples below
DT="2006-10-01 06:55:55"
echo $DT
# add 2 days, one hour and 5 sec to any date
date --date "$DT 2 days 1 hour 5 sec"
# subtract from any date
date --date "$DT 3 days 5 hours 10 sec ago"
date --date "$DT -3 days -5 hours -10 sec"
# or any mix of +/-. What will be the date in 3 months less 5 days?
date --date "now +3 months -5 days"

Resources