6
I am developing an application that matches the calculation of total hours worked on points cards, taking into account whether it is night time reduction or not and, if it is, what is the entrance and night out.
The problem is:
To calculate the point card, I am going through inputs and outputs, using Calendar, and adding minute by minute 1 by 1, into the input and into an auxiliary variable, as counter.
When it is to calculate the reduction of night time, I calculate from second to second and, I make the reduction (for those who do not know, at night, the hours worked are worth "more" in the proportion of every 7 seconds, matches that you worked 8)
But this method is "very" slow and, I have to calculate points cards of several days, which makes the application stay slow.
My doubt:
Is there a method or Library that does these calculations in an optimized way? Or is there a way to do these calculations faster? (using threads, or something like)
I will post my code that calculates the total card point, commented it for better understanding (Obs: has an object cartãoponto
as a parameter, but during the code, you can understand its attributes)
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
}
The slowness occurs because you are using strings to store time and have to keep converting to do the calculations, use an Arraylist<Date> to store the entries.
– Daniel Santos
I don’t think so, because I do two or three conversions from one side to the other, while I have to go through the whole beat second by second or minute by minute, I think one way to reduce that would be by using the Jodatime and "removing" as many beats as possible to then begin to traverse the remaining beats. But even so, it is an idea and is already an optimization more, even if small. I use
JPA
, then I need an entity class. In the database you put what kind of data to relate the Arraylist? (just to clarify, I useMySQL
as a database)– Thomas Braz Pinto
recalling also that I do the entity classes by the automatic generator that netbeans makes available
– Thomas Braz Pinto
In that case it would be better for you to create a separate table to store the beats. I recommend creating a table with the input and output columns.
– Daniel Santos