Calcular e exibir datas no intervalo com PHP

Calendário dia 31
  • 20 de Abr de 2013
  • 8438 Visualizações
  • 31 Comentários

Esses dias tive que fazer uma rotina para exibir todas as datas dentro de um certo intervalo estipulado pelo cliente.

Exemplo

Se o usuário digitou a data 20/04/2013 e 25/04/2013, a rotina teria que exibir obrigatoriamente todas datas dentro deste limite, que seriam as seguintes datas, exatamente:

  • 20/04/2013
  • 21/04/2013
  • 22/04/2013
  • 23/04/2013
  • 24/04/2013
  • 25/04/2013

Inicialmente isso me pareceu super simples e até foi. Segue abaixo a minha rotina para imprimir todas as datas dentro do intervalo solicitado.

<?php
    //Star date
    $dateStart 		= '20/04/2013';
    $dateStart 		= implode('-', array_reverse(explode('/', substr($dateStart, 0, 10)))).substr($dateStart, 10);
    $dateStart 		= new DateTime($dateStart);

    //End date
    $dateEnd 		= '25/04/2013';
    $dateEnd 		= implode('-', array_reverse(explode('/', substr($dateEnd, 0, 10)))).substr($dateEnd, 10);
    $dateEnd 		= new DateTime($dateEnd);

    //Prints days according to the interval
    $dateRange = array();
    while($dateStart <= $dateEnd){
        $dateRange[] = $dateStart->format('Y-m-d');
        $dateStart = $dateStart->modify('+1day');
    }

    var_dump($dateRange);
?>

Vamos para explicações

1 - Entre as linhas 01 e 10 eu faço o tratamento da data de início e fim utilizando a classe DateTime do PHP.

2 - Entre as linhas 13 e 17, eu faço um loop em busca de todos os dias deste intervalo. Perceba que na linha 16 eu somo um dia na variável $dateStart.

3 - E finalmente na linha 19 eu imprimo todos as datas que estão dentro deste intervalo.

Você tem alguma outra forma de exibir todas datas dentro de um intervalo? Aproveite e sugira comentando abaixo!

TAGS: cakephp, calcular datas, calcular intervalo data, datetime, tiagomatosweb

Deixe um comentário


31 Comentários

    • Muito bom o código. Pelo o que entendi ele coloca todas as datas do intervalo em uma array. Existe algum jeito de comparar esse array com outro array e exibir o número de dias que são iguais? Sugere alguma documentação?

      • Olá Davis, sim tem como! Você pode fazer de duas formas:

        1) Na unha para você ter liberdade: você vai pegar o $array_data1 e dar um foreach nele. Aí dentro desse foreach você vai pegar o $array_data2 e dar outro foreach. Aí dentro deste último foreach você irá colocar as suas condições (if, else, >, <, ==, !=, etc...)



        2) Usando array_intersect(): aqui basta você ter os dois arrays $array_data1 e $array_data2 e executar a função array_intersect($array_data1, $array_data2) e pronto, o PHP irá te dar os arrays com os mesmos valores. E se ainda você quiser saber os diferentes, é só usar array_diff().



        Dúvidas, acesse 
        http://php.net/array_diff e http://php.net/array_intersect



        Espero ter ajudado. 

    • Queria agradecer ao Tiago por postar esta lógica, pois nós seguidamente deparamos com estas situações que acaba nos pegando desprevenidos e com isso perdemos tempo e paciência.
      Fiz algumas alterações usando este método para atender as minhas necessidades.
      Contudo a situação ficou assim:
      A pessoa informa em um formulário de pesquisa a data inicial e data final. Após isso o script cria os intervalos de datas desde o início informado até o final informado.
      Mas não retorna todos os dias e sim o primeiro dia do mês e o seu último.
      Estou postando abaixo os códigos para quem quiser fazer o uso.
      Peço desculpas por eventuais erros.
      Segue o link: http://pastebin.com/nwvfD36H
      Um abraço a todos.

      • Olá Beto, obrigado pela colaboração!

    • Perfeito, favoritada na minha biblioteca de cod... :D valeu pela dica...

      • Valeu Bruno! \o/

    • De 01/10/2013 à 31/10/2013 não funciona. =(

      • Na verdade funciona, o que aconteceu é que o timezone do seu servidor deve estar setado como "America/Sao_Paulo". Assim quando a contagem chega no dia 20/10, automaticamente adiciona 1h. Então, a comparação vai por água a baixo.
        Faça um teste para comparar da seguinte forma: onde tem a classe DateTime, instancie ela dessa forma: "new DateTime($dateStart, new DateTimeZone('America/Sao_paulo'));" e "new DateTime($dateEnd, new DateTimeZone('America/Recife'));". Agora analise a diferença! Espero ter ajudado. Abs.

        • Show Tiago!

          Só corrija ali no seu comentário o correto é: new DateTime($dateEnd, new DateTimeZone(‘America/Recife’));

          "$dateEnd"

          Mas isso é garantido para todas as datas?

          Um abraço!

          • Sim, é garantido! Obrigado e espero ter ajudado!

    • Bom dia Pessoal.
      Estou com uma dúvida cruel aqui que está me quebrando a cabeça, caso alguem puder me ajudar eu ficaria muito grato.
      Seguinte:

      Estou desenvolvendo um sistema para escola, onde o aluno paga mensalmente sua mensalidade.
      Hoje eu consigo criar uma fatura manualmente, onde o aluno entra em sua área de trabalho e imprime seu boleto, já no layout do banco e tal..

      O meu problema é: Como eu faço para pegar todos os alunos do banco de dados, gerar uma fatura para cada um deles (valores iguais para todos) e imprimir todos os boletos em um impressora... tudo isso automático???
      Estou tendo muitas duvidas com for no php, pois venho do asp e estou apanhando bastante.... caso puderem detalhar seria de grande ajuda!!

      Att,
      Thiago

      • Olá Thiago, neste caso você tem que fazer uma consulta no banco pegando todos os dados necessários. Após isso criar uma rotina para que o PHP leia esses dados, monte o boleto e dê saída na impressora. Para imprimir, sugiro usar uma função javascript. Espero ter ajudado. Abs.

    • Tiago, muito obrigado cara...valeu pela tua ajuda que foi primordial pro trabalho..Um grande abraço e que Deus te abençôe

    • Boa tarde Tiago, muito obrigado cara...vc me deu uma luz...já estou conseguindo efetuar a diferença esntre as datas, só que a data final sempre tá dando um dia a menos...
      Não estou conseguindo fazer a consulta.Olha o código como ficou:

      while($iddatainizio3 format('Y-m-d');
      $iddatainizio3 = $iddatainizio3->modify('+1day');

      }

      foreach($dateRange_form as $k => $v){

      //verifica se um indice do array de datas do formulário está contido no array de datas do banco. Se sim, coloca o resultado em um novo array
      if(in_array($v, $dateRange_db)){
      $newDate[] = $v;
      }
      }

      //exibindo o novo array de datas, as que estão correlacionadas

      //////////////////////////////////////////////////////////////////////////////////////// Já tentei fazer a consulta e não consegui...tipo if (empty($newDate)){
      echo "Não existe hóspedes cadastrados"
      }

      echo "

      ";
      print_r($newDate);
      echo "
      ";

      • Charles, o código ficou meio bagunçado! Cria um gist e me envia. Abs.

        • Cara...já resolvi...Sem sua ajuda seria muito mais difícil...Obrigado Tiago e que Deus te abençôe cara.Valeu mesmo.

          • Tranquilo Charles. Eu que agradeço! Abs e boa sorte!

    • Bom dia Tiago, será que você pode me ajudar??
      ainda não resolvo o problema e estou ha um tempão tentando calcular datas vindas do banco e outras vindas do formulário, se alguém puder me ajudar serei muito grato...Já consegui pegar as sequencias de datas vindas tanto do formulário quanto do banco de dados Mysql. Só não consigo verificar entre elas qual as datas repetidas. Estou fazendo um programa para um hotel e preciso que o dono consulte se há vagas disponíveis. Abaixo segue o código:

      <?php
      include("conecta.php");
      $id_hospedagem = $_POST["hospedagem"];
      $data_entrada1=$_POST["data_entrada"];
      $data_entrada2=explode("/", $data_entrada1);
      $data_entrada= $data_entrada2[2]."-".$data_entrada2[1]."-".$data_entrada2[0];

      $data_saida1=$_POST["data_saida"];
      $data_saida2=explode("/", $data_saida1);
      $data_saida= $data_saida2[2]."-".$data_saida2[1]."-".$data_saida2[0];

      $hospedagem_tipo=explode("-",$hospedagem);
      $id_hospedegem = $hospedagem_tipo[0];
      $tipo_hospedegem = $hospedagem_tipo[1];
      $valor_hospedegem = $hospedagem_tipo[2];


      // CALENDÁRIO para pegar todas as datas do início ao final para fazer a comparação
      $banco_datas_form = mysql_query("SELECT * FROM periodi2013 WHERE datainizio BETWEEN '$data_entrada' AND '$data_saida'");

      // pega os índices do CALENDÁRIO para pegar todas as datas do início ao final para fazer a comparação
      $banco_datas = mysql_query("SELECT * FROM prenota2013 WHERE id_hospedagem='$id_hospedagem'");


      while($row2 = mysql_fetch_array($banco_datas))
      {
      $iddatainizio = $row2["iddatainizio"];
      $iddatafine = $row2["iddatafine"]+1;

      /////////////////////////////////// Pega as datas do banco...são várias sequencias de datas de entrada e saida

      $banco_recebe = mysql_query("SELECT * FROM periodi2013 WHERE idperiodi BETWEEN '$iddatainizio' AND '$iddatafine'");

      while($row3 = mysql_fetch_array($banco_recebe))
      {
      $row2_form = mysql_fetch_array($banco_datas_form);

      //////////////////////////////////// resultado das datas do formulário
      $periodo = $row2_form["datainizio"];



      $iddatainizio3 = $row3["datainizio"];
      $iddatafine3 = $row3["datafine"];
      for ($counter = $iddatainizio3; $counter <= $iddatafine3; $counter += 1)
      {

      ////////////////////////////////////// resultado das data vinda do banco
      echo $counter ."";

      NÃO CONSIGO VERIFICAR SE OS DIAS SÃO REPETIDOS
      ////////////////////////////////////// resultado da data vinda do formuário
      echo $periodo ."";


      }
      }
      }

      • Olá Charles, para identificar as datas repetidas fazendo essa comparação de datas do intervalo do banco X intervalo do formulário faça o seguinte: 1) Coloque os dois intervalos em um array. 2) Depois faça um foreach em um dos intervalos, sugiro o do form, para percorrer todo o array do intervalo do form. 3) Use a função in_array do php para fazer essa comparação, dentro do foreach. 4) Pegue o resultado e coloque de novo em um novo array. Veja esse pequeno código que fiz para você ter uma idéia: https://gist.github.com/anonymous/e1407a4cc0e27664e0d6. OBS: Quando for postar códigos, utilize o gist ou algo similar.

    • Boa noite Tiago, estou fazendo um banco de dados para um hotel, vou postar aqui minha dúvida e se você responder irá me ajudar bastante:
      Tenho duas tabelas com data de entrada e outra de saída, o cliente quer que quando o apartamento estiver ocupado ele saiba através de um form e busca.
      Já consegui através do método DateTime pegar todas as datas mas estou quebrando a cabeça pra fazer o casamento da pesquisa com o que está banco:
      Olha meu código:
      while($row2 = mysql_fetch_array($result_rec)){

      $data_recebe1=$row2["data_entrada"];
      $data_recebe2=explode("-", $data_recebe1);
      $entrada= $data_recebe2[2]."-".$data_recebe2[1]."-".$data_recebe2[0];


      $data_saida1=$row2["data_saida"];
      $data_saida2=explode("-", $data_saida1);
      $saida= $data_saida2[2]."-".$data_saida2[1]."-".$data_saida2[0];

      /////////////////

      $one= new DateTime($entrada);
      $two = new DateTime($saida);

      // Resgata diferença entre as datas
      $dateInterval = $one->diff($two);
      $dia1 = $dateInterval->days;

      $i = new DateInterval('P1D');
      $d = new Datetime($entrada);


      foreach(new DatePeriod($d, $i, $dia1) as $d) {
      $nova_data = $d->format('d-m-Y') ."";
      //echo $nova_data."";
      echo $nova_data;
      }



      /////////////////

      }

      • Olá Charles, eu não entendi bem o que você precisa. Mas me parece que você quer comparar datas, é isso? Tente colocar as datas no formato padrão do banco (AAAA-MM-DD) e compare normalmente com if, exemplo: if($data1 > $data2){ echo "aqui" }. Será que resolve? Veja se é isso e me retorne. Abs.

        • Obrigado pela resposta Tiago, não é isso não...As datas já estão no formato date.
          Exemplo: entrada (2013-10-21), saída (2013-10-31).
          Preciso das datas entre as datas acima em sequencia para fazer a validação do form ( <?
          Tenho um formulário que escolhe as datas: Assim: dia entrada e dia saida e faz a procura dentro das datas q
          Eu até consegui pegar as datas entre elas com o código abaixo mas quando vou fazer a verificação:
          $one= new DateTime($entrada);
          $two = new DateTime($saida);

          // Resgata diferença entre as datas
          $dateInterval = $one->diff($two);
          $dia1 = $dateInterval->days;

          $i = new DateInterval('P1D');
          $d = new Datetime($entrada);


          foreach(new DatePeriod($d, $i, $dia1) as $d) {
          $nova_data = $d->format('d-m-Y') ."";
          //echo $nova_data."";
          echo $nova_data;
          }

          • Desculpe Charles, mas acho que ainda não entendi muito bem. Veja se é isso: você quer exibir as datas de um intervalo, no caso de 2013-10-21 até 2013-10-31. Isso o Post já ensina certo? Agora, seu form vai enviar uma data e você quer saber se esta data enviada está dentro do intervalo descrito? Se for isso, faça os seguinte: pegue o intervalo de datas e coloque todos em um array, após isso você verifica com a função in_array do php, dessa forma: if(in_array('date string'), $array_date){ echo "aqui" }. Veja mais em: http://www.php.net/in_array. Resolve?

            • Tiago, você não sabe como está me ajundando. Obrigado cara...Acho que estou no caminho...mas ainda estou quebrando a cabeça...Você pode continuar me ajudando??
              Vou postar aqui o link da página pra vc dar uma olhada:
              http://www.hotelnossacasa.tur.br/admin/teste13_1.php

              O resultado pega dois intervalos de hospedagem no banco...Um do dia 2013-10-21 até dia 2013-11-06 e outro do dia 2013-11-08 ao dia 2013-11-12...Acho que tenho que unir os dois pra ter um resultado, né assim?? Usei var_dump(array_diff_key($dateRange_form, $dateRange)); mas parece que não deu certo...Sei que estais me ajudando de bom coração e não quero te perturbar...Te agradeço muito pois esse trabalho tá me deixando meio pirado...Já tem agluns dias que estou nele...Posto aqui o código, se vc puder dar uma olhada te agradeço muito:
              http://www.hotelnossacasa.tur.br/admin/teste_13_3.php

              • Opa Charles, claro que ajudo! Afinal de contas, o objetivo do blog é este. Mas, de fato não ficou 100% claro pra mim qual é o seu objetivo. Veja se é isso: você quer identificar se o intervalo de datas passado pelo forma equivale ao intervalo de data do banco? É isso?

    • Muito bom, parabens, me ajudou em um projeto.

      • Olá Ronaldo! Quem bom que te ajudou de alguma forma. Fico feliz em saber. Obrigado por se dar o trabalho em escrever no meu blog. Abs.

    • Muito bom, espero mais dicas e tutoriais bons como esse!

      • Olá Rafael, sim, sempre que eu passar por algum tipo de "problema" durante o desenvolvimento, eu irei compartilhar com a comunidade. Obrigado por ter visitado meu blog. Abs.

    • Olá Tiago, muito bom seu artigo. Tenho um problema com datas, onde preciso exibir todos os registros dos útimos 12 meses, a partir do mês atual. Por exemplo:

      Mês atual: abril.

      Então tenho que exibir os registros de maio/2012 até abril/2013
      Como posso fazer isso?
      Valeu e parabéns pelo excelente artigo.

      • Olá Julio, obrigado pelos elogios, isso me motiva a manter a filosofia do blog. :)
        Sobre sua dúvida, você poderia unir a função date com strtotime.
        Experimente exibir o resultado desta linha de código: "date('Y-m-01', strtotime('-1 year'));" que você irá entender.
        Espero ter ajudado.
        Um abraço!