views:

341

answers:

4

Hi. I want to do some calendar manipulations in bash - specifically, I want to figure out the last date of a given month (including leap-year, and a preparing a table for a lookup is not a valid solution for me).

Supposedly I have the following code:

$year=2009
$start_month=2
$end_month=10
for $month in $(seq $start_month $end_month); do
  echo "Last date of "$(date +"%B" -d "${year}-${month}-01")" is: " ???
done

I can't figure out how to do something like this. I though date -d would work like POSIX mktime and fold invalid dates to their valid equivalents, so I could say something like date -d "2009-03-00" and get '2009-02-28', but no such luck.

Is there anyway to do it using only what is available on bash in a standard GNU environment?

+1  A: 

If you don't mind playing with grep/awk/perl, you can take a look at cal.

$ cal 4 2009
     April 2009
Su Mo Tu We Th Fr Sa 
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

Edit (MarkusQ): To atone for my joke solution below I'll contribute to yours:

cal 4 2009 | tr ' ' '\n' | grep -v ^$ | tail -n 1
mouviciel
Something like this: cal 2 2009 | perl -nle 'm/\S/ and $line = $_; END { @r = split /\s/,$line; print pop @r; }'It would work, I guess, but its not really nice :-/
Guss
@MarkusQ: your parser is much cleaner then mine, but I'd still prefer Steve Baker's solution. Thanks anyway :-)
Guss
cal | awk '!/^$/{E=$NF} END{print E}'
dannysauer
A: 

Well, one way would be to watch the current date in a loop until the month component changes, saving the day component for one round. That would give you both the first and last day of the month, but it might be too slow.

Posted 1 April 2009

MarkusQ
Ha. it would also be problematic for past dates, unless I can get my hand on a time machine.
Guss
+5  A: 

Try: date -d 'yesterday 2009-03-01'

Intuitive I know. Earlier versions of date used to work the POSIX way.

Steve Baker
Heh, brilliant. Thanks. Obviously I should have read the info documentation (not that I'm going to now, I just can't stand the info browser).
Guss
'2009-02-01 last day month' also works, but this is more elegant.
Sean Bright
+3  A: 

date(1)'s -d is GNU specific; so using that will only work on GNU Linux.

A more portable solution (this should even work in sh AFAIK), is this:

: $(cal 4 2009); echo $_
lhunath
Neat trick! definitely "out side the box". Reason why I won't use it though: It produces an error message - I can redirect it, but its still not nice. Also- date -d may be GNU specific, but I'm writing a GNU bash script- its valid to expect it to be deployed on a GNU env (could also be Solaris)
Guss
It does not produce an error. Did you not put the colon at the front? Thats not the prompt in this example, you actually need to type colon-space-dollar...etc.
camh
@Guss: There should be no error message. Check that you copied it right, and if so, show the error message or talk to me about it in #bash on freenode. Moreover, you cannot expect to be in a GNU environment even if it's GNU bash. Bash is available (even by default) in a LOT of non-GNU environments.
lhunath