Trabalhando com datas úteis em php
by Rodrigo Régis Palmeira on jul.06, 2009, under PHP
Olá!
Hoje eu vou publicar funções muito úteis no dia-a-dia: Somar datas considerando dias úteis.
Obs.: Serão considerados dias não úteis apenas os sábados, domingos e feriados nacionais.
Os feriados nacionais são em sua maioria fixos (ex.: 01/05, 07/09, 02/11) e existem alguns feriados “móveis” (ex.: carnaval, páscoa, corpus christi) que são baseados no feriado da páscoa.
Existe uma função nativa do php para retornar a data da páscoa do ano informado (easter_date) que ajuda muito na hora de descobrir os feriados nacionais, mas se você não tiver essa função disponível no seu servidor, então existe uma outra opção. Trata-se de um algorítmo criado em 532 D.C. para descobrir a data da páscoa do ano informado que está postado abaixo:
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 32 | <?php /** * @param string|int $Year * Displays <a href="http://br.php.net/easter_date">php.net</a> * @link http://br.php.net/easter_date */ function retornarPascoa($Year) { /* G is the Golden Number-1 H is 23-Epact (modulo 30) I is the number of days from 21 March to the Paschal full moon J is the weekday for the Paschal full moon (0=Sunday, 1=Monday, etc.) L is the number of days from 21 March to the Sunday on or before the Paschal full moon (a number between -6 and 28) */ $G = $Year % 19; $C = (int)($Year / 100); $H = (int)($C - (int)($C / 4) - (int)((8*$C+13) / 25) + 19*$G + 15) % 30; $I = (int)$H - (int)($H / 28)*(1 - (int)($H / 28)*(int)(29 / ($H + 1))*((int)(21 - $G) / 11)); $J = ($Year + (int)($Year/4) + $I + 2 - $C + (int)($C/4)) % 7; $L = $I - $J; $m = 3 + (int)(($L + 40) / 44); $d = $L + 28 - 31 * ((int)($m / 4)); $y = $Year; $E = mktime(0,0,0, $m, $d, $y); return $E; } ?> |
Sabendo que dia é a páscoa, tudo fica mais fácil. Basta descobrir os outros feriados conforme abaixo:
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 32 | <?php /** * @author Rodrigo Régis Palmeira <regisbsb@gmail.com> * @param string $ano - ano em que se quer calcular os feriados * @return array com feriados nacionais do ano informado do ano (fixo e moveis) */ function retornarFeriados($ano) { $dia = 86400; $datas = array(); $datas['pascoa'] = easter_date($ano); $datas['sexta_santa'] = $datas['pascoa'] - (2 * $dia); $datas['carnaval'] = $datas['pascoa'] - (47 * $dia); $datas['corpus_cristi'] = $datas['pascoa'] + (60 * $dia); $feriados = array ( 'Ano Novo' => '01/01/'.date('Y'), 'Carnaval' => date('d/m/Y',$datas['carnaval']), 'Sexta-Feira Santa' => date('d/m/Y',$datas['sexta_santa']), 'Páscoa' => date('d/m/Y',$datas['pascoa']), 'Tiradentes' => '21/04/'.date('Y'), 'Dia do Trabalhador' => '01/05/'.date('Y'), 'Corpus Cristi' => date('d/m/Y',$datas['corpus_cristi']), 'Dia da Independência' => '07/09/'.date('Y'), 'Nossa Senhora de Aparecida' => '12/10/'.date('Y'), 'Dia de Finados' => '02/11/'.date('Y'), 'Proclamação da República' => '15/11/'.date('Y'), 'Natal' => '25/12/'.date('Y') ); return $feriados; } ?> |
Depois disso, você só precisa informar quantos dias você quer somar, a partir de qual data e se deseja considerar dias úteis ou não:
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?php /** * @author Rodrigo Régis Palmeira <regisbsb@gmail.com> * @param int $soma - dias a serem somados * @param bolean $uteis - considera dias uteis - default false * @param date $data - data inicial válida - default date('d/m/Y') * @return string - data em formado d/m/Y */ function somarData($soma, $uteis = false, $data = null) { $ar = explode("/",$data); if (!empty($ar[0]) && !empty($ar[1]) && !empty($ar[2])) { if (checkdate($ar[1],$ar[0],$ar[2])) { $dia = $ar[0]; $mes = $ar[1]; $ano = $ar[2]; } else { return "Informe uma data válida!"; } } else { $dia = date('d'); $mes = date('m'); $ano = date('Y'); } if ($uteis) { $contDia = 0; $qtdDiasUteis = 0; while ($qtdDiasUteis < $soma) { $contDia++; if (($dias_da_semana = gmdate('w', strtotime('+'.$contDia.' day', mktime(0, 0, 0, $mes, $dia, $ano))) ) != '0' && $dias_da_semana != '6' && (!in_array(date('d/m/Y', mktime(0, 0, 0, $mes, $dia + $contDia, $ano)),retornarFeriados($ano)))) { $qtdDiasUteis++; } } $novaData = date("d/m/Y", mktime(0, 0, 0, $mes, $dia + $contDia, $ano)); } else { $novaData = date("d/m/Y", mktime(0, 0, 0, $mes, $dia + $soma, $ano)); } return $novaData; } ?> |
É isso!
Espero ter ajudado!

abril 23rd, 2010 on 10:06
Sobre o comentário anterior, está errado. Peço desculpa pelo erro que cometi.
abril 23rd, 2010 on 09:52
Atenção que o Carnaval são -47 dias nos anos bisextos e -46 dias nos anos não bisextos.
O Corpo de Deus também não são apenas +60 dias, já que é sempre a uma 5ª feira.
janeiro 25th, 2010 on 09:15
Ele conta somente feriados nacionais (Brasil).
Para acrescentar demais feriados, sugiro que você tenha um cadastro em banco e diferencie feriados com datas fixas dos demais para não precisar ficar cadastrando todos os feriados regionais todos os anos.
janeiro 10th, 2010 on 17:29
não está a contar os feriados, sabes porque será?
outubro 29th, 2009 on 08:44
Você encontrou falha em algum ano?
Se sim então favor me informe a data para que eu possa estudar o erro e corrigir o algorítimo.