DateChooser e horário de verão

7 respostas
duardor

Olá pessoal,

Bom eu já li muita coisa na internet sobre problema de serialização de data e horário de verão entre java e flex.
Eu já estava bem preparado para isso mas fui usar um DateChooser e vi que esse lance de data no Flash Player é uma droga total! Bom, meu background é de muito tempo trabalhando com bibliotecas ajax/html/javascript que têm estes tipo de componente de data e um erro que quase todas as bibliotecas cometem é que quando se têm um componente que seleciona apenas a data, ignorando a hora, e o objeto resultante deste seleção é um Date, a biblioteca considera as horas minutos segundos e milisegundos da data como 0. O problema que ao fazer isso e tentar selecionar a data que acontece o nosso amado horário de verão, as bibliotecas javascript fazem um new Date usando a data selecionada pelo usuário, peguemos como exemplo deste ano 18/10/2009, e consideram nela 0 para todas as outras propriedades (hora, min, seg e ms). Se o windows estiver marcado para ajustar o horário de verão o resultado desta operação será 17/10/2009 23:00:00.
A grande maioria destas bibliotecas percebe o erro e a solução é muito simples: basta considerar que a parte que será ignorada em determinada data não seja 0. Algumas bibliotecas fazem o fix trocando a hora para 12 e isto já resolve a grande maioria dos problemas pois as aplicações só querem saber do componente dia/mes/ano e a hora que é ignorada pode ser qualquer uma que não altere o componente dia/mes/ano.
Ok, como eu já esperava o flex (ou o flash player pelo que me parece) têm o mesmo problema. Pensei comigo então que ao atribuir uma data para um DateChooser que fosse fabricada por mim e não tivesse os componentes de horário iguais a 0 resolveria o problema. Infelizmente parece que o método setter do DateChooser pega minha data e cria uma outra (grande idéia criar um outro objeto sendo que Date é imutável… sigh)… Isto é, se eu criar uma data 18/10/2009 12:00:00 e atribuir esta data com o dateChooser.selectedDate o componente parece que cria outra data com 0 nos componentes de horário e por fim a minha data resultante será 17/10/2009 23:00. O pior de tudo é que o componente dá a impressão ao usuário que a data selecionada é a 18, pois o 18 fica com o fundo “selecionado” mas a data que seria serializada seria 17/10/2009 23:00.

Bom, minha dúvida é: em um cenário que eu não posso simplesmente desmarcar a opção do SO de ajuste de horário, não quero de maneira nenhuma trafegar String (irc!) e também não desejo alterar código fonte de ds, como eu posso solucionar o referido caso? No momento só estou pensando na solução de escrever um componente de DateChooser e DateField e resolver estes problemas por mim mesmo…

Escrevi o seguinte programa para testar estes casos, é bem simples e fácil de entender. É possível ver este mesmo problema na internet até no livedoc, poe exemplo tente seleciona 18/10/2009 no primeiro exemplo de http://livedocs.adobe.com/flex/3/html/help.html?content=controls_12.html.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" >
	
	<mx:Script>
		<![CDATA[
			import mx.events.CalendarLayoutChangeEvent;
			
			import mx.controls.DateChooser;
			import mx.controls.Alert;
			
			public function onOkButton(e:MouseEvent):void
			{
			
				var dt:Date = new Date(2009, 9, 18, 13, 30, 30);
				dateChooser.selectedDate = dt;
				var dt2:Date = dateChooser.selectedDate;
				var dtf:DateFormatter = new DateFormatter();
				
				var msg:String = "";
				
				msg += "Propriedades individuais data bruta: Dia " + dt.getDate()+ " mês " + dt.getMonth() + " ano " + dt.getFullYear()+" hora "+dt.getHours() +" minuto "+dt.getMinutes()+" segundo "+dt.getSeconds()+"\n\n";
				msg += "Propriedades individuais data chooser: Dia " + dt2.getDate()+ " mês " + dt2.getMonth() + " ano " + dt2.getFullYear()+" hora "+dt2.getHours() +" minuto "+dt2.getMinutes()+" segundo "+dt2.getSeconds()+"\n\n";
				msg += "Formatado data bruta: " +(dtf.format(dt)) +"\n\n";
				msg += "Formatado data chooser: " +(dtf.format(dt2)) +"\n\n";
				msg += "As duas datas são o mesmo objeto?: " +(dt == dt2) +"\n\n";
				
				textArea.text = msg;
				
				
			
			}
			
			public function onChangeDateChooser(e:CalendarLayoutChangeEvent):void
			{
				textArea.text = String(e.newDate);
			}
			
		]]>
	</mx:Script>
	
	<mx:DateFormatter id="df"/>
	<mx:DateChooser id="dateChooser" yearNavigationEnabled="true" change="onChangeDateChooser(event);" />	
	<mx:Label  color="blue" text="Date selected: {df.format(dateChooser.selectedDate)}"/>
	<mx:Button id="pesquisarButton" label="Atribuir data 18/10/2009 13:30:30 ao calendário"  click="onOkButton(event);"  />
	<mx:TextArea id="textArea" width="400" height="250" />
	
</mx:Application>

7 Respostas

duardor

Sem solução?
Alguém mais experiente têm algum comentário?

H

Oi Eduardo, tudo bem?

Realmente esse papo de horário de verão é um pouco chato… Eu customizei o DateChooser, não testei muito mais parece que está funcionando

package
{
	import mx.controls.DateChooser;
	import mx.events.CalendarLayoutChangeEvent;

	public class MyDateChooser extends DateChooser
	{
		private var _mySelectedDate:Date;
		
		public function MyDateChooser():void
		{
			addEventListener(CalendarLayoutChangeEvent.CHANGE, onChange);
		}
		
		private function onChange(e:CalendarLayoutChangeEvent):void
		{
			selectedDate = e.newDate;
		}
		
		override public function set selectedDate(value:Date) : void
		{
			_mySelectedDate = value;
			super.selectedDate = value;
		}
		
		[Bindable("change")]
		[Bindable("valueCommit")]
		[Inspectable(category="General")]
		override public function get selectedDate():Date
		{
			return _mySelectedDate;	
		}
		
	}
}

Outra solução seria sobrescrever o método scrubTimeValue, do DateChooser, que faz o corte dos minutos, segundos e etc. Algumas pessoas não sabem que apesar de ser um método com o namespace mx_internal, podemos sobrescreve-lo:

package
{
	import mx.controls.DateChooser;
	import mx.core.mx_internal;
	use namespace mx_internal;
	
	public class MyDateChooser extends DateChooser
	{
		
		override mx_internal function scrubTimeValue(value:Object) : Object
		{
			return value;
		}
	}
}

Neste caso eu consegui resolver um dos problemas (o código acima esta incompleto, foi só para exemplificar sobrescrever o método), que seria continuar com a data cheia, mais acabou dando outros problemas com o CalendarLayout, e não fui a fundo para investigar o pq, fique a vontade :slight_smile:

Espero ter ajudado

[]s,

Henrique

H

Achei um bug, quando selecionamos o dia 18 no click… acho que resolvi somando 12 :slight_smile:

private function onChange(e:CalendarLayoutChangeEvent):void
{
	e.newDate =  new Date(e.newDate.fullYearUTC, e.newDate.monthUTC, e.newDate.dateUTC, 12, 0, 0);
	selectedDate = e.newDate;
}

[]s,

Henrique

D

Olá, alguém sabe se o dateField tem alguma caracteristica diferente do dateChooser? Fiz o mesmo procedimento para o dateField e ele insere a data errada na caixa de texto, mas se eu der um Alert.show da data selecionada ele mostra a data certa.

Obrigado.

D

Resolvido, na função onChange deve-se inserir uma linha:

package componentes
{
	import mx.controls.DateField;
	import mx.events.CalendarLayoutChangeEvent;

	public class myDateField extends DateField
	{
		public var _mySelectedDate:Date;
		public function myDateField():void
		{
			addEventListener(CalendarLayoutChangeEvent.CHANGE, onChange);
		}
		private function onChange(e:CalendarLayoutChangeEvent):void{
			e.newDate = new Date(e.newDate.fullYearUTC, e.newDate.monthUTC, e.newDate.dateUTC, 12,0,0);
			selectedDate = e.newDate;
			//nova linha
			this.text = DateField.dateToString(e.newDate,"DD/MM/YYYY");
		}
		override public function set selectedDate(value:Date):void{
			_mySelectedDate = value;
			super.selectedDate = _mySelectedDate;
		}
		[Bindable("change")]
		[Bindable("valueCommit")]
		[Bindable("close")]
		[Inspectable(category="General")]
		override public function get selectedDate():Date{
			return _mySelectedDate;
		}
		
	}
}
D

Encontrei um problema, a opção allowMultipleSelection não funciona no componente extendido, não sei porque razão. Se alguem souber responder eu agradeço.

R

eu não consegui identificar se este tópico é de java ou javascript. Mas se o assunto é javascript realmente existe um bug muito horroroso em operações envolvendo datas no horário de verão, é que o primeiro dia do horário de verão não existe na primeira hora redonda. Isso é incrível.

Exemplo, no ano de 2011 o horário de verão começou do dia 15/10/2011 para 16/10/2011, então, não existe a hora 16/10/2011 00:00:00.

var hoje=new Date(2011,9,16);
console.log(""+hoje);//Sat Oct 15 2011 23:00:00 GMT-0300 (BRT)

hoje=new Date(2011,9,16,1,0,0);
console.log(""+hoje);Sun Oct 16 2011 01:00:00 GMT-0200 (BRST)

Não é possível deixar esse treco assim?!?! No java, isso não acontece, tanto que a dica é sempre normalizar de fazer qualquer operação envolvendo datas. No javascript esse lógica não tem chance de acontecer. Alguém tem que resolver essa pendenga. Ou o ECMAScript ou o V8 do google. Que lixo.

Criado 29 de outubro de 2009
Ultima resposta 29 de mar. de 2012
Respostas 7
Participantes 4