Erro em cálculo com hora!

Delphi

17/12/2007

Preciso dividir um determinado tempo em pedaços iguais onde o cliente determina a hora inicial, a hora final e o intervalo, só que o delphi está calculando errado.
Ex: hora inicial = 08:00, hora final = 08:30, intervalo = 15 minutos
Programa:
For I := 1 to Cont + 1 do
Begin
...HoraInicial := IncMinute(HoraInicial, Intervalo); // se der um showmessage aqui, a hora está correta
...If HoraInicial = HoraFinal then
......Break
...Else If HoraInicial > HoraFinal then
......Showmessage(´mensagem´);
End;
Nesta circunstância a resposta está OK, porém se a diferença entre a hora inicial e a hora final for maior que 30 minutos, não dá certo de jeito nenhum.
Aguém sabe o porquê disto?


Edilcimar

Edilcimar

Curtidas 0

Respostas

Massuda

Massuda

17/12/2007

Como TDateTime é um ponto flutuante, sempre existe a possibilidade de haver imprecisões nos cálculos. Explique o que seu loop faz.


GOSTEI 0
Felipeucc

Felipeucc

17/12/2007

Olá amigo,

Acredito que o erro esteja no For I := 1 to[color=red:4fdd7fb557] Cont + 1[/color:4fdd7fb557] do

Apesar de não ter especificado o que faz esse for, acredito que não precise do + 1 no Cont.

Verifique se é isso ou dê mais detalhes sobre o código.

Mas, dizer o que o Delphi está fazendo errado.... essa foi boa. hehehhe.

Não leve a mau, mas o Delphi fez o que você programou.

Abraços


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

O loop está certo, a conta está certa, eu estou mandando o delphi fazer exatamente aquilo que está escrito e ele está fazendo conta errada.
Quanto ao Cont + 1 eu preciso dele, pois quero ver se o cliente não colocou por exemplo hora incial = 08:00, hora final = 8:50 e intervalo = 15. Se eu colocar apenas o Cont, ele vai até 8:45, mas com Cont + 1 ele vai até 09:00, passando portanto das 08:50 e mostrando para o cliente que a hora final está errada pois 50 minutos não é divisível por 15 minutos!
Coloque o meu código num form e execute para ver se dá certo!


GOSTEI 0
Massuda

Massuda

17/12/2007

Mas de onde vem o Cont? Pelo que entendi, a pessoa informa HoraInicial, HoraFinal e Intervalo, é isso?


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

Este Cont é uma conta que faço para ver quantos consultas caberiam entre a hora inicial e a hora final.
Cont := Trunc(Hora * 24 * 60 / Intervalo); no exemplo de 1 hora e intervalo de 15 minutos isto retorna 4


GOSTEI 0
Felipeucc

Felipeucc

17/12/2007

Que valor é atribuido a hora ?
não vi como o resultado disso pode ser 4.


GOSTEI 0
Massuda

Massuda

17/12/2007

O que afinal está calculando errado?


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

Desculpe esqueci de escrever
Hora := HoraFinal - HoraInicial


GOSTEI 0
Felipeucc

Felipeucc

17/12/2007

Amigo,
Aconselho que dê uma estudada na Library DateUtils (pode ser acessada pelo help do Delphi). Lá você encontrará várias funções que podem dar uma simplificada no seu código.

Exemplo: Substitua o código que atribui valor a sua variavel cont por
MinutesBetween(DateTimePicker2.DateTime, DateTimePicker1.DateTime);

Faça uma verificação de Cont div Intervalo <> 0 then
mensagem que intervalo deve ser divisivel pelo periodo... (algo do tipo)


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

Incialmente eu olhei as funções de hora do help do delphi, e não achei algo a contento. O MinutesBeteween() vai me informar a quantidade de minutos entre uma hora inicial e outra final, o que quero é saber quantos ´pedaços´ de intervalos cabem entre a hora inicial e final, para poder calcular se a hora final informada pelo cliente está correta, conforme informei anteriormente, a estrutura que eu montei não tem erro de lógica, o problema está em:
Hora Inicial = 08:00 - Intervalo = 15 minutos
Hora Final = 08:15 -> ok funciona direito
Hora Final = 08:30 -> ok funciona direito
Hora Final = 08:45 -> erro, a conta não bate mais daqui para frente, qualquer que seja o múltiplo de 15 minutos.
O que quero saber é o porquê o delphi me dá este erro?
Se eu der um showmessage(timetostr(hora)), após cada soma, ela está correta, sem nenhum defeito, porém quando faço comparação com a hora final, apesar do showmessage() mostrar a hora correta, internamente o delphi diz que está errado!


GOSTEI 0
Felipeucc

Felipeucc

17/12/2007

O delphi interpreta data e hora com número float onde o valor antes da virgula representa a data e depois da virgula representa a hora. (use o debug) onde o dia 0 equivale a 30/12/1899. E não recomendo o uso de Trunc para cálculo de datas e horas.


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

Se você reparar, vai ver que uso Trunc não para fazer conta com horas, mas para calcular o Cont (quantidade de intervalos no período), portanto aí não importa se uso trunc ou div, eu pego inicialmente a hora inicial e final de 2 maskedit, já dei showmessage() em cada linha, tudo que é mostrado na tela está correto, pode ser que o erro seja de arredondamento, mas se o erro existe, por que ele não aparece no showmessage()? Outra coisa, se existe erro de arredondamento o que devo usar? DecodeDate e depois EncodeDate para fazer as comparações?
E se fizer isto ainda assim não vai continuar a haver erro de arredondamento?


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

segue o código completo com comentário
procedure TForm19.MaskEdit8Exit(Sender: TObject);
Var I, Consultas : Word;
begin
...HoraInicial := StrToTime(MaskEdit1.Text);
...MaskEdit8.Color := clWhite;
...Try
......If Trim(MaskEdit8.Text) <> ´:´ then
.........HoraFinal := StrToTime(MaskEdit8.Text);
...Except
......ShowMessage(´Esta não é uma hora válida´);
......MaskEdit8.SetFocus;
...End;
...Hora := HoraFinal - HoraInicial;
...If Hora <= 0 then
...Begin
......ShowMessage(´Horário final tem que ser maior que horário inicial´);
......MaskEdit8.SetFocus;
...End;
...Consultas := Trunc(Hora * 24 * 60 / Intervalo);
...For I := 1 to Consultas + 1 do
...Begin
......HoraInicial := IncMinute(HoraInicial, Intervalo);
......If (HoraInicial = HoraFinal) then
.........Break
......Else If (HoraInicial > HoraFinal) then
......Begin
.........ShowMessage(FormatDateTime(´hh:mm:ss:zzz´, horainicial) + ´ ´ + FormatDateTime(´hh:mm:ss:zzzz´, horafinal)); //////// se a diferença for de 45 minutos ou mais aqui mostra a hora com até os milisegundos iguais, isto foi colocado apenas para efetuar comparação de tempo
.........ShowMessage(´A divisão de tempo entre hora inicial´ + #13 + 10 + ´e hora final, em função do intervalo,´ + 13 + 10 + ´está errada, refaça as contas´);
.........MaskEdit8.SetFocus;
......End;
...End;
end;

O intervalo de tempo usado foi 15 minutos, hora inicial 08:00 (mas pode ser qualquer uma), se hora final for múltiplo de 15 mas maior que 30 minutos, dá erro
???????????????????????????????????


GOSTEI 0
Fknyght

Fknyght

17/12/2007

Cara, tente fazer o seguinte
coloque dois maskedits no form, um edit e um memo e tente o codigo abaixo

procedure TForm1.Button1Click(Sender: TObject);
Var HI , HF : TTime; Intervalo : Integer;
begin
  Memo1.Lines.Clear;
  try HI := StrToTime( MaskEdit1.Text ); except HI := 0; end;
  try HF := StrToTime( MaskEdit2.Text ); except HF := 0; end;
  Intervalo := StrToIntDef(Edit1.Text,15);
  
  if ( ( HI <> 0 ) and ( HF <> 0 ) ) then
    Begin
      While HI <= HF do
        Begin
          Memo1.Lines.Add ( TimeToStr( HI ) );
          HI := HI + StrToTime(´00:´ + IntToStr(Intervalo) + ´:00´ );
        End;
    End
  else
    ShowMessage(´Hora inválidas´);
end;


Lembre-se que se você tiver que fazer calculos com data e hora você tem que fazer no formato de data e hora, nao pode colocar valores inteiros ok


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

fknyght, valeu, este teu macete funcionou


GOSTEI 0
Edilcimar

Edilcimar

17/12/2007

Houve um problema aqui
While HI <= HF do -> você não compara se HI = HF, eu preciso que existe esta possibilidade para avisar, e no teu caso alguma hora HI vai ser maior que HF, portanto não funcionou como pensei que funcionaria, está acontecendo o mesmo que acontecia anteriormente


GOSTEI 0
POSTAR