sexta-feira, 12 de março de 2010

Resolvendo problemas de intervalo de data com Records em Delphi

 
 

Sent to you by fabio.newinf via Google Reader:

 
 

via Andreano Lanusse Blog by Andreano Lanusse on 3/3/10

Record é um tipo de dado que lhe permite estruturar dados, a partir do Delphi 2006 Record se tornou quase uma classe, suportando:

  • Construtores
  • Sobreposição de operadores
  • Declaração de métodos não-virtuais
  • Métodos e propriedades estáticos

Podemos utilizar os Record de várias maneiras, no meu caso utilizo muito em parâmetros  de métodos que devem representar chaves primárias (Primary Key), desta forma facilita a leitura e manutenção do código, é verdade que você não fica mudando as chaves primárias das tabelas do seu banco de dados o tempo todo, mas quando precisar o mudança no código será simples. Outro exemplo seria informar intervalo de dados.

Imagine que você precise gerar um conjunto de boletos de um determinado período, você iria declarar algo assim.

    procedure GerarBoleto( DataInicial, DataFinal : TDateTime );

Geralmente temos problema com periodos, porque os bancos de dados armazenam data e hora no mesmo campo, desta forma temos que na data inicial estar certo que a hora está acertada para '00:00:00′ e para a data final teremos que estar certos de ter como hora final '23:59:59′, existem outros aspectos e artifícios dependendo do banco de dados para contornar esta situação, mas isso depende de cada banco.

Record é uma excelente solução para estes casos, para isso representamos os parâmetros do método GerarBoleto como um Record e ele irá fazer todo o trabalho para evitar os problema de data e hora, assim como facilitar a leitura, entendimento e manutenção do código.

O método passaria a ser declarado assim:

    procedure GerarBoleto( periodo : TPeriodo );

A declaração do Record teria as propriedades DataInicial e DataFinal, estas por suas vez quando receberam valores terão os mesmo ajustados de acordo com os método Set.

Abaixo a declaração do Record e a seguir algumas explicações para o mesmo.

unit Perido;  interface  uses SysUtils, DateUtils;  type    TPeriodo = Record   private     FDataFinal: TDateTime;     FDataInicial: TDateTime;     procedure SetDataFinal(const Value: TDateTime);     procedure SetDataInicial(const Value: TDateTime);    public     property DataInicial: TDateTime read FDataInicial write SetDataInicial;     property DataFinal: TDateTime read FDataFinal write SetDataFinal;      Constructor Create(Di, Df: TDateTime);      procedure SetIntervaloAnual( Anoi, Anof : Integer );   end;  implementation  { TPeriodo }  constructor TPeriodo.Create(Di, Df: TDateTime); begin   DataInicial := Di;   DataFinal := Df end;  procedure TPeriodo.SetDataFinal(const Value: TDateTime); begin   FDataFinal := EncodeDateTime(Yearof(Value), MonthOf(Value), Dayof(Value), 23, 59, 59, 1000); end;  procedure TPeriodo.SetDataInicial(const Value: TDateTime); begin   FDataInicial := EncodeDateTime(Yearof(Value), MonthOf(Value), Dayof(Value), 0, 0, 0, 0); end;  procedure TPeriodo.SetIntervaloAnual(Anoi, Anof: Integer); begin   DataInicial := EncodeDate(Anoi, 1, 1);   DataFinal   := EncodeDate(Anof, 12, 31); end;  end.
  • Toda e qualquer atribuição de valor para DataInicial e DataFinal serão ajustados de acordo com o horário inicial e final
  • Foi criado um método adicional SetIntervaloAnual, onde você pode informar o ano inicial e final para o período e o método irá gerar os intervalos.

Abaixo uma das formas onde podemos utilizar este Record, informando período inicial e final;

var   periodo : TPeriodo; begin   periodo.DataInicial := EncodeDate( 2009, 1, 1);   periodo.DataFinal   := Now;    GerarBoleto(periodo);

Outra forma é passar o período utilizando o construtor do Record

var   periodo : TPeriodo; begin   periodo.Create(EncodeDate( 2009, 1, 1), Now);   GerarBoleto(periodo);

Outra forma seria utilizar o método SetIntervaloAnual, onde você apenas especifica o período anual.

var   periodo : TPeriodo; begin    periodo.SetIntervaloAnual(2008, 2009);    GerarBoleto(periodo);

Em todos os casos, os valores horários foram acertados.

Mas este record pode fazer muito mais por nós, porque não gerar a declaração where do SQL para as datas de acordo com os valores? Dois simples métodos pode resolver todos os problemas.

Field, é o nome do campo que representa a data em sua tabela.

function TPeriodo.DataDBFormat(const Value: TDateTime): String; begin   Result := FormatDateTime('mm/dd/yyyy hh:mm:ss', Value); end;  function TPeriodo.GenerateSQL(Field: String): String; Const   sql: String = '%s between ''%s'' and ''%s'' '; begin   Result := Format(sql, [FieldI, DataDBFormat(DataInicial), DataDBFormat(DataFinal)]); end;

Na prática usamos desta forma:

var   periodo : TPeriodo; begin    periodo.SetIntervaloAnual(2008, 2009);    ShowMessage( periodo.GenerateSQL('DATA_BOLETO'));

O resultado no ShowMessage será: DATA_BOLETO between '01/01/2008 00:00:00′ and '12/31/2009 23:59:59′

Espero que este post seja útil e lhe ajude no seu dia-a-dia. Download código fonte

Até o próximo post.


 
 

Things you can do from here:

 
 

Nenhum comentário: