Um colega colou esse cron: 0 9 star star 1-5, dizendo que roda de segunda a sexta às 9 AM. Olhei para ele e disse que não rodaria nesta segunda. Não é piada — cada um dos 5 campos tem suas próprias regras. Errar em qualquer um e seu schedule não é o que você pensa que é.
Este guia é para que da próxima vez que você ler uma expressão cron, não precise abrir a man page do crontab(5) para entender o que ela realmente faz.
Resumo em 30 segundos
- Uma expressão cron tem 5 campos, da esquerda para a direita: minute, hour, day-of-month, month, day-of-week.
- Cada campo pode ser star (qualquer), um número, um intervalo (9-17), um passo (star/15), ou uma lista (1,15).
- Sunday no campo day-of-week é 0 (e 7 é aceito como alias). Nunca escreva 7 por portabilidade — alguns schedulers rejeitam.
- Quando tanto day-of-month quanto day-of-week estão restritos (nenhum é star), a regra de disparo é OR: qualquer coincidência conta.
- Em um dia de transição DST, cron pode perder uma execução ou disparar duas vezes. É uma limitação do cron, não um bug.
5 cenários reais: armadilhas campo por campo
Cenário 1: star/15 em minute — você não sabe realmente o que faz
Um colega escreveu star/15 star star star star pensando a cada 15 minutos. Realidade: minute=0, 15, 30, 45.
Armadilha: muitos programadores assumem que star/15 começa a contar do minuto atual, depois a cada 15 depois. Errado. Começa do limite inferior do campo (0) e seleciona valores por passo. Então um schedule que começa às 5:07:23 roda primeiro às 5:15:00, não 5:22:23.
Fix: use valores explícitos, ou abra star/15 em um cron generator e verifique o preview. star/5 significa 0, 5, 10, …, 55 — cinco valores, intervalos de cinco minutos.
Cenário 2: intervalo de hora 9-17
Tutoriais antigos dizem que horário de trabalho é 9-17. A expressão 0 9-17 star star star significa que dispara em hour=9, 10, 11, 12, 13, 14, 15, 16, 17 — nove horas diferentes, uma vez cada.
Armadilha: não é das 9 AM às 5 PM como janela. Não dispara às 17:30 (a corrida de 17:00:00 é a última), e nada dispara depois das 18:00. Para cada 30 minutos durante horário de trabalho, escreva star/30 9-17 star star star — 9:00, 9:30, 10:00, 10:30, …, 17:00, 17:30 — 18 corridas por dia ao longo de 9 horas.
Cenário 3: day-of-month star vs números específicos
Tarefa: rodar relatório no dia 1 de cada mês. 0 0 1 star star parece certo, e aqui não tem problema.
Armadilha: às vezes equipes querem último-dia-do-mês e escrevem 0 0 L star star. Mas L é uma extensão do Quartz; Vixie cron (o cron padrão do Linux) não reconhece. Para suporte Quartz, você precisa de um scheduler Quartz, ou tratar no script.
Fix: uma abordagem confiável de fim de mês é fallback de dia da semana. Se o último dia cai em fim de semana, roda na sexta anterior. Use 0 0 star star 1-5 com intervalo day-of-month 28-31, e deixa o script decidir se hoje é o último dia útil.
Cenário 4: Sunday em day-of-week é 0, não 7
Tarefa: backup todo domingo às 3 AM. O colega escreve 0 3 star star SUN — você sabe que isso é domingo. Mas se ele escrever 0 3 star star 7, como você interpreta?
Armadilha: Vixie cron / cronie aceitam tanto 0 quanto 7 como Sunday. Alguns schedulers (Quartz antigo, algumas configs antigas do AWS EventBridge) só aceitam 0 e rejeitam 7.
Fix: escreva sempre 0. É o padrão RFC e tem a melhor portabilidade. Trate 7 como extensão específica do parser.
Cenário 5: abreviação de mês JAN FEB MAR … DEC
Exemplo de documentação: 0 9 star JAN-MAR star. Sintaxe válida, equivalente a 0 9 star 1-3 star.
Armadilha: abreviações só funcionam no campo day-of-week (SUN MON TUE WED THU FRI SAT) e no campo month (JAN … DEC). Você não pode usar abreviação em minute / hour / day-of-month.
Fix: se sua equipe lê abreviatura confortavelmente, use; na dúvida, volte para 0-6 para weekday e 1-12 para mês.
4 fatos contraintuitivos sobre cron
Fato 1: day-of-month e day-of-week são OR, não AND
Tarefa: disparar domingo de cada semana, OU dia 1 de cada mês. 0 0 1 star 0 se lê como: só quando coincidirem dia-1 e domingo. Errado.
Regra real: quando tanto day-of-month quanto day-of-week estão restritos (nenhum é star), a regra OR se aplica. Qualquer coincidência dispara. Então 0 0 1 star 0 = corridas do dia-1 + corridas de cada domingo (pode produzir 1-2 disparos em um mês dependendo do calendário).
Para semântica AND estrita, use um script ou troque de scheduler (k8s CronJob suporta semântica de campos mais rica).
Fato 2: star significa coisas diferentes em campos diferentes
star em minute = qualquer 0-59, a cada minuto. star em hour = qualquer 0-23, a cada hora cheia. A diferença é frequência — star de minute é por minuto, star de outros campos significa a frequência máxima permitida para aquele campo.
Fato 3: star/S é equivalente a 0/S
star/15 é o mesmo que 0/15, no campo minute onde o limite inferior é 0. 9-17/2 produz 9, 11, 13, 15, 17 — cinco valores.
Armadilha: escrever 1/15 no campo minute dá 1, 16, 31, 46 — quatro valores, não a cada 15 minutos começando do 1.
Fato 4: dias DST podem perder uma corrida ou disparar duas vezes
Nas transições DST da América do Norte (segundo domingo de março / primeiro domingo de novembro), o horário local pula ou repete uma hora. Cron agenda contra horário local wall-clock, e as implementações variam.
Fix: para tarefas sensíveis ao tempo, não use cron simples. Use systemd timer ou k8s CronJob em UTC com timezone explícito — sem drift de DST.
3 templates reais de schedule
Template 1: a cada 15 minutos no horário de trabalho
star/15 9-17 star star 1-5
Significado: segunda a sexta, 9 AM às 5 PM incluído, a cada 15 minutos.
Frequência: 9 horas × 4 por hora = 36 corridas por dia útil, sem fins de semana. Quer menos? star/30 dá 18 por dia.
Template 2: fim de semana sexta às 6 PM
0 18 star star 5
Nota: o valor de day-of-week é 5, não FRI — são equivalentes. Teste qual o cron do seu deployment aceita; algumas implementações rejeitam a abreviação.
Frequência: uma vez por semana, sexta 6 PM. Na segunda de manhã o relatório já deve estar no inbox.
Template 3: backup mensal no dia 1 à meia-noite, fallback para sexta anterior se dia 1 cair em fim de semana
Isso não dá para expressar em cron simples — precisa de um script wrapper.
Implementação de referência: um bash script (a.sh) que primeiro verifica com date se hoje é o primeiro. Se sim, roda o backup. crontab então roda 0 0 28-31 star star 1-5 /path/to/a.sh — dia útil da última semana de cada mês à meia-noite, o script verifica se hoje é o dia antes do 1, e roda o backup se for.
Práticas recomendadas
- Não escreva cron no escuro — abra crontab.guru ou nosso cron generator e visualize os campos, verifique a descrição em linguagem natural.
- Sempre confira a lista de next-run antes de fazer deploy — piick cron-generator por padrão mostra as próximas 5 execuções; cole sua expressão, veja se os tempos batem com a janela esperada.
- Para tarefas sensíveis ao tempo use UTC mais TZ explícito — DST é o pecado original do cron; systemd timer ou k8s CronJob com spec.timezone=UTC contorna.
- Não enfie último-dia-do-mês em day-of-month 31 — L é Quartz e pouco confiável cross-platform; deixa o script decidir.
- Tarefas críticas precisam timeout e retry — ao cron não importa se a tarefa terminou; kill -9 timeout não interrompe a tarefa. Use systemd OnFailure para retries.
Cron é uma das ferramentas mais práticas do Unix — 5 campos, sintaxe simples, cross-platform. Construímos o cron-generator para transformar campos em dropdowns mais preview em tempo real mais lista de next-run, para ser mais difícil cair em armadilha ao escrever.
Teste nossa ferramenta cron generator, alterne para Visual Builder ou Raw Editor, cole star/15 9-17 star star 1-5, veja se as próximas 5 execuções caem no horário de trabalho 9-17 de dias úteis. Se sim — parabéns, seu primeiro schedule cron pousa. Se não — use o feedback de next-runs para achar qual campo está errado.