Calcolo giorni lavorativi tra due date (escluse le feste comandate)

Maures

Utente Attivo
25 Mar 2015
45
0
0
Buongiorno a tutti,
devo creare uno script per il calcolo dei giorni lavorativi fra due date.
Sfruttando questo codice sono riuscito nel mio intento, ma ora mi si pone un problema.
Come potete vedere, il codice inserisce manualmente in un array le feste, costringendo poi il programmatore a modificarle di volta in volta ogni anno. inoltre se dovessi fare il calcolo a cavallo di due anni, non funzionerebbe. come rendere dinamico questo array?
Come aggiungo a questo array anche la pasqua, che non è mai nello stesso giorno?

Grazie a tutti.
 

borgo italia

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
4 Feb 2008
16.042
146
63
PR
www.borgo-italia.it
ciao
questa considera festivi solo il sabato e la domenica
se vuoi anche le altre devi farti un array con le date delle feste (es 25/04, 01/06....)
poi con date("d/m",$timestamp) verifichi che non sia sabato o domenica ma se festa decrementi
il problema l'hai con la data di pasqua variabile di anno in anno

PHP:
<?php
function giorni_lav($d1,$d2){
	$d_i=explode("-",$d1);//attento al formato delle date che hai tu
	$d_f=explode("-",$d2);
	$d_i_ts=mktime(0,0,0,$d_i[1],$d_i[0],$d_i[2]);//espressa in secondi TIME STAMP
	$d_f_ts=mktime(0,0,0,$d_f[1],$d_f[0],$d_f[2]);
	$g_ts= 24*60*60;//secondi in un giorno
	$quanti_giorni=(int)(($d_f_ts-$d_i_ts)/$g_ts-1);//giorni totali compresi i festivi
	while($d_i_ts < $d_f_ts){
		//7=domenica, 6=sabato
		if(date("N",$d_i_ts)== '6' || date("N",$d_i_ts)== '7'){
			$quanti_giorni -= 1;// se trovo un sabato o una domenica decremento l'intervallo
		}
		$d_i_ts +=$g_ts;//incrementa l'iniziale di un giorno
	}
	return $quanti_giorni;
}
// test
$data_inizio="01-06-2015";
$data_fine="13-06-2015";
echo "giornate lavorative ".giorni_lav($data_inizio,$data_fine);
//OUTPUT giornate lavorative 9
?>
 

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
Ciao, anche il lunedi di pasqua è festa. credo
Puoi provare a calcolarlo con questa funzione.
Secondo me nel link che hai postato, la seconda soluzione che hanno proposto ( number_of_working_days() ) si adatta meglio alle tue esigenze ed è molto più semplice da modificare. Necessita però di php 5.3.0 o superiore visto l'utilizzo della classe DateTime()
 

borgo italia

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
4 Feb 2008
16.042
146
63
PR
www.borgo-italia.it
ciao
criric ha ragione, che cada di domenica la pasqua è risaputo e quindi basterebbe calcolarla come domenica, ma anche lunedì è festivo e quindi da determinare quindi secondo me si dovrebbe:
determinare la datqa della pasqua e aggiungere un giorno
verificare se la pasqua cade tra le due date richieste e togliere dai lavorativi il lunedi
se ti interessa vado a ripescare una funzione che avevo fatto e che calcolava la data per ogni anno con l'algoritomo di gaus

@criric
la funzione number_of_working_days() non credo che consideri le festività locali e quindi secondo me da fare sempre un array con tali date
 

criric

Super Moderatore
Membro dello Staff
SUPER MOD
MOD
21 Ago 2010
5.607
54
48
TN
Si l'array delle festività locali è inevitabile.
Avevo iniziato a buttar gìù un idea ma poi mi sono bloccato, posto la bozza incompleta
PHP:
function Pasqua($anno) {

    $nc = intval($anno / 100);
    $nn = $anno - 19 * intval($anno / 19);
    $nk = intval(($nc - 17) / 25);
    $ni1 = $nc - intval($nc / 4) - intval(($nc - $nk) / 3) + 19 * $nn + 15;
    $ni2 = $ni1 - 30 * intval($ni1 / 30);
    $ni3 = $ni2 - intval($ni2 / 28) * (1 - intval($ni2 / 28) * intval(29 / ($ni2 + 1)) * intval((21 - $nn) / 11));
    $nj1 = $anno + intval($anno / 4) + $ni3 + 2 - $nc + intval($nc / 4);
    $nj2 = $nj1 - 7 * intval($nj1 / 7);
    $nl = $ni3 - $nj2;

    $mese = 3 + intval(($nl + 40) / 44);
    $giorno = $nl + 28 - 31 * intval($mese / 4);

    return $anno . "-" . $mese . "-" . $giorno;
}

function festivo($data = false) {

    $check = new DateTime();
    if (!$check->createFromFormat('Y-m-d', $data)) {
        return "data non valida";
    }

    $d = new DateTime($data);
    $pasqua = new DateTime(Pasqua($d->format("Y")));

    $festivita = array(
        "01-01" => "Capodanno",
        "01-06" => "Epifania",
        "04-25" => "Festa della liberazione",
        $pasqua->format("m-d") => "Pasqua",
        $pasqua->modify("+1 day")->format("m-d") => "Lunedi' dell'Angelo",
        "05-01" => "Festa dei lavoratori",
        "06-02" => "Festa della repubblica",
        "08-15" => "Ferragosto",
        "11-01" => "Festa di tutti i santi",
        "12-08" => "Festa dell'immacolata",
        "12-25" => "Natale",
        "12-26" => "Giorno di Santo Stefano"
    );
    if (!$data) {
        return $festivita;
    }
    if (array_key_exists($d->format('m-d'), $festivita)) {
        return $festivita[$d->format('m-d')];
    }
    if ($d->format('w') == 0) {
        return "Domenica";
    }

    return false;
}

var_dump(festivo(date("Y-m-d")));
edit:
ops, avevo troncato, cmq ho sbagliato script
 
Ultima modifica:

marino51

Utente Attivo
28 Feb 2013
2.955
171
63
Lombardia
vedi se ti va bene,
ciao
Marino

PHP:
<?php
  $holidayDays = 
  [
    "*-01-01"=>"Capodanno",
    "*-01-06"=>"Epifania", 
    "*-04-25"=>"Liberazione", 
    "*-05-01"=>"Festa Lavoratori", 
    "*-06-02"=>"Festa della Repubblica", 
    "*-08-15"=>"Ferragosto", 
    "*-11-01"=>"Tutti Santi", 
    "*-12-08"=>"Immacolata", 
    "*-12-25"=>"Natale", 
    "*-12-26"=>"Santo Stefano",
    "*-08-16"=>"Patrono"
  ];

$DataInizio	= '2015-01-01';
$DataFine	= '2015-12-31';

$AnnoInizio	= date('Y', strtotime($DataInizio));
Pasqua($AnnoInizio);
$holidayDays[$AnnoInizio."-".$Lmese."-".$Lgiorno] = "Pasquetta ".$AnnoInizio;

$AnnoFine	= date('Y', strtotime($DataFine));
if($AnnoFine != $AnnoInizio) {
  Pasqua($AnnoFine);
  $holidayDays[$AnnoFine."-".$Lmese."-".$Lgiorno] = "Pasquetta ".$AnnoFine;
}
echo $DataInizio." --> ".$DataFine."<br /><br />";
echo "number_of_working_days = ".number_of_working_days($DataInizio, $DataFine, $holidayDays)."<br /><br />";
print_r ($holidayDays);


function number_of_working_days($from, $to, $holidayDays, $workingDays = [1, 2, 3, 4, 5]) 
{
  $holidayDays = array_flip($holidayDays);

  $from = new DateTime($from);
  $to = new DateTime($to);
  $to->modify('+1 day');
  $interval = new DateInterval('P1D');
  $periods = new DatePeriod($from, $interval, $to);

  $days = 0;
  foreach ($periods as $period) {
    if (!in_array($period->format('N'),   $workingDays)) continue;
    if ( in_array($period->format('Y-m-d'), $holidayDays)) continue;
    if ( in_array($period->format('*-m-d'), $holidayDays)) continue;
    $days++;
  }
  return $days;
}

function Pasqua($anno) { 
  global $Pmese,$Pgiorno,$Lmese,$Lgiorno; 

  $nc=intval($anno/100); 
  $nn=$anno-19*intval($anno/19); 
  $nk=intval(($nc-17)/25); 
  $ni1=$nc-intval($nc/4)-intval(($nc-$nk)/3)+19*$nn+15; 
  $ni2=$ni1-30*intval($ni1/30); 
  $ni3=$ni2-intval($ni2/28)*(1-intval($ni2/28)*intval(29/($ni2+1))*intval((21-$nn)/11)); 
  $nj1=$anno+intval($anno/4)+$ni3+2-$nc+intval($nc/4); 
  $nj2=$nj1-7*intval($nj1/7); 
  $nl=$ni3-$nj2; 

  $Pmese=3+intval(($nl+40)/44); 
  $Pgiorno=$nl+28-31*intval($Pmese/4); 

  if ($Pmese == 3 and $Pgiorno == 31) { $Lmese = 4; $Lgiorno = 1; } 
  else { $Lmese = $Pmese; $Lgiorno = $Pgiorno + 1; } 
} 
?>
Codice:
2015-01-01 --> 2015-12-31

number_of_working_days = 255

Array ( [*-01-01] => Capodanno [*-01-06] => Epifania [*-04-25] => Liberazione [*-05-01] => Festa Lavoratori [*-06-02] => Festa della Repubblica [*-08-15] => Ferragosto [*-11-01] => Tutti Santi [*-12-08] => Immacolata [*-12-25] => Natale [*-12-26] => Santo Stefano [*-08-16] => Patrono [2015-4-6] => Pasquetta 2015 )