Rodrigo Régis

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!

:, , , , , ,

5 Comments for this entry

Leave a Reply

Looking for something?

Use the form below to search the site:

Still not finding what you're looking for? Drop a comment on a post or contact us so we can take care of it!

Blogroll

A few highly recommended websites...

Archives

All entries, chronologically...