How to calculate point cards

Asked

Viewed 392 times

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.

  • 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 use MySQL as a database)

  • recalling also that I do the entity classes by the automatic generator that netbeans makes available

  • 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.

1 answer

-1

I think the best way would be:

  1. Discover the amount of hours worked at night (no reduction)
  2. Transfore to decimal. Ex: 3h25m is 3.42 (25/60=0.42)
  3. Multiply this value by 1.142857142857143. This is the ratio of normal time to night time given by 60/52.5: Ex: 3,42*1,142857142857143 = 3,908571
  4. Convert back to hh:mm: Ex: 0,908571*60 = 54,5142 = 3h:55m
  • I thought I’d do it this way, but it doesn’t work, because this method is general, so I use it for other methods as well, and there are some I have to filter some things from a certain point, which complicates a little bit

  • Face is not why "complicates a little"' that is wrong, sometimes (not always) to leave the algorithm faster we will have to create complex routines, so if you do not try what the above answer pointed out (although it makes sense), you can not say that it does not work.

  • I know it makes sense, but really, doing it that way solves my problem in parts, but it creates other problems, that I would have to resort to the old method to continue, which doesn’t do much, seeing that I want to optimize the system, then really, it works but in a deficient way, ie, solves part of the problem only

Browser other questions tagged

You are not signed in. Login or sign up in order to post.