Calcular periodo e horas entre datas

25 respostas
java
M

Pessoal, preciso da ajuda de alguém com isso, pois não faço ideia de como fazer.
Recebo uma data inicial e um tempo de esforço, a partir daí preciso calcular a data final de acordo com o tempo informado e distribuir nos dias do período as horas utilizadas.
Obs: Tomando como base uma jornada 07:30 - 12:00 e 13:00 - 17:30 e intervalo 12:00 - 13:00, para esse cálculo.
Ex:
Data Inicial -> 30-03-2017
Tempo Esforço: 22h:15m

Período Tempo
30-03-2017 9h
31-03-2017 9h
03-04-2017 4h 15m
Estou tendo dificuldade com isso, alguém poderia me ajudar, fico muito grato.

Obrigado

25 Respostas

M

Cara data no java é um pouco chato de trabalhar. Mas saiu no Java8 uma nova api e ainda não testei. Mas da uma olhada pode ser que resolva seu problema.

Link para uma breve introdução.

http://4java.com.br/java-8-e-sua-nova-api-para-datas/

L

1 - Divida o total de horas de esforço pelo número de horas diárias (somando-se a primeira e a segunda parte você tem o total de horas diárias).
2 - Verifique o resto da divisão, se ele for menor que o número de horas de um dia, considere um dia a mais no cálculo da data de término.
3 - Com o valor do resto da divisão, calcule o total de horas e minutos do último dia.

Exemplo:
Início 01/04/2017
Esforço: 23:30 horas
23:30 / 9 = 2 resto 5:30 => total de dias: 3
Primeiro período: 07:30 - 12:00: 4:30 horas
Assim sendo:
01/04/2017 - 9:00 horas
02/04/2017 - 9:00 horas
03/04/2017 - 5:30 horas

M

Matheus, obrigado pela dica, mas como estou com o Java 7, não me ajuda muito no momento e também não faço ideia de como fazer.

Preciso de ajuda em desenvolver mesmo.

M

Obrigado Luis Augusto pelas dicas, foi de grande valia.

Você poderia me enviar um exemplo de código, por favor.

L

Não. Esta parte é tua responsabilidade. A estrutura lógica está pronta, basta implementar :smiley:
Sucesso!

M

Ok! Só pedi como base de estudo, como sou iniciante e não tenho seu conhecimento, pensei que pudesse me ajudar com isso.

Mas mesmo assim, muito obrigado pelas dicas.

L

Independente de ser iniciante ou não, você deve ser capaz de construir a tua forma de desenvolver.
Além do mais, a solução que apontei é muito simples, basicamente, divisão (operador /) e resto (operador %).
Para ir somando os dias à data inicial, utilize o Calendar

Calendar cal = Calendar.getInstance();

E utilize os métodos setTime(Date data) e add(Calendar.DAY_OF_MONTH, int days)

Como transformar a data inicial em Date?
Utilize a classe SimpleDateFormat

SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

Detalhe, o parâmetro dd/MM/yyyy corresponde ao formato em que a data inicial será inserida. Se for o padrão americano, utilize

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

Ou o padrão em que a String que representa a data inicial vier a ser informada. Para converter a String em Date, invoque o método parse(String str) (Este método lança uma ParseException que precisa ser tratada).

Dúvidas? Primeiro pesquise no google, tente encontrar exemplos do que precisa e, se não tiver sucesso, o fórum está aqui.

M

Ok, obrigado. Vou tentar, se tiver dúvidas, volto aqui!

M

Já que está iniciando recomendo fortemente atualizar a versão do Java .

Até porque ja já que teremos o Java 9 e como comentei. As maneiras tradicionais de trabalhar como datas como nosso amigo @Luis_Augusto_Santos mostrou é extramente desconfortável. Além de que você pode acabar utilizando métodos ou classes do Java 7 que serão descontinuados nas versões futuras.

E como mencionei anteriormente uma das grandes mudanças do Java 8 é essa nova maneira de trabalhar com datas ja que o sistema antigo é muito precário.

M

Ok Matheus.

M

Pessoal, o que estou fazendo de errado, os meus cálculos dos períodos estão corretos, a soma deu 9.0 para os dois períodos, mas para o tempo de esforço que deveria dar 20.25, está dando 23.25.

String tempoEsforco = "20:15:00";
    
    String horaInicioManha = "07:30:00";
	String horaFimManha = "12:00:00";
    
	String horaInicioTarde = "13:00:00";
	String horaFimTarde = "17:30:00";
	
	SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
	
	//Período da manhã
	Date hm1 = sdf.parse(horaInicioManha);
    Date hm2 = sdf.parse(horaFimManha);
    double diffInMillis1 =   (hm2.getTime() - hm1.getTime())/ (double) (1000*60*60); //4.5
    int horasManha = (int) (diffInMillis1);
    int minutosManha = (int) ((diffInMillis1-horasManha) * 60);
    //System.out.println(horasManha+ " : " +minutosManha);
    
    //Período da tarde
    Date ht1 = sdf.parse(horaInicioTarde);
    Date ht2 = sdf.parse(horaFimTarde);
    double diffInMillis2 =   (ht2.getTime() - ht1.getTime())/ (double) (1000*60*60); //4.5
    int horasTarde = (int) (diffInMillis2);
    int minutosTarde = (int) ((diffInMillis2-horasTarde) * 60);
    //System.out.println(horasTarde+ " : " +minutosTarde);
    
   	    	    
    //Total dos dois períodos
    double somaDiffInMillis =   diffInMillis1 + diffInMillis2; //9.0
    int horasTotal = (int) (somaDiffInMillis);
    int minutosTotal = (int) ((somaDiffInMillis-horasTotal) * 60);
    //System.out.println(horasTotal+ " : " +minutosTotal);
    
    //Tempo esforço
  	Date tempoEsf = sdf.parse(tempoEsforco);
  	double diffInMillisTempoEsforco =   (tempoEsf.getTime()) / (double) (1000*60*60);
    //Aqui deveria dar 20.25 e está dando 23.25

Desde já agradeço a ajuda.

L

Agora vou responder certo

double diffInMillisTempoEsforco = (tempoEsf.getTime() - 10800000) / (double) (1000*60*60);

Essa foi a solução que eu encontrei pois vi que se você criar uma variável que recebe “00:00:00” ela retorna no getTime 10800000. Não sei o por que disso, sou iniciante em programação então espero que alguém explique um pouco melhor o que realmente acontece.

M

Obrigado Lucas pela resposta!

Pois é, também não imagino porque isso acontece, já tentei de diversas maneiras corrigir, mas sem êxito.

L

Este valor, em ms, corresponde a 3 horas. +3 é o fuso onde a maior porção do território brasileiro se encontra.
Fuso horário. Faz sentido para vocês?

M

Verdade Luis!

E como seto o timezone? Seria assim?

DateFormat df = DateFormat.getTimeInstance(DateFormat.MEDIUM);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
L

Você até pode fazer

df.setTimeZone(TimeZone.getTimeZone("UTC"));

Mas, não esqueça que os objetos de Date são construídos com base na data e hora 01/01/1970 00:00:00, ou seja, se você define o timezone, vai acabar trabalhando com a data 31/12/1969 e a hora será 21:00:00

M

Tá, e como você faria, pode dar uma dica?

L

A melhor opção, sem dúvidas, é a nova API de datas e horas do java (a partir do java 8).
Só não entendi uma coisa: você já não tem o esforço, por quê calcular o mesmo novamente?

“Marcos_rhs:

Recebo uma data inicial e um tempo de esforço

M

Estou apenas transformando o esforço em decimal. Para fazer aquela divisão que você comentou, pegar o esforço e dividir pelo total de horas do período e depois pegar o resto.

Existe uma maneira mais simples?

L

Vamos supor um esforço de 187 horas (escolhi aleatoriamente), começando em 10/04/2017, com atividade entre 07:30 e 12:00 e 13:00 e 17:30 horas.
Temos:

//9 horas por dia
        int horasDia = 9;
        //Data inicial
        String dataIni = "10/04/2017";
        //Esforço total
        int totalEsforco = 187;

        int diasInteiros = totalEsforco/horasDia;
        int parte = totalEsforco%horasDia;
        
        System.out.println("Serão " + diasInteiros + " dias e " + parte + " horas");
        
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(dataIni));
        cal.add(Calendar.DAY_OF_MONTH, diasInteiros + (parte != 0 ? 1 : 0));
        System.out.println("Data final: " + sdf.format(cal.getTime()));

E a saída

Serão 20 dias e 7 horas
Data final: 01/05/2017

Mudando para 72 horas de esforço:

Serão 8 dias e 0 horas
Data final: 18/04/2017

E mudando para 235 horas

Serão 26 dias e 1 horas
Data final: 07/05/2017
M

E seu eu colocar o esforço assim 0.45?

L

0.45 precisa ser convertido em horas. Para isso, você precisa utilizar regra de três e calcular quanto de uma hora é 0.45.
Mesmo assim, você já tem o total de esforço, não precisa calcular novamente.

Edit:

Usando a mesma estrutura anterior, apenas adequando para a tua questão:

//9 horas por dia
        int horasDia = 9;
        //Data inicial
        String dataIni = "10/04/2017";
        //Esforço total
        float totalEsforco = 235.45f;
        
        int diasInteiros = (int) totalEsforco/horasDia;
        float parte = totalEsforco%horasDia;
        
        int parteInteira = (int) parte;
        float minutes = (parte - parteInteira) * 60;
        
        System.out.println("Serão " + diasInteiros + " dias e " + parteInteira + " horas e " + minutes + " minutos");
        
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.setTime(sdf.parse(dataIni));
        cal.add(Calendar.DAY_OF_MONTH, diasInteiros + (parte != 0 ? 1 : 0));
        System.out.println("Data final: " + sdf.format(cal.getTime()));

E a saída é algo assim

Serão 26 dias e 1 horas e 26.999817 minutos
Data final: 07/05/2017
M

O que eu notei Luiz, é que está ignorando o dia e começando no dia 11/04/2017. Coloca 27h de esforço deveria acabar dia 12/04/2017, incluindo o dia 10/04.

L

Com certeza!
Quando você invoca o método set de um objeto da classe Calendar, ele vai pegar o valor da data que aquele objeto representa e adicionar ao campo especificado (Calendar.DAY_OF_MONTH, no caso) o valor informado.
Cabe a você controlar isso.
Das duas uma: ou você coloca a data com um dia antes (cal.set(Calendar.DAY_OF_MONTH, (-1));) ou você remove um dia do total de dias calculado a partir da divisão de esforço por horas por dia.

M

Entendi. Cara, muito obrigado pela ajuda.

Criado 31 de março de 2017
Ultima resposta 3 de abr. de 2017
Respostas 25
Participantes 4