I'm developing an application that corresponds to the calculation of total hours worked on points cards, taking into account whether it is night time reduction or not and, if so, what is the night entry and exit.
The problem is:
To calculate the point card, I am traversing entries and exits using Calendar , and adding minute by minute 1 by 1, in the input and in an auxiliary variable, as counter.
When calculating the reduction of the night time, I calculate from second to second, and do the reduction (for those who do not know, at night, the hours worked are worth "more" in proportion to every 7 seconds, you worked 8)
But this method is "very" slow, and I have to calculate points cards for several days, which makes the application slow.
My question:
Is there a method or library that does these calculations optimally? Or is there a way to do these calculations faster? (using threads, or something of the type)
I'm going to post my code that calculates the total of the point card, I commented it for a better understanding (obs: it has an object cartãoponto
as parameter, but during the code, you can understand the attributes of it)
public static synchronized String getHor(Cartaoponto c) {
boolean isNot = c.getIsnoturnoCartaoponto();//verifico se é para reduzir ou não
String[] entss = c.getEntradasCartaoponto().split("=");//entradas, setado como string porque não existe um valor fixo, e como string posso ir adicionando eternamente
String[] saiss = c.getSaidasCartaoponto().split("=");//mesma coisa das entradas
String entra = getAddIn(sdfH.format(c.getAdicionalentradaCartaoponto()), entss);//Verifica se tem que adicionar um "extra" no início do Cartão ponto
String saia = getAddSai(sdfH.format(c.getAdicionalsaidaCartaoponto()), saiss);//mesma coisa de antes, so que no anterior
entss = entra.split("=");//seto novamente o valor (já mudado!)
saiss = saia.split("=");
Date entNot = c.getEntradanoturnaCartaoponto();//entrada noturna
Date saiNot = c.getSaidanoturnaCartaoponto();//saída noturna
Date data = c.getDataCartaoponto();//data em relação ao cartão ponto
StringTools stT = new StringTools();
int cont = 0;
int aux1 = 0, aux2 = 0;
for (String s : entss) {
if (!s.trim().equals(":")) {//verifico quantas batidas estão preenchidas
cont += 1;
}
if (s.trim().equals("00:00")) {
aux1 += 1;
}
}
for (String s : saiss) {//verifico se a batida não é 0,
if (s.trim().equals("00:00")) {
aux2 += 1;
}
}
for (int i = 0; i < entss.length; i++) {
if (!entss[i].trim().equals(":")) {
if (saiss[i].trim().equals(":")) {//se tiver entrada, mas não tiver saída, retorna erro!
return "ERRO";
}
}
}
if (aux1 + aux2 > 4) {//se tiver mais de 4 batidas que é "00:00"
cont = 0;
}
if (cont == 0) {//se não houver batidas (estiver vazio) retorna 0
return "00:00";
}
String[] ents = new String[cont];//seta uma nova variável, com o número de batidas (tirando as vazias)
String[] saids = new String[cont];
cont = 0;
for (String s : entss) {//seta o valor para os Arrays
if (!s.trim().equals(":")) {
ents[cont] = s;
cont += 1;
}
}
cont = 0;
for (String s : saiss) {
if (!s.trim().equals(":")) {
saids[cont] = s;
cont += 1;
}
}
String a = "";
try {
SimpleDateFormat sdfh = new SimpleDateFormat("HH:mm");
Calendar tot = Calendar.getInstance();
tot.set(data.getYear(),//total
data.getMonth(),
data.getDay(),
0,
0,
0);
Calendar datIn = Calendar.getInstance();
datIn.set(tot.get(Calendar.YEAR),//data de Início (para verificar depois, pois pode ser mais que 24h e o Calendar não ajuda nesse quesito)
tot.get(Calendar.MONDAY),
tot.get(Calendar.DAY_OF_MONTH),
tot.get(Calendar.HOUR_OF_DAY),
tot.get(Calendar.MINUTE),
tot.get(Calendar.SECOND)
);
datIn.set(Calendar.MILLISECOND, 0);//millisegundos = 0, porque tem verificações e isso já me deu dor de cabeça
tot.set(Calendar.MILLISECOND, aux2);
for (int i = 0; i < ents.length; i++) {//laço de repetição entre as batidas
if (saids[i].trim().equals(":")) {//se a saída estiver vazia
if (ents[i].trim().equals(":")) {//se a entrada estiver vazia, vá para o próximo (mesmo tendo a verificação anterior, resolvi ter certeza)
continue;
} else {//se tiver entrada, mas não tiver saída, retorna erro
return "ERRO";
}
}
Calendar saiNotu = Calendar.getInstance();//saida noturna
saiNotu.setTime(saiNot);
saiNotu.set(Calendar.MILLISECOND, 0);
Calendar entNotu = Calendar.getInstance();//entrada noturna
entNotu.setTime(entNot);
entNotu.set(Calendar.MILLISECOND, 0);
if (entNotu.get(Calendar.HOUR_OF_DAY) >= 00 && entNotu.get(Calendar.HOUR_OF_DAY) < saiNotu.get(Calendar.HOUR_OF_DAY)) {
entNotu.add(Calendar.DAY_OF_YEAR, 1);//seto assim, pois na lei brasileira, a entrada é 22:00 do dia x, e a saída é 05:00 do dia x+1
}
Calendar sai = Calendar.getInstance();//saída
sai.setTime(data);
sai.set(Calendar.HOUR_OF_DAY, sdfh.parse(saids[i]).getHours());
sai.set(Calendar.MINUTE, sdfh.parse(saids[i]).getMinutes());
sai.set(Calendar.MILLISECOND, 0);
if (sai.get(Calendar.HOUR_OF_DAY) >= 00 && sai.get(Calendar.HOUR_OF_DAY) < saiNotu.get(Calendar.HOUR_OF_DAY)) {
sai.add(Calendar.DAY_OF_YEAR, 1);
}
Calendar ent = Calendar.getInstance();//entrada
ent.setTime(data);
ent.set(Calendar.HOUR_OF_DAY, sdfh.parse(ents[i]).getHours());
ent.set(Calendar.MINUTE, sdfh.parse(ents[i]).getMinutes());
ent.set(Calendar.MILLISECOND, 0);
if (ent.get(Calendar.HOUR_OF_DAY) >= 00 && ent.get(Calendar.HOUR_OF_DAY) < saiNotu.get(Calendar.HOUR_OF_DAY)) {
ent.add(Calendar.DAY_OF_YEAR, 1);
}
while (ent.after(sai)) {
sai.add(Calendar.DAY_OF_MONTH, 1);
}//se a saída for antes da entrada (como 23:30 e 00:00 por exemplo) adiciona 1 à saída
int aux = 0;
while (!ent.equals(sai)) {//percorre o tempo (entre ent e sai)
Date entras = sdfH.parse(sdfH.format(ent.getTime()));//fiz isso para ajudar na verificação
Date entraNot = sdfH.parse(sdfH.format(entNot.getTime()));
int day2 = entraNot.getDate() + 1;
String day1 = String.valueOf(day2);
if (day2 < 10) {
day1 = "0" + day1;
}
Date saiaNot = sdfHd.parse(day1 + "-" + sdfH.format(saiNot.getTime()));//até aqui, foi pelo seguinte quesito:
//A entrada e saída, pode dar um erro de verificação se eu deixar para o dia atual, por isso tenho
//que deixar toda hora como válida, ou seja, se fosse sem essa verificação anterior, quando tivesse
//03:00 até 06:00 ele ia contar como hora normal, não hora reduzida, mas já se tivesse
//22:00 até as 00:00 ele funcionava, por isso eu tive que fazer essa "gambiarra"
if (entras.before(entraNot)) {//se entrada for antes da entrada noturna
day2 = entraNot.getDate() - 1;
day1 = String.valueOf(day2);
if (day2 < 10) {
day1 = "0" + day1;
}
entraNot = sdfHd.parse(day1 + "-" + sdfH.format(entNot.getTime()));
day2 = saiaNot.getDate() - 1;
day1 = String.valueOf(day2);
if (day2 < 10) {
day1 = "0" + day1;
}
saiaNot = sdfHd.parse(day1 + "-" + sdfH.format(saiNot.getTime()));
}//removo 1 dia da entrada e da saída noturna
if ((entras.after(entraNot) || entras.equals(entraNot)) && entras.before(saiaNot)) {//se a entrada for entre entrada noturna e a saída noturna
if (isNot) {//calculo o total como hora noturna reduzida se o cartãoponto pedir isso
ent.add(Calendar.SECOND, 1);
aux += 1;
if (aux == 7) {
tot.add(Calendar.SECOND, 8);
aux = 0;
}
} else {//senão, adiciono minuto a minuto
ent.add(Calendar.MINUTE, 1);
tot.add(Calendar.MINUTE, 1);
}
} else {//se não estiver dentro da hora noturna (fora de entrada noturna e saída noturna)
ent.add(Calendar.MINUTE, 1);//adiciona minuto a minuto
tot.add(Calendar.MINUTE, 1);
}
}
}
boolean teste = false;//verificação de erro
int multiplicador = stT.dataDiff(datIn.getTime(), tot.getTime());//multiplicador de dias (pega a diferença de data entre data de Início e o total)
if (multiplicador < 0) {//se o multiplicador for menor que 0 (data de Início for depois da data final) (deu erro, por isso o teste)
multiplicador = multiplicador * (-1);//multiplicador fica normal, teste=true
teste = true;
}
multiplicador = multiplicador * 24;//multiplica os dias para ter as horas
multiplicador = multiplicador + tot.get(Calendar.HOUR_OF_DAY);//adiciona o total de horas ao dia
if (multiplicador > 24) {//verificação de erro também, porque se for mais que 24, o teste é true.
multiplicador = multiplicador - 24;
}
if (multiplicador >= 10 && multiplicador <= 25) {//daqui para frente eu deixo o total no formato ("HH:mm:ss") para o SimpleDateFormat
//para logo em seguida arredondar os segundos para ficar no formato ("HH:mm")
if (tot.get(Calendar.MINUTE) < 10) {
if (tot.get(Calendar.SECOND) < 10) {
a = String.valueOf(multiplicador)
+ ":0"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":0"
+ String.valueOf(tot.get(Calendar.SECOND));
} else {
a = String.valueOf(multiplicador)
+ ":0"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":"
+ String.valueOf(tot.get(Calendar.SECOND));
}
} else if (tot.get(Calendar.SECOND) < 10) {
a = String.valueOf(multiplicador)
+ ":"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":0"
+ String.valueOf(tot.get(Calendar.SECOND));
} else {
a = String.valueOf(multiplicador)
+ ":"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":"
+ String.valueOf(tot.get(Calendar.SECOND));
}
a = String.valueOf(multiplicador)
+ ":"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":"
+ String.valueOf(tot.get(Calendar.SECOND));
} else if (multiplicador < 10) {
if (tot.get(Calendar.MINUTE) < 10) {
if (tot.get(Calendar.SECOND) < 10) {
a = "0" + String.valueOf(multiplicador)
+ ":0"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":0"
+ String.valueOf(tot.get(Calendar.SECOND));
} else {
a = "0" + String.valueOf(multiplicador)
+ ":0"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":"
+ String.valueOf(tot.get(Calendar.SECOND));
}
} else if (tot.get(Calendar.SECOND) < 10) {
a = "0" + String.valueOf(multiplicador)
+ ":"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":0"
+ String.valueOf(tot.get(Calendar.SECOND));
} else {
a = "0" + String.valueOf(multiplicador)
+ ":"
+ String.valueOf(tot.get(Calendar.MINUTE))
+ ":"
+ String.valueOf(tot.get(Calendar.SECOND));
}
}
a = arredondaSegundos(a);//aqui ele arredonda os segundos, se for maior que 30, para cima, senão, para baixo
if (teste) {//se deu erro, posta o valor do total
System.out.println("A: " + a);
}
} catch (Exception E) {
E.printStackTrace();
}
return a;//retorna o total
}