Reputation: 95
I have a simple code, it is working but not as intended. The main propose of my code is to decrease the given date until the target date 2012-01-31,
But the results:
2017-10-28
2017-09-28
2017-08-28
2017-07-28
2017-06-28
2017-05-28
2017-04-28
2017-03-28
2017-02-28
2017-01-28
2016-12-28
2016-11-28
2016-10-28
2016-09-28
2016-08-28
2016-07-28
2016-06-28
2016-05-28
2016-04-28
2016-03-28
2016-02-28
2016-01-28
...
The code:
#!/bin/bash
d=2017-10-31
while [ "$d" != 2012-01-31 ]; do
echo $d
d=$(date -I -d "$d -1 month")
done
I really wish for the correct months in-placed like:
2017-10-31
2017-09-30
2017-08-31
2017-07-31
2017-06-30
2017-05-31
2017-04-30
2017-03-31
2017-02-28
2017-01-31
2016-12-31
2016-11-30
2016-10-31
2016-09-30
2016-08-31
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2016-03-31
2016-02-29
2016-01-31
...
How can I manage to do this?
Upvotes: 0
Views: 88
Reputation: 1131
Another option like randomir's answer is to use the relative word yesterday
instead of day ago
.
d=2017-10-31
while [ "$d" != 2012-01-31 ]; do
echo $d
d=$(date -I -d "${d%-*}-01 yesterday")
done
Upvotes: 0
Reputation: 18697
Assuming your starting date is always the last day in month, you can let date
take care of counting days per month if you use this algorithm:
date = date +1 day -1 month -1 day
Namely, first flip the date to the 1st day of next month, then simply subtract one month to get the 1st day of current month, and finally just subtract 1 day to get the last day of the previous month.
For example:
#!/bin/bash
d=2017-10-31
while [ "$d" != 2012-01-31 ]; do
echo $d
d=$(date -I -d "$(date -I -d "$(date -I -d "$d +1 day") 1 month ago") 1 day ago")
done
Note 1 day ago
is used instead of -1 day
, because the latter can be interpreted as a timezone by date
(known gotcha).
Alternatively, you can manually set the day to 01
(using shell's parameter expansion for suffix removal ${d%-*}
) and then simply subtract 1 day
with date
:
d=2017-10-31
while [ "$d" != 2012-01-31 ]; do
echo $d
d=$(date -I -d "${d%-*}-01 1 day ago")
done
The output is (in both cases):
2017-10-31
2017-09-30
2017-08-31
2017-07-31
2017-06-30
2017-05-31
2017-04-30
...
Upvotes: 1
Reputation: 67527
It's easier to generate the beginning of the month and do little trick to get the end of month without checking dates
$ d=2017-10-31; bd=$(date -I -d "$d +1 month");
while [ $d != 2012-01-31 ];
do
bd=$(date -I -d "$bd - 1 month");
d=$(date -I -d "$bd - 1 day");
echo $d;
done
2017-10-31
2017-09-30
2017-08-31
2017-07-31
...
2016-07-31
2016-06-30
2016-05-31
2016-04-30
2012-03-31
2012-02-29
2012-01-31
Upvotes: 1
Reputation: 50219
Perhaps instead of subtracting a month (which is notorious for this behavior) you can subtract the number of days that are in the current month
!/bin/bash
d=2017-10-31
while [ "$d" != 2012-01-31 ]; do
echo $d
days_in_month==$(cal $(date +"%m %Y" -d $d) | awk 'NF {DAYS = $NF}; END {print DAYS}')
d=$(date -I -d "$d $days_in_month day ago")
done
Upvotes: 1