Creare un set di date a seconda del frazionamento scelto da inserire in MySQL

francescoITA

Nuovo Utente
10 Gen 2020
12
0
1
Ciao a tutti,
sono nuovo del forum e del mondo php al quale ho dovuto - causa forza maggiore - avvicinarmi per cui vi chiedo clemenza per eventuali errori banali

Ho bisogno di una mano con uno script che sto tentando (invano) di finire
In pratica partendo da un dato e una data , a seconda del frazionamento contenuto nella variabile $data06 dovrò creare e inserire in una tabella MySQL il dato replicato con N date

Per esempio se $data06 = “annuale” e $data03 = “2019/01/01”

Il programma dovrà creare 5 scadenze annuali :

2019/01/01

2020/01/01

2021/01/01

2022/01/01

2023/01/01


Se $data06=“semestrale” dovrà crearmi 10 scadenze intervallate di 6 mesi in 6 mesi , sempre fino al 2023/01/01 ...


Purtroppo però ho necessità che la variabile $data03 sia una stringa e non riesco a convertire da data a stringa e pertanto nella parte finale del codice va in errore e mi inserisce (nel caso di frazionamento annuale, solo le prime 2 annualità)

Spero di essere stato abbastanza chiaro :

Questo è lo spezzone di codice incriminato
PHP:
  switch ($data06) {

          

                        case 'annuale':

                            $numrate = 5;

                            $aumdata = "+12 months";                           

                            break;

                      

                        case 'semestrale':

                            $numrate = 10;

                            $aumdata = "6 month";

                            break;

                          

                        default:

                            echo "errore nel frazionamento";

                            break;

                    }

                  

                  

                  

                  

                  

                    //IMPORTO IL PRIMO DATO COSì COME è, QUINDI LA PRIMA SCADENZA

                    $sql = "INSERT into $nometb (

                            nominativo,        scadenza

                                ) values (

                            '$data01',     '$data03'

                                )";

                        if ($conna->query($sql) === TRUE) {} else {die('ERRORE NELL\'IMPORTAZIONE'. $conna->error); }

          

                    //CREO ED IMPORTO LE RATE SUCCESSIVE

                    $newDate = date_create($data03);

                  

                    for ($mul = 2; $mul <= $numrate; ++$mul) {

                                              

                      

                        $datanuova = date_create($data03);

                        $datanuova->modify($aumdata);

                        $datanuova->format('yy/m/d');

                        $newDate = $datanuova->format('yy/m/d');

                      

                      

                        $sql = "INSERT into $nometb (

                                nominativo,        scadenza

                                ) values (

                            '$data01',     '$newDate'

                                )";

                      


//QUI C'E' l'errore perche' dovrei convertire la data $newDate in stringa per ricominciare il ciclo

//ed ho la necessita' che $data03 sia una stringa !!



                        $data03 = $newDate;


                      

                      

                        if ($conna->query($sql) === TRUE) {} else {die('ERRORE NELL\'IMPORTAZIONE'. $conna->error); }

                    }

          

              

                }

            }

        }
con queto cosdice, mi inserisce solo due record e poi esce dallo script

come posso risolvere?

mille grazie a chi mi aiuterà

francesco
 
Ultima modifica di un moderatore:
credo che tu possa avere dei problemi usando date di fine mese,
la data di inizio mese non evidenzia i 28, 29, 30 e 31 che possono slittare ai primi del mese successivo usando "+ x months"
e sfalsando poi tutta la sequenza,

ti propongo questo codice, che dovrai integrare con la gestione del db se vorrai usarlo
PHP:
<?php
$data06 = "annuale";
$data03 = "2019/02/28";

$data06 = "semestrale";
$data03 = "2019/08/31";

switch ($data06)
{
    case "annuale":
    $numrate = 5;
    $aumdata = "+1 year";
    break;

    case "semestrale":
    $numrate = 10;
    $aumdata = "+6 months";
    break;

    default:
    echo "errore nel frazionamento";
    die;
    break;
}
$giorno = (new DateTime($data03))->format("d");                      // estrae il giorno dalla data


echo "<h3>".$data06."</h3>";

echo $data03."<br />";                                               // prima data da considerare E DA SCRIVERE NEL DB
for ($i=1; $i<$numrate; $i++)
{
$data03 = DateCalc($data03, $giorno, $aumdata);
echo $data03."<br />";                                               // date successive da considerare E DA SCRIVERE NEL DB
}


function DateCalc($dt, $dd, $dp="")
{
    $dt = new DateTime($dt);                                         // usa la data

    $d = $dd;                                                        // usa il giorno
//  echo $d."<br />";

    $dt = $dt->format("Y/m/01");                                     // ottiene la data al primo giorno del mese
//  echo $dt."<br />";

    $dt = new DateTime($dt);                                         // usa la nuova data
    if (!empty($dp)) $dt = $dt->modify($dp);                         // la modifica se necessario

    $ld =  $dt->modify('last day of this month')->format("d");       // ottiene l'ultimo giorno del mese
//  echo $ld."<br />";

    $d = min($d, $ld);                                               // definisce il giorno da usare
//  echo $d."<br />";

    return $dt->format("Y/m/").$d;                                   // ritorna la data formattata
}
?>

questo il risultato per un semestrale

1578701699865.png


funziona correttamente anche con l'annuale
 
se vuoi gestire il fine mese puoi sostituire $giorno = (new DateTime….. con
PHP:
$dt = new DateTime($data03);
$cd = $dt->format("d");                                              // estrae il giorno dalla data
$ld = $dt->modify('last day of this month')->format("d");            // ottiene l'ultimo giorno del mese
$giorno = ( $cd == $ld ) ? "31" : $cd;                               // gestisce il fine mese

con questo risultato ( partendo dal 28 )

1578702785582.png
 
Basterebbe parametrizzare un pò per evitare l'uso di if e switch....

Per quanto riguarda la gestione dei bisestili:
Freq: Scadenza mensile
Inizio il 29-01-2019
->29-02-2019 (non esiste -> skip to 01-01-2019), da questo momento in poi la data del 29-02 non sarà più utilizzata...

Differenza tra l'utilizzo di P1M e P1D, scadenza mensile non calcola i giorni del mese, quindi segue il normale andamento mensile (come anche gli abbonamenti di vario genere) adattando la scadenza al primo giorno utile, cosa ben diversa sarà scadenza P1D dove ritroveremo sempre il 29-02-XXXX in caso di anni bisestili...
Altra nota, non si avrà MAI una scadenza al 29 Feb XXXX in quanto sarebbe non lineare...
Facendo un piccolo esempio si potrebbe notare che quasi tutte le scadenze fiscali si trovano a ($M/2)+-6.

Questa differenza è da considerarsi una delle grandi discrepanze tra Anno Solare e Anno Commerciale...
Infatti i giorni per anno commerciale (quindi in caso di abbonamenti) sono sempre 360, invece i giorni dell'anno solare possono essere da 365 a 366 come il 2020.


PHP:
function scheduler_map($scheduler){
   $map=
   [
      'giornaliera'=>'P1D',
      'settimanale'=>'P1W',
      'mensile'=>'P1M',
      'trimestrale'=>'P3M',
      'quadrimestrale'=>'P4M',
      'semestrale'=>'P6M',
      'annuale'=>'P1Y'
   ];
   return $map[$scheduler]??$map['annuale'];
}

/**
* @param string $start Data nel formato Y-m-d
* @param string $scheduler Stringa in scheduler_map
* @param string $duration Data nel formato Y-m-d
*
* @return array Dates
* @throws Exception
*/
function __init__($start,$scheduler,$duration){
   $period=scheduler_map($scheduler);
   $init_date=new DateTime();
   $init_date->setTimestamp(strtotime($start));
   $end=new DateTime();
   $end->setTimestamp(strtotime($duration));
   $dates=[];
   $dates[]=$init_date->format('Y-m-d');
   while($end->getTimestamp()>$init_date->getTimestamp()){
      $init_date->add(new DateInterval($period));
      $dates[]=$init_date->format('Y-m-d');
   }
   return $dates;
}


Per richiamare il tutto
PHP:
print_r(__init__(data_inizio,'trimestrale',data_fine));

-------------------------------------------
ES.

Un piccolo esempio di output con parametri in ingresso:
PHP:
print_r(__init__('2019-12-29','mensile','2021-06-01'));

Risultato:
Array
(
[0] => 2019-12-29
[1] => 2020-01-29
[2] => 2020-02-29
[3] => 2020-03-29
[4] => 2020-04-29
[5] => 2020-05-29
[6] => 2020-06-29
[7] => 2020-07-29
[8] => 2020-08-29
[9] => 2020-09-29
[10] => 2020-10-29
[11] => 2020-11-29
[12] => 2020-12-29
[13] => 2021-01-29
[14] => 2021-03-01
[15] => 2021-04-01
[16] => 2021-05-01
[17] => 2021-06-01
)
Effettuando una piccola modifica alla funzione di map, per l'esattenza "'mensile'=>'P30D'," il risultato è il seguente:




Array
(
[0] => 2019-12-29
[1] => 2020-01-28
[2] => 2020-02-27
[3] => 2020-03-28
[4] => 2020-04-27
[5] => 2020-05-27
[6] => 2020-06-26
[7] => 2020-07-26
[8] => 2020-08-25
[9] => 2020-09-24
[10] => 2020-10-24
[11] => 2020-11-23
[12] => 2020-12-23
[13] => 2021-01-22
[14] => 2021-02-21
[15] => 2021-03-23
[16] => 2021-04-22
[17] => 2021-05-22
[18] => 2021-06-21
)
Questa situazione la si nota con il nuovo sistema di fatturazione a 30GG delle compagnie Telefoniche, con fatturazione a 30 GG e data di recapito/scadenza fatture sempre diversi....
 
Ultima modifica:
Wow siete due geni
Ora mi studio entrambe le soluzioni che - ammetto - non sono semplicissime per le mie conoscenze e provo ad integrarle nel codice

Intanto ringrazio entrambi per la disponibilità
Francesco


Inviato dal mio iPhone utilizzando Tapatalk
 
@francescoITA

Da regolamento del forum, come tutti noi sei tenuto ad usare il tag
CODE.JPG
quando posti del codice generico, o il tag
PHP (2).png
quando posti codice PHP oppure la funzione codice dalla barra degli strumenti
box inserisci.png

Inoltre IMPORTANTE: Prima di creare una nuova discussione o di rispondere alle discussioni esistenti ricordati di leggere attentamente il Regolamento del Forum e l'eventuale regolamento specifico della sezione!
Grazie

Per questa volta te lo sistemo io ma mi raccomando per il futuro
 
@francescoITA

Da regolamento del forum, come tutti noi sei tenuto ad usare il tag Vedi l'allegato 6887 quando posti del codice generico, o il tag Vedi l'allegato 6888quando posti codice PHP oppure la funzione codice dalla barra degli strumenti
Vedi l'allegato 6889
Inoltre IMPORTANTE: Prima di creare una nuova discussione o di rispondere alle discussioni esistenti ricordati di leggere attentamente il Regolamento del Forum e l'eventuale regolamento specifico della sezione!
Grazie

Per questa volta te lo sistemo io ma mi raccomando per il futuro

Chiedo scusa mi era sfuggito


Inviato dal mio iPhone utilizzando Tapatalk
 

Discussioni simili