Como gerar datas automaticamente com PHP

Nov 7, 2010 by     21 Comments    Posted under: PHP

Trabalhar com data e hora e valores monetários é bastante complexo em qualquer linguagem que se venha utilizar. Apesar da grande flexibilidade que o PHP oferece com suas funções pré-definidas, também existe uma grande dificuldade por parte dos programadores, principalmente iniciantes, quando o assunto é data, hora ou valores.

Esta semana me deparei com um bom desafio que não havia encontrado ainda, mas sabia que mais cedo ou mais tarde aconteceria. Tratava-se de montar um script ou função para gerar e calcular automaticamente todas as datas de vencimento de um orçamento parcelado, partindo da data da primeira parcela informada pelo usuário do sistema.

A princípio, parece muito fácil, mas não é assim tão simples. Vamos ao código:


function geraParcelas($numParcelas, $venc_parcelas) {

$meses = array();

$venc_parcelas = implode("-", array_reverse(explode("/",$venc_parcelas)));

$venc_parcelas = strtotime($venc_parcelas);

for ($i = 0; $i < = $numParcelas - 1; $i++) {

$meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc_parcelas) + $i date('d',$venc_parcelas), date('Y',$venc_parcelas)));
}
}

Vamos à explanação do código acima realizando um teste de mesa simples:
Imagine os seguintes valores para os parâmetros:

$venc_parcelas = "10/11/2010";
$numParcelas = 6;

Na linha 2, crio um array ou vetor para guardar todas as datas que serão geradas.

Em seguida (linha 3), coloco a data no formato americano aaaa/dd/mm, pois é nesse formato que o php trabalha.

Com a função stringtotime(), linha 4, converto essa data de string para formato data. Na linha 5, inicio um laço de repetição cujo limite é o número de parcelas que devem ser geradas ($numParcelas).

Na linha 6 é que acontece a grande mágica, onde o vetor meses[] extrai em formato de data cada parte da data inicial (primeiro o mês, depois o dia e o ano). Porém ao mês é acrescentado o valor do contador $i. É com esta soma que se consegue fazer com que o mês seja alterado em cada execução do laço, ficando assim:

$meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',2010-11-10) + $i, date('d',2010-11-10), date('Y',2010-11-10)));

Como 2010-11-10 está em formato data e não string, o próprio php se encarrega de incrementar o ano sempre que o mês corresponder a um valor maior que 12 e também altera o mês 13 para 01 (janeiro), fazendo com que as datas sejam geradas corretamente.
Para testar, basta jogar o código em uma página php e mandar imprimir o vetor:


echo $meses[$i];

É isso ai!! Agora basta gravar o vetor em banco de dados usando um novo laço de repetição… mas isso já é outra história… Em breve colocarei outros tutoriais… Portanto, volte sempre! ;)

Referência: www.php.net

UPDATE

Como solicitado por nosso amigo no comentário, segue explicação de como gravar as datas em banco de dados.

Para isso, pode-se utilizar o mesmo laço de repetição anterior e já ir gravando conforme for gerada a data. Retire a impressão e coloque o código abaixo no lugar:


$sql = "INSERT INTO prestacoes (id, vencimento) VALUES (' ', '$meses[$i]')";

$query = mysql_query($sql);

É isso! Caso queiram mais alguma implementação, peçam nos comentários. Até o próximo post.

No related posts.

21 Comments + Add Comment

  • Muito bom o tópido …Mas..
    Não consegui obter resposta com o codigo abaixo , mesmo dando um echo na $meses…
    Acho que não esta funcionando..

  • Olá, Leonardo, tudo bem?
    Obrigado pelo comentário…
    Para imprimir a resposta é necessário usar a função print_r(), assim: print_r($meses). Você tentou assim?

    Abs.

  • Então Sergio , estou tentando de várias formas, reduzi o codigo para caber.. segue código para análise.. aguardo seu breve retorno, estou precisando muito dessa resposta.. Obrigado a atenção.
    function geraParcelas($numParcelas, $venc_parcelas)
    {
    $venc_parcelas = “2010-11-10″;
    $numParcelas = “6″;
    $mesPgto = substr($venc_parcelas,5,-3);
    $meses = array();
    $venc = strtotime($venc_parcelas);
    for ($i = 0; $i <= $numParcelas-1; $i++)
    {
    $mesPgto += 1;
    $mth = $mesPgto – 12;
    $meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc) + $mth, date('d',$venc), date('Y',$venc)));
    print_r($meses);
    }
    }

  • Fla, Leonardo, blza?
    Então… o código em si está blza… a única coisa que vi errado foi na função substr() que vc colocou 5 para a posição inicial e -3 para a qtde de caracteres… não entendi o por quê.

    Uma vez que sua data está no formata americano: 2010-11-10, para pegar o mês apenas, ficaria assim: substr($venc_parcelas,6,2) que resultaria em 11, o mês informado. Verifique se não é isso.

    Repare que a posição 5 de 2010-11-10 retorna ‘-’, o que deve estar dando erro na conta, por isso retorna vazio. Não tenho certeza se é esse o problema, mas tenta ai do jeito que te falei e me diz o que aconteceu, blza.

  • Sergio , testei de tudo que foi forma e nada .. essa questão que vc falou alterei mas nada mudou !!!

  • Olá, leonardo.

    Acho que o que aconteceu foi a questão de caracteres especiais errados quando você copiou do site para seu editor. Pelo menos foi o que aconteceu comigo agora a pouco: o dreamweaver não reconheceu as aspas e o sinal de subtração.

    Então fiz alguns ajustes no código e testei novamente o código. Está tudo fungando, conforme pode ver neste exemplo: http://tecinove.com/teste/index.php
    Abaixo está o código POO funcionando corretamente:

    class Parcelas {
    function geraParcelas() {
    $venc_parcelas = “2010-11-10″;
    $numParcelas = 6;
    $mesPgto = substr($venc_parcelas,5,2);
    $meses = array();
    $venc = strtotime($venc_parcelas);

    //print $mesPgto; break;

    for ($i = 0; $i <= $numParcelas – 1; $i++) {
    $mesPgto += 1;
    $mth = (int)$mesPgto – 12;
    $meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc) + $mth, date('d',$venc), date('Y',$venc)));
    print $meses[$i]."”;
    }
    }
    }

    $minhasParcelas = new Parcelas();

    //print_r($minhasParcelas->geraParcelas());

    $minhasParcelas->geraParcelas();

    OBS: Vc pode testar usando o print_r(), basta descomentar esta linha e comentar a de baixo.

    Segue o código em programação estruturada:

    $venc_parcelas = “2010-11-10″;
    $numParcelas = 6;
    $mesPgto = substr($venc_parcelas,5,2);
    $meses = array();
    $venc = strtotime($venc_parcelas);

    //print $mesPgto; break;

    for ($i = 0; $i <= $numParcelas – 1; $i++) {
    $mesPgto += 1;
    $mth = (int)$mesPgto – 12;
    $meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc) + $mth, date('d',$venc), date('Y',$venc)));
    print $meses[$i]."”;
    }

    Espero que dê certo ai pra vc.

    Abs.

  • Po sergio , por incrível que pareça , copio e colo o código e não vai !!!
    Tem como vc me enviar o arquivo dele funcionando ???

    Ta dando esse erro aqui : Parse error: syntax error, unexpected T_STRING, expecting ‘;’ in /home/storage/2/4b/50/sistemasfavo/public_html/TESTE/datas.php on line 10

    LINHA 10 – for ($i = 0; $i <= $numParcelas–1; $i++) {

    VALEU !

  • Olá Leonardo.

    Acho que o problema está exatamente no ctrl+c e ctrl+v…

    Ao colar no editor, por incrível que pareça o mesmo não reconhece os sinais de subtração e também as aspas duplas. Verifique se não é esse o seu problema ai…

    De qualquer forma, segue o anexo funcionando. (foi no seu e-mail)
    At+

  • Enviado por email pelo leitor Leonardo:

    “Fala Sergio …

    Baixei e testei …. consegui visualizar as informações mas não tive a resposta correta .
    gostaria de saber o seguinte: porque quando coloquei o mes “02″ aparece coisa de 2009 ou seja ano anterior ?
    porque sempre aparece a data do mês anterior ao que foi informado ?

    PARA ESSES PARAMENTROS:

    $venc_parcelas = “2010-02-10″;
    $numParcelas = 6;

    2009-05-10
    2009-06-10
    2009-07-10
    2009-08-10
    2009-09-10
    2009-10-10
    =======================================
    $venc_parcelas = “2010-09-10″;
    $numParcelas =10;

    2010-07-10
    2010-08-10
    2010-09-10
    2010-10-10
    2010-11-10
    2010-12-10
    2011-01-10
    2011-02-10
    2011-03-10
    2011-04-10
    2011-05-10″

  • Ok, realmente havia um erro de lógica no código. Segue abaixo a correção, mas o post também já está corrigido.

    class Parcelas {
    function geraParcelas() {
    $venc_parcelas = “2010-11-10″;
    $numParcelas = 36;
    $meses = array();
    $venc = strtotime($venc_parcelas);

    for ($i = 0; $i < = $numParcelas - 1; $i++) {
    $meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc) + $i, date('d',$venc), date('Y',$venc)));
    print $meses[$i]."
    “;
    }
    }
    }

    $minhasParcelas = new Parcelas();
    $minhasParcelas->geraParcelas();

    Abs.

  • SERGIO , OBRIGADO PELA AJUDA , FUNCIONOU PERFEITAMENTE.

  • Sergio , boa noite !

    Então consegui colocar pra funcionar o script de datas que você mandou e agora me surgiu uma dúvida …
    Como faço para inserir no banco essas informações ???
    Valeu aguardo seu retorno.

  • Olá, Leonardo.

    Para inserir no banco de dados… vc tem que percorrer o vetor com as datas geradas. E para cada posição do vetor realizar um INSERT no banco gravando o conteúdo daquela posição. Mais ou menos assim:

    class Parcelas {
    function geraParcelas() {
    $venc_parcelas = “2010-11-10?;
    $numParcelas = 36;
    $meses = array();
    $venc = strtotime($venc_parcelas);

    for ($i = 0; $i < = $numParcelas – 1; $i++) {
    $meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc) + $i, date('d',$venc), date('Y',$venc)));
    //print $meses[$i];

    }

    $sucesso = 0;
    $erro = 0;

    for ($j = 0; $j < = sizeof($meses) – 1; $j++) {
    $sql = "INSERT INTO parcelas (id_parcela,vencimento) VALUES ('','$meses[$j]')";
    $query = mysql_query($sql);

    if ($query) { // verifica se o insert foi executado com sucesso
    $sucesso += 1; // grava a quantidade de sucessos
    } else {
    $erro += 1; // grava a quantidade de erros
    }

    }

    // verifica quantas mensagens vezes gravou com sucesso e quantas gravou com erro
    echo "Foram salvos ".$sucesso." registros com sucesso!”;
    echo $erro.” registros não foram salvos!”;
    }
    }

  • Bom dia pessoal,

    Uma pergunta, estou precisando de algo similar para um fluxo de caixa, mais dessa maneira tem um BUG. Entrem com o seguinte parametro
    vencimento = 30/11/2010;
    parcelas = 6;

    notem que o mes de fevereiro irá jogar para março e não considerar o ultimo dia util do mês que seria 28 ou 29;

    2010-11-30
    2010-12-30
    2011-01-30
    2011-03-02
    2011-03-30
    2011-04-30

    Obrigado

  • RESOLVIDO

    $venc_parcelas = “30/11/2010″;
    $numParcelas = 6;

    geraParcelas($numParcelas, $venc_parcelas);

    function geraParcelas($numParcelas, $venc_parcelas)
    {
    $meses = array();
    $venc_parcelas = implode(“-”, array_reverse(explode(“/”,$venc_parcelas)));
    $venc_parcelas = strtotime($venc_parcelas);

    for ($i=1;$i<=$numParcelas;$i++)
    {

    $data= date('Y-m', mktime(0,0,0,(date('m',$venc_parcelas)+$i),'01', date('Y',$venc_parcelas)));
    $qtdDias = cal_days_in_month(CAL_GREGORIAN, substr ($data,5,7), substr ($data,0,4));

    if(date('d',$venc_parcelas) <= $qtdDias)
    {
    $meses[$i] = date('Y-m-d', mktime(0,0,0,date('m',$venc_parcelas) + $i, date('d',$venc_parcelas), date('Y',$venc_parcelas)))."”;
    }else{
    $meses[$i] = date(‘Y-m-d’, mktime(0,0,0,date(‘m’,$venc_parcelas) + $i, $qtdDias , date(‘Y’,$venc_parcelas))).”";
    }
    }

    }

  • //Quantidade de dias do mes
    $qtdDias

    //Se o dia do vencimento no ano e no mes corrente forem maiores que o dia do vencimento
    então a data de vencimento vai ser o ultimo dia daqueles mes
    if(date(‘d’,$venc_parcelas) <= $qtdDias)

  • Olá, Éder, blza?
    Obrigado por compartilhar mais esses detalhes conosco.

    Vlew.

  • Eu q agradeço, tava precisando disso ontem, e o script q achei aqui foi bem util, mas enfrentei o mesmo problema, mas pesquisando consegui acertar os ajustes…

  • Olá Sergio!!!

    Parabéns pelo código!!!

    vi funcionando na sua pagina teste, estou enfrentado o mesmo problema de copiar e colar vc poderia enviar o codigo pro meu email obrigado.

  • Olá Sergio!!!

    Parabéns pelo código!!!

    Vc poderia enviar o codigo funcionando pro meu email?

    Muito obrigado

  • Olá, Fábio.
    Obrigado pelo comentário.
    O código acima está funcionando corretamente, basta copiar e adaptar as suas necessidades.
    Abs.

Got anything to say? Go ahead and leave a comment!

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Refresh



Arquivo

November 2010
S M T W T F S
« Oct   Dec »
 123456
78910111213
14151617181920
21222324252627
282930  

Tags