How does the “1 month ago” option in date command work?

I’m not sure if this gets the past date within the current day or if it only takes 30 or 31 days to it.

e.g.

If the current date is March 28th, 1 month ago must be February 28th, but what happen when it’s March 30th?

Scenario

I want to backup some files each day, the script will save this files within the current date with $(date +%Y%m%d) format, like 20150603_bckp.tar.gz, then when the next month arrives, remove all those files within 1 month ago except the 1st’s and the 15th’s files, so this is my condition:

past_month = $(date -d "-1 month" +%Y%m%d)
day = $(date +%d)
if [ "$day" != 01 ] && [ "$day" != 15 ]
then
    rm /path/of/files/${past_month}_bckp.tar.gz
    echo "Depuration done"
else
    echo "Keep file"
fi

But I want to know, what will happen when the date is 30th, 31th or even the past February example? It will keep those files? or remove day 1st files?

When it’s 31th the depuration will execute, so if the past month only had 30 days, this will remove the day 1st file?

I hope I hinted.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

- 1 month will subtract one from the month number, and then if the resulting date is not valid (February 30, for example), adjust it so that it is valid. So December 31 - 1 month is December 1, not a day in November, and March 31 - 1 month is March 3 (unless executed in a leap year).

Here’s quote from the info page for Gnu date (which is the date version which implements this syntax), which includes a good suggestion to make the arithmetic more robust:

The fuzz in units can cause problems with relative items. For
example, 2003-07-31 -1 month might evaluate to 2003-07-01, because
2003-06-31 is an invalid date. To determine the previous month more
reliably, you can ask for the month before the 15th of the current
month. For example:

    $ date -R
    Thu, 31 Jul 2003 13:02:39 -0700
    $ date --date='-1 month' +'Last month was %B?'
    Last month was July?
    $ date --date="$(date +%Y-%m-15) -1 month" +'Last month was %B!'
    Last month was June!

Another warning, also quoted from the info page:

Also, take care when manipulating dates around clock changes such as
daylight saving leaps. In a few cases these have added or subtracted
as much as 24 hours from the clock, so it is often wise to adopt
universal time by setting the TZ environment variable to UTC0
before embarking on calendrical calculations.

Method 2

Instead of relying on filenames for purging your backup files, you’d be safer relying on their time metadata.

For example you can delete all files older than 30 days with this command :

/usr/bin/find /path/to/your/files -type f -ctime +30 -delete

As a free bonus, running this everyday will allow you to keep your backup files on a rolling month, allowing a better disk space management.

For keeping 1st or 15th files, you could either store them in another directory, either update the find command with -not -name option.

Method 3

You could try to see how the date works by the following:

date -d "$(date -d "Mar 31 2019" +%F) +1 month ago"
Sun Mar  3 00:00:00 EET 2019

So I think that based on the curent last month (not curent, if that is March), decreases the number of days from the last month from the curent month.

You could try the following syntax to delete files older then a number of days ( in the example bellow 31 days). One line to solve the problem (this is for a simple approach).

find /path/to/folder/with/arhives/ -mindepth 1 -mtime +31 -delete

For a more detailed approach you could also do something like this:
1. Finding the number of days for the curent month:

cal $(date +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}'
  1. Finding the number of days for the last month:

    echo “$(cal $(date +%m) $(date +%y) | egrep -v “$(date +%y)|Su” | xargs | awk ‘{print $NF}’)-“$(cal $(date -d “+1 month ago” +%m) $(date +%y) | egrep -v “$(date +%y)|Su” | xargs | awk ‘{print $NF}’) | bc

  2. So now we find the difference between those two months:

    echo “$(cal $(date +%m) $(date +%y) | egrep -v “$(date +%y)|Su” | xargs | awk ‘{print $NF}’)-“$(cal $(date -d “+1 month ago” +%m) $(date +%y) | egrep -v “$(date +%y)|Su” | xargs | awk ‘{print $NF}’) | bc

Now lets assign some variables to this 3 steps.
Step 1 Variable Name: FCM
Step 2 Variable Name: FLM
Step 3 Variable NAme: DCL

FCM=$(cal $(date +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}')
FLM=$(al $(date -d "+1 month ago" +%m) $(date +%y) | egrep -v "$(date +%y)|Su" | xargs | awk '{print $NF}')
DCL=$(echo "$FCM-$FLM" | bc)

Verify if $DCL equals 0 (zero) and delete based on the difference between $FCM and $FLM:

if [ $DCL -ne 0 ]; then
    if [ $DCL -lt 0 ]; then
        find /path/to/folder/with/arhives/ -mindepth 1 -mtime +$(echo "$DCL+$FLM" | bc) -delete
    elif [ $DCL -gt 0 ]; then
        find /path/to/folder/with/arhives/ -mindepth 1 -mtime +$(echo "$DCL+$FLM" | bc) -delete
    fi
else
    find /path/to/folder/with/arhives/ -mindepth 1 -mtime +$FLM -delete
fi

You can also add a variable to “/path/to/folde/with/arhives/”.

Conclusion: If you want to delete files older then one month (exactly), you need to adjust the exact number of days, if you are using “date” command and “+1 month ago”.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x