Today I was writing a bash script that needed to reference a time in the past relative to the current UTC date.
For instance, if today is March 31st, 2015 UTC, what month was it exactly one month ago?
However, I found it was less than trivial to actually get the correct answer using a relative time calculation with
For instance, you would think that the result of
$ date +%B -d "1 month ago" would be
February, but the actual result is
March, which is still the month we are currently in! Definitely not the result I was looking for.
Buried in the GNU coreutils manual there was an explanation for this behavior.
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.
I understand why there could be a problem if you were starting with an invalid date, but I was surprised to learn that a clever workaround is still required if the result is an invalid date.
Shouldn’t the logic just be NOT to return an invalid result based on the context of the output? If we only want to return the month, not the date, one would think the context of the calculation would change. This is “relative” time after all. In my opinion this is a total bug and should be fixed – not merely passed off as a necessary annoyance.
Anyway, the workaround suggested is to always use the 15th of the current month as a starting point constant before performing the calculation. This way you avoid the date gap problem since
'1 month' == '28 days' and there are four different month lengths possible in the Gregorian calendar (28, 29, 30 and 31).
So maintaining our above example, if today is March 31st, 2015 UTC, what month was it exactly one month ago?
$ date +%B -d "$(date +%Y-%m-15) - 1 month" will result in
February, which is correct.
Did you find this helpful? Let me know in the comments!
date command was intended for use on Linux and won’t work on OS X or other BSD-based systems.