[Resolvido]Calcular periodo de horas entre duas datas

Galera estou encontrado um seguinte problema.

Preciso exibir para o meu cliente as horas trabalhadas dele e as horas extras(sem valor de remuneração e sim somente valor em horas mesmo) e estou encontrando uma grande dificuldade, alguem ja passou por isso?

Como eu calculo o periodo de horas que ele trabalhou entre duas datas por exemplo:

Entrada1: 08:10
Saida1 : 12:50

Ele trabalhou 3:40 minutos durante esse periodo

Entrada2: 13:50
Saida2: 17:50

Trabalhou mais 4 horas nesse periodo, e o dever dele era de 7 horas por dia, entao ele fez 00:40 min de horas extra.

Estou tendo dificuldade com isso, alguem poderia me ajudar, ficaria muito agradecido. Obrigado

Você está trabalhando com o que? Calendar? ou talvez JodaTime?

entao amigo, no banco que eu consulto a hora é do tipo text, entao eu jogo ele em uma string no java depois converto em calendar.

Se estiver trabalhando com o Date ou o Calendar do JDK, pode utilizar o getTime que retorna um long que representa o número de milissegundos desde 1/1/1970. Aí é só fazer a diferença dos dois longs e converter o resultado de milissegundos para horas/minutos:

long horas = (dataFinal.getTime() - dataInicial.getTime()) / 3600000
long minutos = (dataFinal.getTime() - dataInicial.getTime() - horas*3600000) / 60000 

Acho que o código é esse mesmo.

[code]
public static long validaDate(String horaInicial, String horaFinal) {

    try {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        Calendar cal = Calendar.getInstance();
        Calendar calFinal = Calendar.getInstance();
        
        cal.setTime(sdf.parse(horaInicial));
        calFinal.setTime(sdf.parse(horaFinal));
        
        long horas = calFinal.getTimeInMillis() - cal.getTimeInMillis() / 3600000;
        long minutos = (calFinal.getTimeInMillis() - cal.getTimeInMillis()- horas*3600000) / 60000 ;
        long diferenca = horas+minutos;
        
        return diferenca;
    } catch (ParseException e) {
        e.printStackTrace();
        return 0;
    }
}[/code]

Tenho esse metodo onde recebe 2 String e fiz praticamente igual, ele me retorna um valor em milisegundos? e o do minuto retorna uma valor negativo.

Vamos à matemática.

Você tem 2 Calendars, certo? Se você pegar o que está mais adiante no tempo, e subtrair os milissegundos do outro, vai ter a diferença no tempo em milissegundos.long millis = c1.getTimeInMillis() - c.getTimeInMillis();1 segundo são 1000 milissegundos, então dividindo esse valor por 1000, você terá o tempo em segundos.long segundos = millis / 1000;Daí pra frente já fica mais natural. 1 minuto são 60 segundos, então dividindo o valor por 60 você terá os minutoslong minutos = segundos / 60;Para saber as horas, segue o mesmo processo, 1 hora são 60 minutos.long horas = minutos / 60;Terminando esse processo tem um pequeno detalhe, vamos ver se você consegue descobrir sozinho :slight_smile:

O seu código está quase correto. Tem algumas coisas incorretas:

1 - Você está obtendo apenas informação de horário. Precisa também da data, pois se o horário final é 0:50 e o inicial 22:00, o resultado da diferença vai ser negativo mesmo! Como a data final é sempre maior, então a 0:50 é do próximo dia. Sugiro que capture a data também no SimpleDateFormat

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm");  // acho que é assim o pattern... conferir

E também, o resultado da conta já é a informação de horas e minutos que você precisa. A variável hora vai possuir a diferença das datas em horas e a variável minutos vai possuir os minutos (tudo já convertido). Então você não precisa fazer isso:

Basta retornar a hora e o minuto, talvez em um array de tamanho 2.

o galera, muito obrigado eu consegui resolver o meu problema graça a ajuda de voces, adaptei aqui conforme minha necessidade juntado a resposta de voces obtive esse resultado:

[code]
public static long validaDate(String horaInicial, String horaFinal) {

    try {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        Calendar calInicial = Calendar.getInstance();
        Calendar calFinal = Calendar.getInstance();

        calInicial.setTime(sdf.parse(horaInicial));
        calFinal.setTime(sdf.parse(horaFinal));

        long minutos = ((calFinal.getTimeInMillis() - calInicial.getTimeInMillis())) / 60000;
        long resto = minutos % 60;
        long horas = minutos / 60;

// long horas = (calFinal.getTimeInMillis() - calInicial.getTimeInMillis()) / 3600000;
// String diferenca = horas + “:” + resto;

        return minutos;
    } catch (ParseException e) {
        e.printStackTrace();
        return 0;
    }
}[/code]

EDIT: Na vdd eu so retorno o minutos e no metodo que faz chama a esse calcula as horas certinho. =]

Maravilha :slight_smile:

Só renomeie esse método, por favor 8)

Eu não acredito que as pessoas ainda não entenderam que não podem usar matemática elementar com datas!! :shock: :shock:

Essas contas que vc fizeram não funcionam. Se tiver um dia de mudança de horario estragou. Se for no ultimo dia do ano, estragou, se for mais de um dia de intervalo( o cara entrou 23:59 do dia 1 e sai 00:01 do dia 3), estragou, etc…

Primeiro instancia um calendar com a data menor. E vai acrescentando minutos (minutos porque a precisão da conta é minutos, mas poderia somar segundos ou milissegundos, só que demora mais) até cair na data final.

Este é um processo demorado, mas é o processo que garante que o resultado está certo.

É claro que o algoritmo não é barato, então uma outra forma de fazer é converter as datas para o timezone UTC. Isto porque e o unico que não tem horario de verão. O fato das datas terem o mesmo timezone não garante nada. Tem que ser este time zone.
Depois faz a subtração normal dos milissegundos como vcs fizeram, e isso dá o intervalo certo. Mas sem a conversão do timezone, vai dar errado.

[quote=sergiotaborda]Eu não acredito que as pessoas ainda não entenderam que não podem usar matemática elementar com datas!! :shock: :shock:

Essas contas que vc fizeram não funcionam. Se tiver um dia de mudança de horario estragou. Se for no ultimo dia do ano, estragou, se for mais de um dia de intervalo( o cara entrou 23:59 do dia 1 e sai 00:01 do dia 3), estragou, etc…

Primeiro instancia um calendar com a data menor. E vai acrescentando minutos (minutos porque a precisão da conta é minutos, mas poderia somar segundos ou milissegundos, só que demora mais) até cair na data final.

Este é um processo demorado, mas é o processo que garante que o resultado está certo.

É claro que o algoritmo não é barato, então uma outra forma de fazer é converter as datas para o timezone UTC. Isto porque e o unico que não tem horario de verão. O fato das datas terem o mesmo timezone não garante nada. Tem que ser este time zone.
Depois faz a subtração normal dos milissegundos como vcs fizeram, e isso dá o intervalo certo. Mas sem a conversão do timezone, vai dar errado. [/quote]
Desculpa, não entendi.

Como o dia pode ser um problema se ele informar a data completa?

O cálculo das horas que vc fez não está correto…

Acho que isso deve te ajudar:

public String getHoraExtra(String horaEntrada, String horaSaida, String horasDescanso, String cargaHoraria) throws Exception{

	//Formato dos parametros: hh:mm:ss		
	horaEntrada = "08:10:00"; //Inicio das atividades no dia		
	horaSaida = "17:50:00"; //Fim das atividades no dia
	horasDescanso = "01:00:00"; //Soma do tempo que não exerceu suas atividades
	cargaHoraria = "07:00:00"; //Carga horária trabalhada
	
	String[] horaEntradaHMS = horaEntrada.split(":");;
	String[] horaSaidaHMS = horaSaida.split(":");
	String[] horasDescansoHMS = horasDescanso.split(":");
	String[] cargaHorariaHMS = cargaHoraria.split(":");
	
	///////////////////////////////////////////////////////
	///Horas trabalhadas
	Calendar calHorasTrabalhadas = Calendar.getInstance();
	
	//Set hora saida
	calHorasTrabalhadas.set(Calendar.HOUR, Integer.parseInt(horaSaidaHMS[0]));
	calHorasTrabalhadas.set(Calendar.MINUTE, Integer.parseInt(horaSaidaHMS[1]));
	calHorasTrabalhadas.set(Calendar.SECOND, Integer.parseInt(horaSaidaHMS[2]));
	
	//Subtrai as horas entrada
	calHorasTrabalhadas.add(Calendar.HOUR, (-1) * Integer.parseInt(horaEntradaHMS[0]));
	calHorasTrabalhadas.add(Calendar.MINUTE, (-1) * Integer.parseInt(horaEntradaHMS[1]));
	calHorasTrabalhadas.add(Calendar.SECOND, (-1) * Integer.parseInt(horaEntradaHMS[2]));
	
	//Subtrai as horas de descanso		
	calHorasTrabalhadas.add(Calendar.HOUR, (-1) * Integer.parseInt(horasDescansoHMS[0]));
	calHorasTrabalhadas.add(Calendar.MINUTE, (-1) * Integer.parseInt(horasDescansoHMS[1]));
	calHorasTrabalhadas.add(Calendar.SECOND, (-1) * Integer.parseInt(horasDescansoHMS[2]));
	
	System.out.println("Hora: " + calHorasTrabalhadas.get(Calendar.HOUR));
	System.out.println("Minuto: " + calHorasTrabalhadas.get(Calendar.MINUTE));
	System.out.println("Segundo:" + calHorasTrabalhadas.get(Calendar.SECOND));
					
	///////////////////////////////////////////////////////
	///Carga horaria
	Calendar calCargaHoraria = Calendar.getInstance();
	
	calCargaHoraria.set(Calendar.HOUR, Integer.parseInt(cargaHorariaHMS[0]));
	calCargaHoraria.set(Calendar.MINUTE, Integer.parseInt(cargaHorariaHMS[1]));
	calCargaHoraria.set(Calendar.SECOND, Integer.parseInt(cargaHorariaHMS[2]));
	
	///////////////////////////////////////////////////////
	///Falta:
	/// - Verificar a diferença entre as horas trabalhadas e a carga horária, essa diferença é a hora extra.
	
	return null;
}

[quote=Rodrigo Sasaki][quote=sergiotaborda]Eu não acredito que as pessoas ainda não entenderam que não podem usar matemática elementar com datas!! :shock: :shock:

Essas contas que vc fizeram não funcionam. Se tiver um dia de mudança de horario estragou. Se for no ultimo dia do ano, estragou, se for mais de um dia de intervalo( o cara entrou 23:59 do dia 1 e sai 00:01 do dia 3), estragou, etc…

Primeiro instancia um calendar com a data menor. E vai acrescentando minutos (minutos porque a precisão da conta é minutos, mas poderia somar segundos ou milissegundos, só que demora mais) até cair na data final.

Este é um processo demorado, mas é o processo que garante que o resultado está certo.

É claro que o algoritmo não é barato, então uma outra forma de fazer é converter as datas para o timezone UTC. Isto porque e o unico que não tem horario de verão. O fato das datas terem o mesmo timezone não garante nada. Tem que ser este time zone.
Depois faz a subtração normal dos milissegundos como vcs fizeram, e isso dá o intervalo certo. Mas sem a conversão do timezone, vai dar errado. [/quote]
Desculpa, não entendi.

Como o dia pode ser um problema se ele informar a data completa?[/quote]

Porque o dia é que determina como os milisegundos do private do date representam a hora. Ou seja, se é necessário usar o timezone ou não. Durante o periodo de horario de verão os milisegundos não correspondem ha hora, por isso fazer gettime() / y não dá o numero certo. Pegue o dia 17 de Fevereiro qando a hora mudou e calcule quanto tempo passou entre as 23:59 do dia 16 e as 1:59 do dia 17. O resultado deve ser 1 hora e não duas. Porque no meio houve uma avanço no relogio, mas o tempo real não avançou, logo o intervalo é de 1 hora mas no relogio passaram 2 horas. Para efetios de contar quanto alguem trabalha é preciso considerar 1 e não 2.

Até aí tudo bem, concordo, mas como ele faria pra saber que tem que avançar somente 60 minutos nessa sua soma de minuto a minuto?

Sendo que a única informação que ele tem é a data de início e a data fim.

A minha dúvida real é, por que somar minuto a minuto e não obter a diferença pela subtração? Sendo que ambos os casos estão vulneráveis a alterações como horário de verão.

Amigo com todo o respeito, nao seja tao rude assim com as palavras, o que voce sabe nao quer dizes q tds saibam como a sua devassa experiencia que aparentemente parece ter.

E desculpe me se eu nao tenho a experiencia que voce tem, e que alem de fala dessa maneira, voce poderia compartilhar seu conhecimento mostrando-nos com uma breve explicação sobre isso que voce disse.

Abraços, :smiley:

Na minha humilde opinião, o único ponto levantado pelo sergiotaborda que realmente merece atenção é a mudança de horário de verão. Se você utilizar a data completa, tanto a mudança de ano como a diferença de mais de um dia serão cobertas pela subtração. E também o algoritmo citado por ser bem mais lento: imagine fazer um loop que roda 1000 x 3600 x 24 iterações = 86400000 (diferença entre datas com diferença de um dia em millissegundos). Bem alto para quem considera tempo de CPU. Além disso, como já citaram, isso não cobriria a mudança do horário de verão.

Até aí tudo bem, concordo, mas como ele faria pra saber que tem que avançar somente 60 minutos nessa sua soma de minuto a minuto?

Sendo que a única informação que ele tem é a data de início e a data fim.

A minha dúvida real é, por que somar minuto a minuto e não obter a diferença pela subtração? Sendo que ambos os casos estão vulneráveis a alterações como horário de verão.[/quote]

Não. A adição de minutos no calendar vai direto para o epoc time ( que é o milisegundos base) e depois o calendar reintrepreta . Existe um calculo entre vc dar Calendar.add e Calendar .get. O Get vai dar a hora de relogio (wall clock time) ou seja ele vai avançar mais depressa que o numero de minutos que vc adicionou ( ou mais devagar se for a mudança de hora inversa). Na realidade, para sermos absolutamente exactos seria segundo a segundo , mas para o proposito já basta minuto a minuto. E como eu disse, existe um algoritmo em q vc pode fazer com matemática, mas tem que reduzir o date a UTC. É tudo um problema de referencial. Existe um referencial absoluto (UTC) e um relativo ( timezone) apenas no absoluto que os calculos são simples. E para converter um no outro que existe o calendar.

O loop sim cobre o horario de verão. Esse é o ponto.
Para ter um algoritmo correto vc precisa do loop.
Mas o loop é lento. Ok. Por isso vc precisa usar o algoritmo que converte para UTC como eu expliquei antes.

Acho que entendi o que acontece. O problema está na divisão, pois obtemos apenas a parte “inteira” do resultado, ou seja, o resultado acaba sendo truncado. Se você quiser saber a diferença em dias, isso pode ter alguma influência (por exemplo, um resultado do tipo 3,99999999 dias que na verdade é 4 mas ficamos com o 3).