Yii Framework Forum: Problema trabalhando com datas - Yii Framework Forum

Jump to content

  • (5 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »
  • You cannot start a new topic
  • You cannot reply to this topic

Problema trabalhando com datas Rate Topic: -----

#1 User is offline   josafafilho 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 08-July 09
  • Location:Brazil

Posted 17 July 2009 - 07:04 AM

All,

Estou com um problema na formatação de datas. Já li inumeras vezes as definições da classe CDateFormatter mas acho que ela não se aplica ao meu caso.

O meu cenário é o seguinte, tenho alguns teares e preciso registrar suas paradas.
Ai devo armazenar a data e a hora do inicio da parada e a data e a hora do fim.
Pra facilitar a vida dos usuarios estou utilizando um CMaskedTextField da seguinte maneira.

$masked = new CMaskedTextField();
$masked->mask = '99/99/9999 99:99';
$masked->model = $model;
$masked->attribute = 'paradaInicio';
$masked->run();


mas quando eu chego no model ele não reconhece este valor como uma data entao eu tratei esse valor para que se transformasse em data no beforeSave do model.

até ai tudo bem.
Mas no caso de existir um erro na minha data ele da um erro

htmlspecialchars() expects parameter 1 to be string, object given

acho que ele exibe isso porque o CMaskedTextField espera uma string e o tipo que está retornando é um objeto DateTime.

Queria que alguem me desse uma luz de como resolver isso.
0

#2 User is offline   theoziran 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 17-July 09

Posted 17 July 2009 - 07:37 AM

Um solução pra isso Josafá seria você guardar o timestamp e a formatação da data você escolheria na hora de recuperar, e o legal é que você não precisa validar apenas gravar o timestamp

:)
0

#3 User is offline   theoziran 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 17-July 09

Posted 17 July 2009 - 07:43 AM

Depois pode formatar a data com desejar

http://www.yiiframew...time-formatting
0

#4 User is offline   josafafilho 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 08-July 09
  • Location:Brazil

Posted 17 July 2009 - 07:50 AM

não da pra fazer com time stamp. Como eu disse ali em cima a data e a hora são digitadas pelos usuários.
0

#5 User is offline   Daniel Augusto Bastos 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 347
  • Joined: 25-May 09
  • Location:Rio de Janeiro - Brasil

Posted 29 July 2009 - 03:28 PM

To com o mesmo problema aqui, com uma pequena diferença, não exibe nenhum erro e a data gravada é = 0.

Aparentemente ele interpreta a data no formato do MySQL(yyyy-mm-dd), mas descobri que, para visualizar corretamente, vc pode usar:
  Yii::app()->dateFormatter->formatDateTime

Neste caso, vc formata a data para o modo corrente da sua aplicação(A formatação da data depende da língua configurada no seu main.php).

Atualmente no controller eu to fazendo a operação inversa, mas, não achei nada no Yii que faça isso automaticamente. Provisóriamente estou fazendo assim:

    public static function DateToDBDate($date){
    	$ar = explode('/', $date);
      return $ar[2].'-'.$ar[1].'-'.$ar[0]; 
    }


Quanto a validação de datas, ví que tem um validador, mas não consegui usar ele :(
Vê se ajuda em alguma coisa.
Every solution creates a problem.
twitter.com/nenhumnick
0

#6 User is offline   josafafilho 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 08-July 09
  • Location:Brazil

Posted 30 July 2009 - 05:35 AM

Daniel

eu estou fazendo algo paracido com isso, porém estou armazenando no banco agora valores inteiros com o Unix Time.

Apesar de exister o dateFormatter, achei ele não muito intuitivo. Espero que esse suporte seja melhorado nas próximas versoes do Yii.

Pra validar eu estou usando a função checkdate do PHP.
0

#7 User is offline   ricardograna 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 376
  • Joined: 31-March 09
  • Location:Manaus/AM - Brazil

Posted 30 July 2009 - 08:27 AM

Para gravar

quebre a data-hora com um explode (ou com pattern, se desejar), e obtenha um time com a função mktime. Referencia: http://www.w3schools...date_mktime.asp



Para exibir as datas
Utilize Yii:app()->dateFormatter
Yes, It Is!
0

#8 User is offline   davi_alexandre 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 113
  • Joined: 08-July 09
  • Location:Guarulhos - São Paulo

Posted 30 July 2009 - 04:29 PM

View PostDaniel A. Bastos, on 29 July 2009 - 03:28 PM, said:

Quanto a validação de datas, ví que tem um validador, mas não consegui usar ele :(
Vê se ajuda em alguma coisa.


Para utilizar a validação de data você pode utilizar o CTypeValidator, assim:

array('data', 'type', 'type'=>'date', 'dateFormat'=>'dd/MM/yyyy'),


Nesse caso, ele vai validar no formato que utilizamos no Brasil.

Para trabalhar com CMaskedTextField aqui eu faço o seguinte:

No afterValidate eu converto do formato dd/MM/yyyy para yyyy-MM-dd, da seguinte maneira:

date('Y-m-d', CDateTimeParser::parse($this->data, 'dd/MM/yyyy'));


Prefiro o CDateTimeParser do que explode + mktime para deixar o código mais legível.

No afterFind eu faço o processo inverso. Assim, todo registro recuperado do banco já vem no formato que eu trabalho:

date('d/m/Y', CDateTimeParser::parse($this->data, 'yyyy-MM-dd'));


Acho que assim o código fica bem legível e bem automatizado.
2

#9 User is offline   Daniel Augusto Bastos 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 347
  • Joined: 25-May 09
  • Location:Rio de Janeiro - Brasil

Posted 30 July 2009 - 04:32 PM

Consegui resolver o problema do validador:
vc pode usar o validador do próprio Yii desta forma:
  public function rules(){
    return array(
      array('emissao', 'type', 'type'=>'date', 'dateFormat'=>'yyyy-MM-dd'),
    );
  }


este codigo é dentro do seu Model. Repare que, quando a data chega no model, ela já está invertida, então é necessário passar a máscara invertida também.

ficou razoável, ainda não está perfeito, mas já ta ajudando.
Every solution creates a problem.
twitter.com/nenhumnick
0

#10 User is offline   josafafilho 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 08-July 09
  • Location:Brazil

Posted 31 July 2009 - 01:52 PM

View Postdavi_alexandre, on 30 July 2009 - 04:29 PM, said:


No afterValidate eu converto do formato dd/MM/yyyy para yyyy-MM-dd, da seguinte maneira:

date('Y-m-d', CDateTimeParser::parse($this->data, 'dd/MM/yyyy'));




Uma coisa que não entendo são essas máscaras, até entendo mas acho chato, já que o php trabalha com um formato e o Yii com outro, tipo no php 'Y' representa um ano com 4 dígitos já no Yii eu tenho que colocar 'yyyy'.
Eu, particularmente, acho a leitura da máscara do Yii mais intuitiva, mas também não sou a favor dessas coisas despadronizadas. Na minha opnião o padrão do php deveria ser seguido já que é um framework php.


View Postdavi_alexandre, on 30 July 2009 - 04:29 PM, said:


Prefiro o CDateTimeParser do que explode + mktime para deixar o código mais legível.



Apesar de ser legível creio que utilizar o explode e o mktime pode deixar o desempenho melhor, já que fazem parte do php e internamente são escritos em C.
Porém não sei até que ponto é válido optar por eles só por causa do desempenho.
0

#11 User is offline   davi_alexandre 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 113
  • Joined: 08-July 09
  • Location:Guarulhos - São Paulo

Posted 01 August 2009 - 12:08 AM

View Postjosafafilho, on 31 July 2009 - 01:52 PM, said:

Uma coisa que não entendo são essas máscaras, até entendo mas acho chato, já que o php trabalha com um formato e o Yii com outro, tipo no php 'Y' representa um ano com 4 dígitos já no Yii eu tenho que colocar 'yyyy'.
Eu, particularmente, acho a leitura da máscara do Yii mais intuitiva, mas também não sou a favor dessas coisas despadronizadas. Na minha opnião o padrão do php deveria ser seguido já que é um framework php.


Também não gosto de usar dois padrões diferentes. Talvez, esse problema seja elimidado utilizando o CDateTimeParser junto com o CDateFormatter. Ambos tem o mesmo padrão.

View Postjosafafilho, on 31 July 2009 - 01:52 PM, said:

Apesar de ser legível creio que utilizar o explode e o mktime pode deixar o desempenho melhor, já que fazem parte do php e internamente são escritos em C.
Porém não sei até que ponto é válido optar por eles só por causa do desempenho.


No geral, otimização precoce não é uma prática recomendável. Afinal, não faz sentido otimizar se nem sabemos onde estão os problemas de desempenho. A boa prática é desenvolver um código simples e legível, sem se preocupar com desempenho. Somente com o software pronto podemos efetuar medições de desempenho, utilizando-se, por exemplo, de profiling para identificar os "gargalos" na aplicação. É muito difícil que simples instruções como essas vão causar alguma diferença notável na aplicação.
0

#12 User is offline   ricardograna 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 376
  • Joined: 31-March 09
  • Location:Manaus/AM - Brazil

Posted 02 August 2009 - 12:53 PM

Boa Josafa, não conhecia CDateTimeParser :)
Yes, It Is!
0

#13 User is offline   josafafilho 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 08-July 09
  • Location:Brazil

Posted 03 August 2009 - 09:40 AM

View Postdavi_alexandre, on 01 August 2009 - 12:08 AM, said:

Também não gosto de usar dois padrões diferentes. Talvez, esse problema seja elimidado utilizando o CDateTimeParser junto com o CDateFormatter. Ambos tem o mesmo padrão.

é uma alternativa!

vou tentar me lembrar disso na próxima app que estiver fazendo, agora que jah comecei de uma maneira não é bom mudar.

View Postdavi_alexandre, on 01 August 2009 - 12:08 AM, said:

No geral, otimização precoce não é uma prática recomendável. Afinal, não faz sentido otimizar se nem sabemos onde estão os problemas de desempenho. A boa prática é desenvolver um código simples e legível, sem se preocupar com desempenho. Somente com o software pronto podemos efetuar medições de desempenho, utilizando-se, por exemplo, de profiling para identificar os "gargalos" na aplicação. É muito difícil que simples instruções como essas vão causar alguma diferença notável na aplicação.


dependendo do que estiver sendo feito com simples instruções podemos ganhar em performance e muito. mas isso é outra história e também não da pra se exigir performance extrema com um framework
0

#14 User is offline   josafafilho 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 43
  • Joined: 08-July 09
  • Location:Brazil

Posted 03 August 2009 - 09:42 AM

View Postrickgrana, on 02 August 2009 - 12:53 PM, said:

Boa Josafa, não conhecia CDateTimeParser :)


acho que o crédito vai pra o davi_alexandre
0

#15 User is offline   ricardograna 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 376
  • Joined: 31-March 09
  • Location:Manaus/AM - Brazil

Posted 03 August 2009 - 03:04 PM

Ah! certo, hehehe
Yes, It Is!
0

#16 User is offline   ricardograna 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 376
  • Joined: 31-March 09
  • Location:Manaus/AM - Brazil

Posted 06 August 2009 - 09:22 PM

Muito bem, só agora trabalhei pra valer com as datas e, graças às várias dicas úteis daqui, consegui fazer!!

Gostaria de quotar alguns posts e sugerir uma solução.

View Postdavi_alexandre, on 30 July 2009 - 04:29 PM, said:

Para utilizar a validação de data você pode utilizar o CTypeValidator, assim:

array('data', 'type', 'type'=>'date', 'dateFormat'=>'dd/MM/yyyy'),


Nesse caso, ele vai validar no formato que utilizamos no Brasil.

Para trabalhar com CMaskedTextField aqui eu faço o seguinte:

No afterValidate eu converto do formato dd/MM/yyyy para yyyy-MM-dd, da seguinte maneira:

date('Y-m-d', CDateTimeParser::parse($this->data, 'dd/MM/yyyy'));


Prefiro o CDateTimeParser do que explode + mktime para deixar o código mais legível.

No afterFind eu faço o processo inverso. Assim, todo registro recuperado do banco já vem no formato que eu trabalho:

date('d/m/Y', CDateTimeParser::parse($this->data, 'yyyy-MM-dd'));


Acho que assim o código fica bem legível e bem automatizado.


Muito obrigado, seu post ajudou bastante. Porém, sugiro duas mudanças: ao invés de fazer a conversao no afterValidate, faça-a no beforeSave.
Colocando no primeiro evento, se houver algum problema de validação, a data volta invertida ao form. Se vc fizer no beforeSave, a data somente é invertida se passar pela validacao.


View PostDaniel A. Bastos, on 30 July 2009 - 04:32 PM, said:

Consegui resolver o problema do validador:
vc pode usar o validador do próprio Yii desta forma:
  public function rules(){
    return array(
      array('emissao', 'type', 'type'=>'date', 'dateFormat'=>'yyyy-MM-dd'),
    );
  }


este codigo é dentro do seu Model. Repare que, quando a data chega no model, ela já está invertida, então é necessário passar a máscara invertida também.

ficou razoável, ainda não está perfeito, mas já ta ajudando.


Se fizer a inversão no beforeSave, vc pode utilizar a máscara como 'dd/MM/yyyy'.



Utilizei suas dicas e dei mais uma incrementada, para utilizar as datas com i18N. No seu model, adicione o seguinte codigo:


protected function beforeSave(){
		$this->mydate = date('Y-m-d', CDateTimeParser::parse($this->mydate, Yii::app()->locale->dateFormat));
		return true;
	}
	
	protected function afterFind(){
		$this->mydate = Yii::app()->dateFormatter->formatDateTime(
					CDateTimeParser::parse($this->mydate, 'yyyy-MM-dd'),'medium',null);
		return true;
	}

        public function rules()
	{
		return array(			
			array('mydate', 'type', 'type'=>'date', 'dateFormat'=>Yii::app()->locale->dateFormat),			
		);
	}


Sim, o codigo da conversao está grande. Porém, penso em criar um componente para efetuar esta conversao ou entao estender o CActiveRecord para reconhecer os campos do tipo data para efetuar a conversao.

Tambem tenho uma duvida existencial: como diferenciar um date de um datetime? no trecho
CDateTimeParser::parse($this->mydate, 'yyyy-MM-dd'),'medium',null);
eu tive de assim fazer pq estava me traduzindo a hora quando não havia. Porém, e quando tiver a hora? :/
Yes, It Is!
1

#17 User is offline   Daniel Augusto Bastos 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 347
  • Joined: 25-May 09
  • Location:Rio de Janeiro - Brasil

Posted 07 August 2009 - 03:56 PM

Salve galera.
Tava meio sem tempo, então só vi as msgs hoje :(


rickgrana

  Vc tem razão. A solução do Davi é bem melhor que a minha. Quando respondi não tinha visto o post dele. (Na verdade, o post dele só fui ver hoje, heheh)


  E, a questão do CDateTimeParser, eu tb não o conhecia. :)

A questão do i18N ficou muito boa. Vou implementar algo parecido. :)


Every solution creates a problem.
twitter.com/nenhumnick
0

#18 User is offline   davi_alexandre 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 113
  • Joined: 08-July 09
  • Location:Guarulhos - São Paulo

Posted 07 August 2009 - 08:25 PM

View Postrickgrana, on 06 August 2009 - 09:22 PM, said:

Muito obrigado, seu post ajudou bastante. Porém, sugiro duas mudanças: ao invés de fazer a conversao no afterValidate, faça-a no beforeSave.
Colocando no primeiro evento, se houver algum problema de validação, a data volta invertida ao form. Se vc fizer no beforeSave, a data somente é invertida se passar pela validacao.


Na verdade no afterFind não acontece esse problema, afinal a inversão é feita depois da validação. Basta apenas checar a existência de erros com o método hasErrors();

Quote

Se fizer a inversão no beforeSave, vc pode utilizar a máscara como 'dd/MM/yyyy'.


Eu usei o afterFind justamente por isso, para poder fazer a validação com essa máscara ;D


Quote

Utilizei suas dicas e dei mais uma incrementada, para utilizar as datas com i18N. No seu model, adicione o seguinte codigo:


Muito legal a idéia de i18n!

Quote

Tambem tenho uma duvida existencial: como diferenciar um date de um datetime? no trecho
CDateTimeParser::parse($this->mydate, 'yyyy-MM-dd'),'medium',null);
eu tive de assim fazer pq estava me traduzindo a hora quando não havia. Porém, e quando tiver a hora? :/


Estranho, aqui o CDateTimeParser não funciona se não informar a formato certo da data. Por exemplo

$data = '1986-02-24 16:15:22';
CDateTimeParser::parse($data, 'yyyy-MM-dd');


O código acima não efetua a conversão porque o formato está errado. Por consequência, o formatDateTime também não funciona. Então o "X" da questão aqui é como passar o formato certo para o parse.

Talvez tentando pegar o tipo de dado da coluna, utilizando CDbColummSchema e setando a mascara adequada seja uma solução, no caso de um componente. Para aplicações mais simples, acho que não há problema em deixar o formato fixo.
0

#19 User is offline   ricardograna 

  • Advanced Member
  • PipPipPip
  • Yii
  • Group: Members
  • Posts: 376
  • Joined: 31-March 09
  • Location:Manaus/AM - Brazil

Posted 07 August 2009 - 08:41 PM

View Postdavi_alexandre, on 07 August 2009 - 08:25 PM, said:

Na verdade no afterFind não acontece esse problema, afinal a inversão é feita depois da validação. Basta apenas checar a existência de erros com o método hasErrors();

Eu usei o afterFind justamente por isso, para poder fazer a validação com essa máscara ;D


Mas falei que dava problema com afterValidate, nao com o afterFind, esse ta perfeito. O problema do afterValidate é que ele é executado depois da validacao independentemente se houve erro ou nao. Por isso, prefiro o beforeSave, aonde já nao preciso checar hasErrors()



View Postdavi_alexandre, on 07 August 2009 - 08:25 PM, said:

Estranho, aqui o CDateTimeParser não funciona se não informar a formato certo da data. Por exemplo

$data = '1986-02-24 16:15:22';
CDateTimeParser::parse($data, 'yyyy-MM-dd');


O código acima não efetua a conversão porque o formato está errado. Por consequência, o formatDateTime também não funciona. Então o "X" da questão aqui é como passar o formato certo para o parse.

Talvez tentando pegar o tipo de dado da coluna, utilizando CDbColummSchema e setando a mascara adequada seja uma solução, no caso de um componente. Para aplicações mais simples, acho que não há problema em deixar o formato fixo.


Realmente nao funciona. O que me acontecia era o contrario: minha datanao tinha hora e a hora era adicionada quando convertia (tava me referindo ao resultado do formatDateTime, nao ao parse)

Mas A questao do date/datetime ja resolvi (na mesma linha de pensanmento que a sua).

Postei em http://www.yiiframew...__0

e reproduzo aqui:
protected function beforeSave(){
        foreach($this->metadata->tableSchema->columns as $columnName => $column){
                if ($column->dbType == 'date'){
                        $this->$columnName = date('Y-m-d', CDateTimeParser::parse($this->$columnName, Yii::app()->locale->dateFormat));
                }elseif ($column->dbType == 'datetime'){
                        $this->$columnName = date('Y-m-d H:i:s', CDateTimeParser::parse($this->$columnName, Yii::app()->locale->dateFormat));
                }
        
        }
        
        return true;
}
        

protected function afterFind(){
                                                
        foreach($this->metadata->tableSchema->columns as $columnName => $column){
                        
                if (!strlen($this->$columnName)) continue;
                        
                if ($column->dbType == 'date'){                         
                        $this->$columnName = Yii::app()->dateFormatter->formatDateTime(
                                        CDateTimeParser::parse($this->$columnName, 'yyyy-MM-dd'),'medium',null);
                        }elseif ($column->dbType == 'datetime'){
                                $this->$columnName = Yii::app()->dateFormatter->formatDateTime(
                                        CDateTimeParser::parse($this->$columnName, 'yyyy-MM-dd hh:mm:ss'));
                        }
        }
        return true;
}


Neste codigo, o ActiveRecord já vai atrás de todas as colunas date/datetime e efetua as devidas conversoes.
Yes, It Is!
0

#20 User is offline   davi_alexandre 

  • Standard Member
  • PipPip
  • Yii
  • Group: Members
  • Posts: 113
  • Joined: 08-July 09
  • Location:Guarulhos - São Paulo

Posted 07 August 2009 - 09:29 PM

View Postrickgrana, on 07 August 2009 - 08:41 PM, said:

Mas falei que dava problema com afterValidate, nao com o afterFind, esse ta perfeito. O problema do afterValidate é que ele é executado depois da validacao independentemente se houve erro ou nao. Por isso, prefiro o beforeSave, aonde já nao preciso checar hasErrors()


Falha minha ^^ Eu quis dizer afterValidate mesmo. Mas realmente, o beforeSave é um lugar melhor mesmo.


Ficou bem legal a forma como você fez! Agora é só colocar em um componente e utilizar nos modelos onde for necessário!

Ah, uma dica, você pode trocar o $this->metadata->tableSchema por $this->tableSchema.
0

Share this topic:


  • (5 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users