25

How do I get the previous month end date, based on processing date?

Examples:

  • Processing date = 15jan2015
  • Expected date = 31dec2014,

  • Processing date = 10feb2015
  • Expected date = 31jan2015

4 Answers4

44

With GNU date:

$ date +%d%b%Y
16Aug2015
$ date -d "$(date +%Y-%m-01) -1 day" +%d%b%Y
31Jul2015

Some shells have built-in support for date manipulation:

With ksh93:

$ printf "%(%d%b%Y)T\n" "1st day, yesterday"
31Jul2015

With zsh:

$ zmodload zsh/datetime
$ strftime -s d %Y-%m-01-12 $EPOCHSECONDS
$ strftime -rs d %Y-%m-%d-%H $d
$ strftime %d%b%Y $((d-86400))
31Jul2015
9

Here's a version that works on Mac OS, which uses the BSD date utility:

date -v1d -v-1d +%d%b%Y

The arguments are applied in order. You can kind of imagine that a date is piped from one argument to the next. For example:

  • Start with the current date (date) -> 2017-03-06
  • Set that date to the 1st day of its month (-v1d) -> 2017-03-01
  • Subtract one day from that (-v-1d) -> 2017-02-28
  • Format the date (+%d%b%Y) -> 28Feb2017

You can reach any number of months forward or backward using date -v-1m -v1d -v-1d, replacing -1m with the number of months backwards or forwards (+1m) you want.

That's the generic answer. This question specifically asks about dates relative to a starting date. The Mac OS / BSD date utility doesn't let you supply a datestamp to start from, but you can set each date element individually:

date -v2015y -v1m -v15d -v1d -v-1d +%d%b%Y -> 31Dec2014

7

There are a lot of ways to do this; here is the simplest one I found (here assuming GNU date):

$ date -d "-$(date +%d) days"
Fri Jul 31 16:07:23 EDT 2015
user1717828
  • 3,542
  • 1
    @stephane 's answer is clearer, and this one will not work in some strange years, where days where skipped/added in the middle of the month. Yes this has happened. see https://www.youtube.com/watch?v=-5wpm-gesOY – ctrl-alt-delor Aug 17 '15 at 06:20
  • @richard, the way GNU date day offsets work (a 1 day offset is not the same as a 24 hour one), I think this answer and mine should be equivalent and only fail in timezones that would skip the last day of one month (typically, if that ever happened that would probably be in some pacific island for a switch to -12:00 offset to 12:00 offset (or -13 to 11...)... – Stéphane Chazelas Aug 17 '15 at 08:56
  • @Stephane thanks for pointing out other problems, time is difficult. Note in your solution, in the case that the middle of the month is removed (this has happened) then day 30 is not the 30th day, so subtracting 30 will not get you to the last day of the previous month. I can't see why this one wont work, if there is a 1st day of the month (not guaranteed). However this does not mean that it will. – ctrl-alt-delor Aug 19 '15 at 18:51
  • @richard, See TZ=Pacific/Apia faketime '2011-12-31 12:00' date -d '1 day ago'. You get an error because there was no 2011-12-30 there. That is, the day offset was done on the calendar time. 2011-12-31 minus 31 days gives you 2011-11-30 because it takes 31 off 31. It doesn't take 3124606060 seconds off the current time. Compare with TZ=Pacific/Apia faketime '2011-12-31 12:00' date -d '24 hour ago' which gives you the 29th, that is, this time, the date it was 246060*60 seconds ago. – Stéphane Chazelas Aug 19 '15 at 19:35
0

Try using this code

date -d "-$(date +%d) days  month" +%Y-%m-%d
Walk
  • 111