Campi mysql di tipo Date

Il mio problema me lo porto dietro da tantissimo tempo: le date.

Da un po’ di tempo uso lo UNIX_TIMESTAMP perchè mi viene comodo usare la funzione mktime. Però vorrei fare le cose per bene ora e salvare i dati in formato data. Ora… ho un problema di lingua: la data viene salvata come yyyy-m-d mentre io vorrei dd-mm-yyyy.

Il mio accrocchio per far funzionare le cose è il seguente:




      list($year,$month,$day) = split("-",$ItemScarico->data);

      $Data = date("d/m/Y",mktime(0, 0, 0, $month, $day, $year));



Any suggestions?

1 Like

in mysql non puoi salvare campi DATE in formati diversi da yyyy-mm-dd. Soluzioni

  1. utilizzare la funzione di mysql DATE_FORMAT

SELECT DATE_FORMAT(campo_date, '%d-%m-%Y') FROM item_scarico

  1. se php > 5.2 esiste la funzione date_format() oppure l’oggetto DateTime che ha la funzione format

  2. altrimenti:


$timestamp = strtotime($campo_date);

echo date('d/m/Y', $timestamp);

con il limite del timestamps, quindi solo per date tra 1970 e 2038

Anche io avevo problema con le date… mi sono fatto una bella Yii behavior…

Nota che sul forum si puo trovate codice piu Yii, che usa, per esempio, il dateFormatter di Yii invece di fare la trasformazione manualmente, pero questo behavior io me lo fatto al inizio quando ho cominciato ad usare Yii… e per me lavora a meraviglia…




<?php

/**

 * DateFormater - converts date from/to SQL database (ISO 9075=>"yyyy-mm-dd" to/from dd.mm.yyyy.

 */


class myDateFormat extends CActiveRecordBehavior

{

	//.. array of columns that have dates to be converted

	public $dateColumns = array();


	/**

     * Convert from $dateFormat to ISO 9075 dates before saving

     */

	public function beforeSave($event)

	{

		foreach( $this->dateColumns as $date )

		{

			$_dt = $this->Owner->{$date};

			if(preg_match("/([0-9]{1,2}).([0-9]{1,2}).([0-9]{4})/", $_dt, $regs))

				$_dt = $regs[3]."-".$regs[2]."-".$regs[1];

			$this->Owner->{$date} = $_dt;

		}

		return parent::beforeSave($event);

	}


	/**

     * Converts ISO 9075 dates to $dateFormat after read from database

     */

	public function afterFind($event)

	{

		foreach( $this->dateColumns as $date )

		{

			$_dt = $this->Owner->{$date};

			if(preg_match("/([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})/", $_dt, $regs))

				$_dt = $regs[3].".".$regs[2].".".$regs[1];

			$this->Owner->{$date} = $_dt;

		}

		return parent::afterFind($event);

	}

}



Nel model dove hai campi date fai un nuovo metodo behavior dove dichiari quali campi sono di tipo date




	public function behaviors(){

		return array(

			'myDateFormat'=>array(

				'class'=>'application.components.myDateFormat',

				'dateColumns'=>array('campodata1','campodata2'),

			),

		);

	}



campodata1 e campodata2 sono campi che in database sono di tipo data…

In questo modo ogni volta che Yii fa un find (SELECT) i campi data si convertono nel formato legibile… e ogni volta che i dati si scrivono nel database (INSERT/UPDATE) le date vengono trasformate nel formato mysql…

Nota che io qui uso il formato dd.mm.yyyy… per fare il tuo formato dd-mm-yyyy devi soltanto cambiare i puntini :)

1 Like

Anche io uso questo metodo.

Lo puoi implementare in before safe e after find, in modo da averle sempre nel formato che vuoi:




	public function afterFind()

	{

		parent::afterFind();

		$this->begin= date('d.m.y', strtotime($this->begin));

		$this->end= date('d.m.y', strtotime($this->end));		

	}

	

	public function beforeSave()

	{


		$this->begin= date('Y-m-d', strtotime(substr($this->begin, 3,2).'/'.substr($this->begin, 0,2).'/'.substr($this->begin, 6,2)));

		$this->end= date('Y-m-d', strtotime(substr($this->end, 3,2).'/'.substr($this->end, 0,2).'/'.substr($this->end, 6,2)));

		return parent::beforeSave(); 	

	}




Questo e’ per le maledette date russe con i punti che funzionano male, tu puoi usare la funzione di cui parlava markux

Personalmente ho risolto scrivendomi 2 funzioni per leggere e scrivere le date da MySQL.

Le funzioni sono inserite in una classe ExtActiveRecord che estende CActiveRecord e contiene altre funzioni di utilità.

Tutti i modelli derivano da ExtActiveRecord che mette a disposizione le funzioni sulle date.

// Formatta le date sullo standard MySql (dd/mm/yyyy -&gt; yyyy-mm-dd)


public function dateToMysql(&#036;date)


{


	list(&#036;day,&#036;month,&#036;year)=explode(&quot;/&quot;,&#036;date);


	&#036;mysqldate=&quot;&#036;year-&#036;month-&#036;day&quot;;


	return(&#036;mysqldate);


}











// Formatta le date lette da MySql (yyyy-mm-dd -&gt; dd/mm/yyyy)


public function dateFromMysql(&#036;date)


{


	list(&#036;year,&#036;month,&#036;day)=explode(&quot;-&quot;,&#036;date);


	&#036;date=&quot;&#036;day/&#036;month/&#036;year&quot;;


	return(&#036;date);


}

Spero possa essere utile a qualcuno, ciao

La soluzione di zaccaria mi sembra la più valida: rispetta la struttura di Yii. A mio parere, dovrebbe esserci la possibilità di mettere la gestione del campo data all’interno di Yii. A dire il vero potrebbe essere davveramente utile indicare per ogni campo il tipo di dato:

data

email

numerico

età

in questo modo, nel model si potrebbero impostare poche informazioni e magari far pescare in automatico i plugin come il datepicker di jquery o creare direttamente dropdownList quando il campo è belongs_to (sempre per rispettare lo standard yii).

La soluzioni di Zaccaria ha il diffeto che le due funzioni le devi mettere in tutti i modeli dove hai delle date… e perlopiu le devi cambiare(editare) perche i campi sono fissi ($this->begin, $this->end)…

1 Like

Concordo con mdomba, il suo sistema e’ piu’ fico.

Fa la stessa cosa che faccio io ma con un behavior che potete riciclare nei diversi model.

PS. Ho usato OGGI il tuo behavior. Fantastico. Insieme all’ApplicationConfigBehavior sto facendo un ottimo lavoro. Tutto merito vostro. Ho provato a cercare nel sito il DataFormatter di Yii di cui parlava ma non l’ho trovato così ho deciso di usare il tuo. Questa cosa dei behavior non è subito subito immeditata. Però funzionano. Bello sempre di più questo Yii!

Dunque, mi è servito questo behaviour per dei campi data che ho in una tabella. Continuando a lavorare sullo stesso Model, ho poi dovuto inserire un action afterFind sempre nel model e ora noto che le due cose non lavorano insieme. Praticamente poichè il behaviour lavora proprio sulle action afterfind e before save, è come se la nuova afterfind che ho creato avesse sovrascritto quella del dateformatter…soluzioni?

Innanzi tutto la prima cosa che mi viene da chiedere è questa: se una volta aggiunt il behavior tutto funzionava. Che scopo ha il "nuovo" metodo con lo stesso nome che crea conflitti? Sicuro di non poter usare altre strade?

Con un behavior si solve un problema (per esempio le date)… se che un altro problema ho un altra essigenza di lavorare sui datti si puo farlo nel afterFind() del CActiveRecord - http://www.yiiframew…fterFind-detail

Come dice la documentazione:

Il tuo afterFind lo devi finire con




public function afterFind()

{

   ...

   return parent::afterFind();

}



In questo modo vera chiamatto anche il afterFind() del behavior… dopo del tuo afterFind() nel modulo…

Concordo in pieno. Strano che il team di yii non abbia pensato ad una soluzione così elegante

mdomba in quale file/posizione dichiari questa classe Behavior ?

Grazie ::)

La classe e un file per se, il nome del file e ugualle alla classe - myDateFormat.php… io lo tengo nel folder protected/components…

Ottimo. Funziona alla perfezione.

Sarebbe bello se si potesse anche intercettare e modificare i valori passati da una ricerca; ad esempio quelli della form integrata tramite CGridView in una view "Admin".

Per spiegarmi meglio, prendiamo il metodo search() di un modulo ed impostiamo un criterio per la ricerca di determinati record in base alla data di creazione:


$criteria->compare('t.cr_date', $this->cr_date,true);

poi lasciamo che un utente inserisca la data da ricercare nel formato dd/mm/yyyy.

Se non interveniamo sul valore $this->cr_date trasformandolo in yyyy-mm-dd, la ricerca non produce alcun risultato.

Per ovviare a questo problema (premetto che sono un novizio in yii) ho creato un metodo da inserire direttamente nel modello in questione:




private function reformat($date) {

	$separatore = '/';

	$preg = "/([0-9]{1,2})\\".$separatore."([0-9]{1,2})\\".$separatore."([0-9]{4})/";

	if (preg_match($preg, $date, $regs)) {

		$_dtdb = $regs[3] . "-" . $regs[2] . "-" . $regs[1];

		$_dtrq = $regs[1] . $separatore . $regs[2] . $separatore . $regs[3];

		return str_replace($_dtrq, $_dtdb, $date);

	} else {

		return $date;

	}

}



e facendolo agire nel criterio


$criteria->compare('t.cr_date',  $this->reformat($this->cr_date),true);

ottengo il risultato voluto…

Esiste invece il modo di utilizzare opportunamente il metodo beforeFind() della classe CActiveRecordBehavior, quindi implementando la classe myDateFormat che la estende?

Io non ci sono riuscito e, a prima vista, non ci ho capito un granché!

Grazie!!!!

Ci sono piu modi di fare…

Io per sfrutare lo stesso codice del behavior al inizio chiamo "$this->beforeSave(); " e alla fine $this->afterFind();, ed ho pure fato un metodo soltanto per creare il criteria…




	public function makeCriteria()

	{

		$this->beforeSave();


		$criteria=new CDbCriteria;

		$criteria->compare(...);


		$this->afterFind();

		return $criteria;

	}


	public function search()

	{

		return new CActiveDataProvider(get_class($this), array(

			'criteria'=>$this->makeCriteria(),

		));

	}