Expressões cron
Você cola “15 3 * * 1-5” e recebe o que ela significa, em palavras simples, com as próximas execuções dia a dia no fuso horário que você escolher. Ou o contrário: monte o agendamento pelos menus e leve a expressão pronta.
Não tem uma? Monte aqui
Qual dialeto esta página lê
Cron não é uma coisa só, e esta é a primeira coisa a saber: aqui lemos o crontab clássico com cinco campos (minuto, hora, dia do mês, mês, dia da semana), mais a forma de seis campos com os segundos na frente de tudo, a que o Spring e o node-cron escrevem, mais os atalhos @yearly, @monthly, @weekly, @daily, @midnight e @hourly. O domingo pode ser escrito 0 ou 7, e os nomes de três letras em inglês (MON, FRI, JAN, DEC) funcionam normalmente.
Tudo o que não pertence a este dialeto é recusado com o motivo explicado, em vez de ser lido pela metade: os símbolos do Quartz (o ponto de interrogação, o L do último dia, o W do dia útil mais próximo, o jogo da velha do terceiro domingo), os sete campos do Quartz com o ano no fim, e o @reboot, que não é um horário e sim um evento, e por isso não tem próxima execução para calcular. O mesmo vale para um intervalo escrito de trás para frente, como 5-1: cada pessoa lê do seu jeito, e dar uma resposta seria pior do que declarar o problema. Se o seu trabalho de hoje é com redes e não com agendamentos, a página certa é a Calculadora de sub-redes.
Dia do mês e dia da semana entram em OU
Esta é a armadilha que mais custa horas, e parece um detalhe: quando os dois campos de dia estão escritos, o crontab clássico não os combina em E, e sim em OU. Ou seja, “0 0 13 * 5” não significa “o dia 13 do mês, se for sexta-feira”: significa o dia 13 do mês e, além disso, toda sexta-feira. Quem esperava uma execução por mês recebe cinco ou seis.
A regra só vale quando os dois estão restritos. Se um dos dois é um asterisco, o outro manda sozinho, que é o caso normal. É por isso que a lista logo acima é a parte que realmente importa: você lê as datas uma a uma e percebe na hora se elas aparecem com mais frequência do que você imaginava. Quando os dois campos estão escritos, a página avisa em palavras, para que ninguém descubra por acaso.
Por que “*/7” não significa “a cada sete minutos”
O passo não conta os minutos que passam: ele recomeça do zero a cada hora. Com “*/7” as execuções caem nos minutos 0, 7, 14, 21, 28, 35, 42, 49 e 56, e depois se volta ao minuto 0 da hora seguinte: entre 00:56 e 01:00 passam quatro minutos, não sete. Em uma máquina fazendo trabalho pesado, esses dois inícios próximos são exatamente onde as coisas se acumulam.
A conta fecha quando o passo divide sessenta, ou seja, 2, 3, 4, 5, 6, 10, 12, 15, 20 e 30: só nesses casos “a cada N minutos” é uma descrição verdadeira. Nas horas vale o mesmo raciocínio com vinte e quatro, então “*/13” não é “a cada treze horas”, e sim as horas 0 e 13, com onze horas vazias no meio. É por isso que a frase que você lê acima lista os minutos reais em vez de repetir o passo: a descrição prática é justamente a que faz você errar.
Horário de verão, e por que cada data é conferida de novo
A mudança de horário é o ponto em que até os crons de verdade discordam entre si, então a regra desta página fica escrita, e não subentendida: trabalhamos no horário do relógio de parede, e se essa hora não existe naquela noite, porque os ponteiros pulam para a frente, a execução é pulada e você é avisado; se ao contrário ela existe duas vezes, porque os ponteiros voltam, ela é contada uma vez só, a primeira. Um cron de verdade, na mesma noite, pode recuperar a execução pulada ou disparar duas.
Pelo mesmo motivo toda data gerada é relida: a partir do instante calculado, voltamos ao horário do relógio de parede no fuso escolhido e conferimos a data campo por campo com um segundo trecho de código, escrito uma segunda vez de propósito. Se a conferência não fechar, nada é exibido, porque uma data errada dita com segurança é pior do que nenhuma data. E se você só precisa saber que horas são agora em outro lugar do mundo, o caminho curto é o Relógio mundial.