Como saber a fase da Lua de cabeça?

Quer aprender a descobrir a fase lunar de um dia apenas somando 3 a 4 números? Vamos ver mais a frente...

Ao estudar um pouco sobre as fases lunares, me deparei com um algoritmo muito interessante do matemático John Horton Conway. Ele cria um método para facilitar sabermos as fases lunares, sem a necessidade de cálculos elaborados, apenas com contas que conseguimos realizar mentalmente. Por isso, resolvi incrementar um pouco o algoritmo de fases lunares que eu havia feito e também implementar esse algoritmo mental. Se você ainda não viu a versão simplificada, para computadores, considerando somente o período sinódico, dê uma olhada aqui.

O algoritmo de Conway consiste em achar um padrão apenas utilizando contas simples para as fases lunares do século XX e XXI. Embora ele não tenha calculado os valores para os outros anos, creio que seja possível fazer apenas alterando um parâmetro na somatória final (tentarei posteriormente). A ideia desse algoritmo é que ele possa ser armazenado mentalmente para você saber as fases da lua, sem olhar para o céu.

Em resumo você considera apenas os dois últimos dígitos do ano, calcula o resto da divisão dele por 19 e se for maior que 9, subtraia 19. Multiplica o resultado por 11, calcula o resto da divisão por 30. Subtrai 4, para o século XX ou subtrai 8 para o século XXI e acha o resto da divisão por 30 novamente. Soma com o dia e o mês (se for janeiro ou fevereiro você soma 2). Se você achar difícil, olhe para o céu :D. Para o ano atual (2018), podemos já adiantar uma parte do algoritmo para facilitar o cálculo mental:

  • resto da divisão de 18 (dois últimos dígitos) por 19 é 18
  • como é maior que 9, subtraia 19; temos: 18-19 = -1
  • multiplica o resultado por 11; temos: -1 * 11 = -11
  • resto da divisão de -11 por 30 é 19
  • como estamos no século XXI, subtrai 8; temos 19 - 8 = 11
  • resto da divisão de 11 por 30 é 11

Essa a parte do cálculo que utiliza o ano. Então para o ano de 2018, você não precisa mais realizar nenhum cálculo, o valor obtido é 11 (pode decorar esse número, que até o fim desse ano ele é válido). Caso ache interessante, calcule para os outros anos. Para o dia e mês de hoje (05 de abril) é só fazer a seguinte conta:

  • número obtido (no caso é 11) + dia + mês; temos: 11+5+4 = 20
  • Se for janeiro ou fevereiro soma-se mais 2... não é o caso nosso

Com isso você só precisa saber o número 11 e somar com outros 2 números para saber o dia lunar que estamos. Que no caso é dia 20. Fácil, né? Para saber a fase da lua, você pode utilizar a seguinte tabela:

  • Lua Nova - 0, 1, 29
  • Crescente - de 2 a 6
  • Quarto crescente - 7 e 8
  • Crescente gibosa - de 9 a 13
  • Cheia - de 14 a 16
  • Minguante gibosa - de 17 a 21
  • Quarto minguante - 22 e 23
  • Minguante - de 24 a 28

Ou se preferir é só lembrar que quanto mais próximo do valor 15 estiver, mais cheia está a lua e assim não precisa decorar mais nada.

Com isso, resolvi implementar essa lógica do algoritmo, incrementando alguns valores. Ela pode ser encontrada aqui e aqui. O código está baseado na versão anterior (veja antes de utilizar o novo). Para a tabela de luas, criei uma função com condicionais (preciso melhorar):

    public static MoonPhase getMoonPhaseConway(int lunarDay) {
        if(lunarDay<=28) { if(lunarDay>=24) {
                return MoonPhase.WANING_CRESCENT;
            }
            if(lunarDay>=22) {
                return MoonPhase.THIRD_QUARTER;
            }
            if(lunarDay>=17) {
                return MoonPhase.WANING_GIBBOUS;
            }
            if(lunarDay>=14) {
                return MoonPhase.FULL_MOON;
            }
            if(lunarDay>=9) {
                return MoonPhase.WAXING_GIBBOUS;
            }
            if(lunarDay>=7) {
                return MoonPhase.FIRST_QUARTER;
            }
            if(lunarDay>=2) {
                return MoonPhase.WAXING_CRESCENT;
            }
        }
        return MoonPhase.NEW_MOON; //0,1,29
    }

E o código da lógica:

    public static int getLunarDayConway(LocalDateTime ldt) {
        var year = ldt.getYear();
        var month = ldt.getMonthValue();
        var day = ldt.getDayOfMonth();
        if(year < 1900 || year >= 2100) throw new RuntimeException("Date must be greater than 1900 and less than 2100");
        var centS = -4.0;
        if(year > 2000) {
            centS = -8.3;
        }
        var lastTwoDigits = year%100.0;
        double vl = lastTwoDigits % 19;
        if(vl > 9) {
            vl-=19.0;
        }
        vl*=11.0;
        vl%=30;
        vl+=centS;
        vl+=month+day;
        if(month<3) {
            vl+=2;
        }
        vl = Math.round(vl)%30;
        return (int)((vl < 0) ? vl+30 : vl);
    }

Da linha 7 a 17 é o cálculo do valor referente ao ano, que no nosso caso (2018) é 11. E na linha 18 é a soma que fazemos do mês e do dia para descobrir o dia lunar.

Sobre: Thiago Galbiatti Vespa

Thiago Galbiatti Vespa é mestre em Ciências da Computação e Matemática Computacional pela USP e bacharel em Ciências da Computação pela UNESP. Coordenador de projetos do JavaNoroeste, membro do JCP (Java Community Process), consultor Oracle, arquiteto de software de empresas de médio e grande porte, palestrante de vários eventos e colaborador de projetos open source. Possui as certificações: Oracle Certified Master, Java EE 5 Enterprise Architect – Step 1, 2 and 3; Oracle WebCenter Portal 11g Certified Implementation Specialist; Oracle Service Oriented Architecture Infrastructure Implementation Certified Expert; Oracle Certified Professional, Java EE 5 Web Services Developer; Oracle Certified Expert, NetBeans Integrated Development Environment 6.1 Programmer; Oracle Certified Professional, Java Programmer; Oracle Certified Associate, Java SE 5/SE 6