Date and Calendar – Finding First and Last Day of a Month

calendardate

Given two numbers, month and year, how can I compute the first and the last day of that month ? My goal is to output these three lines:

  1. month / year (month in textual form but that is trivial)

  2. for each day of the month: name of the day of the week for the current day: Fri. & Sat. & Sun. […]

  3. day number within the month: 1 & 2 & 3 […] & 28 & .. ?

I'm looking for a solution using GNU date or BSD date (on OS X).

Best Answer

Some time ago I had similar issue. There is my solution:

 $ ./get_dates.sh 2012 07
The first day is 01.2012.07, Sunday
The last day is 31.2012.07, Tuesday
 $ cal
 July 2012
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 31

Script itself:

#!/bin/bash
# last day for month
lastday()  {
#                ja   fe   ma   ap   ma   jn   jl   ag   se   oc   no   de
  mlength=('xx' '31' '28' '31' '30' '31' '30' '31' '31' '30' '31' '30' '31')

  year=$1
  month=$2

  if [ $month -ne 2 ] ; then
    echo ${mlength[$month]}
    return 0
  fi

  leap=0
  ((!(year%100))) && { ((!(year%400))) && leap=1 ; } || { ((!(year%4))) && leap=1 ; }

  feblength=28
  ((leap)) && feblength=29
  echo $feblength
}

# date to Julian date
date2jd() {

  year=$1
  month=$2
  day=$3
  lday=$(lastday $year $month) || exit $?

  if ((day<1 || day> lday)) ; then
    echo day out of range
    exit 1
  fi

  echo $(( jd = day - 32075
                + 1461 * (year + 4800 - (14 - month)/12)/4
                        + 367 * (month - 2 + (14 - month)/12*12)/12
                    - 3 * ((year + 4900 - (14 - month)/12)/100)/4
                - 2400001 ))
}

jd2dow()
{
  days=('Sunday' 'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday' 'Saturday')

  jd=$1
  if ((jd<1 || jd>782028)) ; then
    echo julian day out of range
    return 1
  fi

  ((dow=(jd+3)%7))

  echo ${days[dow]}
}


echo -n "The first day is 01.$1.$2, "
jd2dow $(date2jd $1 $2 01)
echo -n "The last day is $(lastday $1 $2).$1.$2, "
jd2dow $(date2jd $1 $2 $(lastday $1 $2))

I didn't have GNU date on machines I need it, therefore I didn't solve it with date. May be there is more beautiful solution.

Related Question