Gerando Calendários com PHP

Artigo que apresenta um script com a implementação de uma função para geração de calendários usando PHP.

Calendário

Segue uma função em PHP para geração de calendários na forma de tabelas HTML. Ela permite habilitar ou desabilitar a exibição de dias extras (do mês anterior ou posterior que compartilham a mesma linha do calendário).

Linguagem: PHP

Copyright 2011 Rubens Takiguti Ribeiro

Licença: LGPL 3 ou superior

/**
 * Gera um calendario na forma de tabela HTML
 * @param int $mes Mes desejado (1 = Janeiro, 12 = Dezembro)
 * @param int $ano Ano desejado
 * @param bool $preencher_dias Preencher os dias extras com numeros ou nao
 * @return string Calendario na forma de tabela HTML
 */
function gerar_calendario($mes, $ano, $preencher_dias = true) {
    $time_primeiro_dia = mktime(0, 0, 0, $mes, 1, $ano);
    $time_ultimo_dia   = mktime(0, 0, 0, $mes + 1, 0, $ano);

    $primeiro_dia_semana = (int)strftime('%u', $time_primeiro_dia);
    $ultimo_dia          = (int)strftime('%d', $time_ultimo_dia);
    $ultimo_dia_semana   = (int)strftime('%u', $time_ultimo_dia);

    // Obter nome do mes
    $nome_mes = strftime('%B', $time_primeiro_dia);

    // Obter nomes dos dias da semana
    for ($i = 1; $i <= 7; $i++) {
        $time = mktime(0, 0, 0, $mes, $i - $primeiro_dia_semana, $ano);
        $nome_dia[$i] = strftime('%A', $time);
        $nome_abreviado_dia[$i] = strftime('%a', $time);
    }

    // Determinar dias a serem exibidos
    $dias = array();
    if ($primeiro_dia_semana != 7) {
        $time_ultimo_dia_mes_passado = mktime(0, 0, 0, $mes, 0, $ano);
        $ultimo_dia_mes_passado = (int)strftime('%d', $time_ultimo_dia_mes_passado);
        for ($i = $primeiro_dia_semana - 1; $i >= 0; $i--) {
            $dias[] = $preencher_dias ? $ultimo_dia_mes_passado - $i : '';
        }
    }
    $posicao_antes = count($dias);;
    for ($i = 1; $i <= $ultimo_dia; $i++) {
        $dias[] = $i;
    }
    $posicao_depois = count($dias);
    if ($ultimo_dia_semana < 6) {
        $max = 7 - $ultimo_dia_semana;
        for ($i = 1; $i < $max; $i++) {
            $dias[] = $preencher_dias ? $i : '';
        }
    } elseif ($ultimo_dia_semana == 7) {
        for ($i = 1; $i <= 6; $i++) {
            $dias[] = $preencher_dias ? $i : '';
        }
    }

    $tabela = <<<HTML
<table class="calendario">
<caption>{$nome_mes}/{$ano}</caption>
<thead>
<tr>
  <th scope="col"><abbr title="{$nome_dia[1]}">{$nome_abreviado_dia[1]}</abbr></th>
  <th scope="col"><abbr title="{$nome_dia[2]}">{$nome_abreviado_dia[2]}</abbr></th>
  <th scope="col"><abbr title="{$nome_dia[3]}">{$nome_abreviado_dia[3]}</abbr></th>
  <th scope="col"><abbr title="{$nome_dia[4]}">{$nome_abreviado_dia[4]}</abbr></th>
  <th scope="col"><abbr title="{$nome_dia[5]}">{$nome_abreviado_dia[5]}</abbr></th>
  <th scope="col"><abbr title="{$nome_dia[6]}">{$nome_abreviado_dia[6]}</abbr></th>
  <th scope="col"><abbr title="{$nome_dia[7]}">{$nome_abreviado_dia[7]}</abbr></th>
</tr>
</thead>
<tbody>

HTML;
    $coluna = 1;
    foreach ($dias as $i => $dia) {
        if ($coluna == 1) {
            $tabela .= '<tr>';
        }
        $class = $i < $posicao_antes || $i >= $posicao_depois ? ' class="extra"' : '';
        $tabela .= '<td'.$class.'>'.$dia.'</td>';
        $coluna += 1;
        if ($coluna == 8) {
            $tabela .= '</tr>';
            $coluna = 1;
        }
    }
    $tabela .= <<<HTML
</tbody>
</table>
HTML;
    return $tabela;
}

Exemplo de uso:

setlocale(LC_TIME, 'pt_BR.UTF-8');
echo gerar_calendario(3, 2011);

Observe que ela é sensível à localidade, ou seja, os nomes dos meses e dos dias da semana são determinados com a localidade especificada pela função setlocale.

6 comentários

Rubens Takiguti Ribeiro (autor do blog) disse...

É só chamar a função colocando as linhas abaixo onde você quer que o calendário apareça:

$time = time();
$mes = (int)strftime('%m', $time);
$ano = (int)strftime('%Y', $time);

setlocale(LC_TIME, 'pt_BR.UTF-8');
echo gerar_calendario($mes, $ano, true);

Anônimo disse...

Ficou estranho o codigo

August/2012
Wed Thu Fri Sat Sun Mon Tue
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 1 2 3 4
5 6

nao começa numa determinada semana e passa para o mes seguinte na exibição

$mes = date('n')-1;// ou $mes = date('n');
$ano = date('Y');
echo gerar_calendario($mes, $ano);

sei que peguei o codigo pronto
mais nao serviu para o que eu queria

Rubens Takiguti Ribeiro (autor do blog) disse...

Olá, Anônimo

Aqui no meu computador a função retornou corretamente. Acredito que no seu, ocorreu algum problema na detecção do dia da semana e por isso ficou assim.

Se puder, faça um teste para ver o que o código abaixo exibe:

$time = mktime(0, 0, 0, 8, 1, 2012);
$dia_semana = strftime('%u', $time);
var_dump($dia_semana);


O correto é exibir:
string(1) "3"