Primeiro e último dia de um mês

6

Dados dois números, mês e ano, como posso calcular o primeiro e o último dia desse mês? Meu objetivo é gerar essas três linhas:

  1. mês / ano (mês em formato textual, mas isso é trivial)

  2. para cada dia do mês: nome do dia da semana do dia atual: sex. & Sentou. & Dom. [...]

  3. número do dia no mês: 1 & 2 & 3 [...] & 28 & ..?

Estou procurando uma solução usando o GNU date ou o BSD date (no OS X).

    
por alecail 17.07.2012 / 11:28

5 respostas

4

Algum tempo atrás eu tive problema semelhante. Existe a minha solução:

 $ ./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 em si:

#!/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))

Eu não tinha o GNU date nas máquinas que preciso, portanto não resolvi com data. Pode haver uma solução mais bonita.

    
por 17.07.2012 / 14:47
8

Eu serei honesto; do jeito que você está fazendo a pergunta, eu tenho a sensação de que você recebeu um dever de casa, então vou deixar alguns passos para fora da resposta como um exercício para o leitor:

Você deve dar uma boa olhada na página de manual date ; especialmente a -d flag, que permite examinar qualquer dia. O primeiro dia do mês M no ano Y seria "M / 01 / Y"

Obtendo o último dia do mês, sua melhor aposta é adicionar 1 ao número do mês que você recebeu e deduzir um dia na data.

Dica: date pode aceitar alguma aritmética extensa; Eu posso, por exemplo, dizer date -d "01/07/2012 + 1 month - 1 day" e isso me dará a resposta correta.

Você pode descobrir como exibir a saída desejada em 2) e 3) estudando a seção "formato" da página date .

Dicas: veja %a e %d

    
por 17.07.2012 / 11:56
5
# 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"
    
por 16.12.2015 / 20:26
3
**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

**Currunt 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
    
por 08.09.2014 / 14:20
2
date -d "20121101 + 1 month - 1 day" +%Y%m%d
    
por 01.11.2012 / 09:27

Tags