First and last day of a month

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).

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

# Last month:
l_first_date=$(date -d "`date +%Y%m01` -1 month" +%Y-%m-%d)
l_last_date=$(date -d "`date +%Y%m01` -1 day" +%Y-%m-%d)

# This month:
t_first_date=$(date -d "`date +%Y%m01`" +%Y-%m-%d)
t_last_date=$(date -d "`date +%Y%m01` +1 month -1 day" +%Y-%m-%d)

# Next month:
n_first_date=$(date -d "`date +%Y%m01` +1 month" +%Y-%m-%d)
n_last_date=$(date -d "`date +%Y%m01` +2  month -1 day" +%Y-%m-%d)

# Print everything
echo "Last month: $l_first_date to $l_last_date"
echo "This month: $t_first_date to $t_last_date"
echo "Next month: $n_first_date to $n_last_date"

Method 2

I’ll be honest; from the way you’re asking the question I get the sense you’ve been assigned some homework, so I’ll leave a few steps out of the answer as an exercise for the reader:

You’ll want to take a good look at the date manual page; especially the -d flag, which allows you to examine any given day. The first day of month M in year Y would be “M/01/Y”

Getting the last day of the month, your best bet is to add 1 to the number of the month you were given, then deduct one day in the date.

Hint: date can actually accept some extensive arithmetic; I can, for instance, say date -d "01/07/2012 + 1 month - 1 day" and it will give me the correct answer.

You can find out how to display the output you want in 2) and 3) by studying the “format” section of the date manpage.

Hints: Look at %a and %d

Method 3

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.

Method 4

date -d "20121101 + 1 month - 1 day" +%Y%m%d

Method 5

Previous Month Start and End date

month_year=$(date +'%m %Y' | awk '!--$1{$1=12;$2--}1')
m=${month_year% *}
y=${month_year##* }
d=$(cal $m $y | paste -s - | awk '{print $NF}')
first_date=$(printf '01-%02s-%s' $m $y)
last_date=$(printf '%s-%02s-%s' $d $m $y)
echo $first_date $last_date

Current Month Start and End date

month_year=$(date +'%m %Y' | awk '!$1{$1=12;$2--}1')
m=${month_year% *}
y=${month_year##* }
d=$(cal $m $y | paste -s - | awk '{print $NF}')
first_date=$(printf '01-%02s-%s' $m $y)
last_date=$(printf '%s-%02s-%s' $d $m $y)
echo $first_date $last_date

Next Month Start and End date

month_year=$(date +'%m %Y' | awk '!++$1{$1=12;$2--}1')
m=${month_year% *}
y=${month_year##* }
d=$(cal $m $y | paste -s - | awk '{print $NF}')
first_date=$(printf '01-%02s-%s' $m $y)
last_date=$(printf '%s-%02s-%s' $d $m $y)
echo $first_date $last_date


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
Inline Feedbacks
View all comments