Ir para o conteúdo
Toova
Todas as Ferramentas

Sintaxe de Expressões Cron Explicada

Toova

Expressões cron são um daqueles tópicos que o dev aprende uma vez, esquece os detalhes e consulta de novo a cada seis meses. Uma string de cinco caracteres como 30 9 * * 1-5 consegue codificar um agendamento surpreendentemente específico — "todo dia útil às 9h30" — mas a sintaxe tem casos extremos suficientes para causar confusão real: campos com índice 0 versus índice 1, domingo sendo ao mesmo tempo 0 e 7, a diferença entre o padrão Unix e a extensão de seis campos do Quartz, e o comportamento sutil de valores de passo combinados com intervalos.

Este guia cobre a sintaxe cron a partir dos fundamentos e depois percorre cada caractere especial com exemplos concretos. Seja para escrever uma tarefa cron para um daemon Linux, configurar um agendamento no GitHub Actions ou criar uma regra no AWS EventBridge, os mesmos conceitos subjacentes se aplicam — com algumas diferenças importantes entre plataformas explicadas ao longo do caminho.

Os Cinco Campos Padrão

Uma expressão cron padrão tem cinco campos separados por espaço, lidos da esquerda para a direita: minuto, hora, dia do mês, mês e dia da semana. Cada campo restringe quando a tarefa é executada ao longo dessa dimensão. A tarefa só executa quando todos os cinco campos correspondem simultaneamente.

# Campo           Posição  Intervalo       Caracteres especiais
# ─────────────────────────────────────────────────────────────
# Minuto              1      0-59            * / , -
# Hora                2      0-23            * / , -
# Dia do mês          3      1-31            * / , - ? L W
# Mês                 4      1-12 ou JAN-DEC * / , -
# Dia da semana       5      0-7 (0=7=Dom) ou DOM-SAB  * / , - ? L #

Lendo uma expressão como 30 9 * * 1-5: minuto 30, hora 9, qualquer dia do mês, qualquer mês, dia da semana 1 a 5 (segunda a sexta). Resultado: 9h30 todo dia útil.

Campo 1: Minuto (0–59)

O campo de minuto especifica em qual(is) minuto(s) da hora a tarefa deve executar. 0 significa o início da hora, 30 significa meia hora, 59 significa um minuto antes de a hora virar. Usar * executa a tarefa todo minuto.

Campo 2: Hora (0–23)

As horas usam formato 24 horas. 0 é meia-noite, 12 é meio-dia, 23 é 23h. Não existe AM/PM no cron — uma tarefa às 9h da manhã usa hora 9, e uma tarefa às 9h da noite usa hora 21.

Campo 3: Dia do Mês (1–31)

Ao contrário dos outros campos, dia do mês começa em 1, não em 0. Os valores válidos são de 1 a 31. Se você especificar um dia que não existe em determinado mês (por exemplo, dia 31 em abril), a tarefa simplesmente não executa naquele mês. No Quartz, o caractere especial L representa o último dia do mês, independentemente de quantos dias ele tem.

Campo 4: Mês (1–12)

Os valores de mês vão de 1 (janeiro) a 12 (dezembro). Muitos agendadores também aceitam abreviações de três letras: JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC. Elas são insensíveis a maiúsculas na maioria das implementações.

Campo 5: Dia da Semana (0–7)

Este é o campo com mais bagagem histórica. Tanto 0 quanto 7 representam domingo — isso é uma quirk de compatibilidade do Unix antigo. Segunda-feira é 1, terça 2, até sábado 6. Nomes de três letras também funcionam: SUN, MON, TUE, WED, THU, FRI, SAT.

Quando tanto dia do mês quanto dia da semana são especificados (nenhum é *), a maioria dos daemons cron Unix usa lógica OR: a tarefa executa se corresponder a qualquer um dos dois campos. Isso surpreende muitos devs. Se você quer "o dia 15, mas somente se for dia útil", você precisa tratar isso no próprio script da tarefa, não na expressão cron.

Caracteres Especiais

Asterisco (*) — Todo Valor

O asterisco corresponde a todos os valores válidos de um campo. No campo de minuto, * significa minutos de 0 a 59. No campo de mês, significa todos os 12 meses. É o caractere mais comum em expressões cron.

Barra (/) — Valores de Passo

A barra define um intervalo de passo. */5 no campo de minuto significa "a cada 5 minutos". De forma mais precisa, significa "todo valor no intervalo divisível por 5 a partir do primeiro valor do intervalo". Então */5 em minutos resulta em 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55.

Passos podem ser combinados com intervalos: 10-30/5 no campo de minuto significa a cada 5 minutos entre o minuto 10 e o minuto 30, resultando em 10, 15, 20, 25, 30. O passo começa no limite inferior do intervalo.

Vírgula (,) — Lista de Valores

Vírgulas criam uma lista de valores específicos. 1,3,5 no campo de mês significa janeiro, março e maio. 9,17 no campo de hora significa 9h e 17h. Você pode listar quantos valores precisar e combiná-los com outras construções.

Hífen (-) — Intervalo

Um hífen especifica um intervalo inclusivo. 1-5 no campo de dia da semana significa segunda a sexta. 9-17 no campo de hora significa das 9h às 17h. Os intervalos são inclusivos em ambos os extremos.

Ponto de Interrogação (?) — Sem Valor Específico (Somente Quartz)

O cron Unix padrão não suporta ?. No Quartz Scheduler, ele é usado nos campos de dia do mês ou dia da semana para significar "não me importo com este campo". Como o Quartz nem sempre consegue resolver conflitos entre dia do mês e dia da semana, um dos dois deve ser definido como ? quando o outro é especificado. 0 0 15 * ? significa "o dia 15 de todo mês, qualquer dia da semana." 0 0 ? * MON significa "toda segunda-feira, qualquer dia do mês."

L — Último (Somente Quartz)

L no campo de dia do mês significa o último dia do mês. L no campo de dia da semana significa sábado, ou quando combinado com um número (ex: 5L), a última ocorrência daquele dia da semana no mês. 5L é a última sexta-feira do mês.

W — Dia Útil Mais Próximo (Somente Quartz)

W no campo de dia do mês encontra o dia útil (segunda a sexta) mais próximo do dia especificado. 15W significa o dia útil mais próximo do dia 15. Se o dia 15 cair no sábado, a tarefa executa no dia 14 (sexta). Se cair no domingo, executa no dia 16 (segunda). W não cruza os limites do mês.

Cerquilha (#) — Enésimo Dia da Semana do Mês (Somente Quartz)

# especifica a N-ésima ocorrência de um dia da semana em um mês. 5#2 significa a segunda sexta-feira do mês. 2#1 significa a primeira terça-feira. Se a ocorrência especificada não existir em determinado mês, a tarefa não executa naquele mês.

Padrões Cron Comuns

# Todo minuto
* * * * *

# Todo dia à meia-noite (00:00)
0 0 * * *

# Todo dia às 9h30
30 9 * * *

# Toda segunda-feira às 8h
0 8 * * 1

# Primeiro dia de cada mês ao meio-dia
0 12 1 * *

# A cada 15 minutos
*/15 * * * *

# Dias de semana às 18h
0 18 * * 1-5

Você pode testar e validar qualquer um desses usando a ferramenta Cron Parser, que mostra os próximos cinco horários de execução para qualquer expressão e destaca a sintaxe inválida. Use o Conversor de Timestamp se precisar verificar a que corresponde um timestamp Unix específico no seu fuso horário local.

A Extensão de 6 Campos: Quartz Scheduler

O Quartz Scheduler — muito usado no ecossistema Java e adotado por muitos agendadores corporativos — adiciona um campo obrigatório de segundos no início da expressão. O formato se torna: segundo minuto hora dia-do-mês mês dia-da-semana.

# Quartz 6 campos: segundo minuto hora dia mês dia-da-semana
# Executar exatamente nos 00 segundos, 30 minutos, toda hora
0 30 * * * ?

# Executar à meia-noite todo dia
0 0 0 * * ?

# Executar a cada 5 segundos
0/5 * * * * ?

# Último dia do mês às 10h
0 0 10 L * ?

# Última sexta-feira do mês às 15h
0 0 15 ? * 6L

Principais diferenças em relação ao cron padrão: o campo de segundos (0–59) é o primeiro e obrigatório; dia da semana usa 1 (domingo) a 7 (sábado), não 0–6; ? é obrigatório em dia do mês ou dia da semana quando o outro é especificado; e L, W e # são caracteres especiais válidos.

Nunca cole uma expressão Quartz em um crontab Unix sem remover o campo de segundos e ajustar a numeração do dia da semana. Os parsers não são intercambiáveis.

Cron em Diferentes Sistemas

Linux/Unix crontab (Vixie cron)

A forma original e mais comum. Cinco campos separados por espaço, seguidos do comando. Variáveis de ambiente como CRON_TZ ou TZ definem o fuso horário. Crontabs de usuário são editados com crontab -e; crontabs do sistema ficam em /etc/cron.d/. Os atalhos @reboot, @daily, @hourly, @weekly e @monthly são amplamente suportados como aliases para padrões comuns.

GitHub Actions

O GitHub Actions usa sintaxe cron padrão de 5 campos, mas o fuso horário é sempre UTC — não há como especificar um fuso horário local na própria expressão. As expressões são avaliadas no nível do repositório, não por job. Note que workflows agendados podem atrasar alguns minutos durante períodos de alta carga na infraestrutura do GitHub.

# Sintaxe de agendamento do GitHub Actions (5 campos, UTC somente)
on:
  schedule:
    # Executar todo dia às 02:30 UTC
    - cron: '30 2 * * *'
    # Executar toda segunda-feira às 09:00 UTC
    - cron: '0 9 * * 1'

A documentação oficial do GitHub Actions sobre cron observa que o intervalo mínimo é de 5 minutos — expressões que executariam com mais frequência que isso são silenciosamente ignoradas.

AWS EventBridge (CloudWatch Events)

O AWS EventBridge suporta tanto expressões de taxa (rate(5 minutes)) quanto expressões cron. A variante cron deles tem 6 campos mas difere do Quartz: dia da semana usa nomes Dom–Sáb ou 1–7 onde 1 é domingo, todos os horários são UTC, e pelo menos um entre dia do mês e dia da semana deve ser ?. A AWS não suporta os caracteres W nem #.

# AWS EventBridge (cron em UTC, variante de 6 campos)
# Executa todo dia às 10:00 AM UTC
cron(0 10 * * ? *)

# Executa às 18:00 no último dia útil de cada mês
cron(0 18 L-1 * ? *)

Kubernetes CronJob

O Kubernetes CronJob usa sintaxe cron padrão de 5 campos. O fuso horário padrão é o do processo kube-controller-manager (geralmente UTC em clusters gerenciados). O Kubernetes 1.25 adicionou o campo timeZone na spec do CronJob, permitindo configuração de fuso por tarefa sem depender do fuso do sistema.

Node.js (node-cron / cron npm)

O popular pacote node-cron suporta expressões padrão de 5 campos mais um 6º campo de segundos opcionalmente adicionado antes. O pacote cron é compatível com Quartz. Ambos suportam strings de fuso horário (ex: America/Sao_Paulo) como opção de construtor. Consulte a documentação do seu pacote específico para confirmar qual formato ele espera.

Armadilhas Comuns

Suposições de fuso horário

O cron executa no fuso horário do servidor ou container, que frequentemente é UTC em ambientes de nuvem. Uma tarefa planejada para rodar às "9h no horário comercial" definida como 0 9 * * * executará às 9h UTC — o que pode ser 5h, 6h ou 11h no seu fuso horário dependendo do offset e do horário de verão. Sempre defina CRON_TZ, use o campo de fuso horário do agendador ou converta seu horário alvo para UTC explicitamente. O Conversor de Fuso Horário pode ajudar a encontrar o equivalente UTC para qualquer horário local em qualquer fuso.

Lógica OR entre dia do mês e dia da semana

No cron Unix, quando os campos de dia do mês e dia da semana são ambos não-*, o daemon executa a tarefa se qualquer um dos dois corresponder. Então 0 9 15 * 1 executa no dia 15 de todo mês E toda segunda-feira — não apenas nas segundas que caem no dia 15. Para obter lógica AND, você precisa implementar a verificação adicional dentro do script da tarefa.

Confundir valores de passo com intervalos

*/5 significa "a cada 5 minutos a partir de 0" (0, 5, 10 ...). 5/5 significa "a cada 5 minutos a partir de 5" (5, 10, 15 ...). 5-30/5 significa "a cada 5 minutos entre o minuto 5 e o minuto 30" (5, 10, 15, 20, 25, 30). Misturar esses com intervalos pode produzir resultados inesperados se você não for deliberado sobre o valor inicial.

A armadilha do "a cada segundo"

A resolução mínima do cron no formato padrão de 5 campos é um minuto. Você não pode agendar uma tarefa cron para executar a cada segundo ou a cada poucos segundos usando um crontab. Para agendamentos sub-minuto, use um temporizador em nível de linguagem (setInterval no Node.js, APScheduler no Python) ou um sistema de filas dedicado em vez de cron. Se você precisar a cada 30 segundos, execute duas tarefas cron: uma em * * * * * e outra que aguarda 30 segundos antes de executar.

Esquecendo a numeração dos meses

No cron padrão, os meses vão de 1 (janeiro) a 12 (dezembro). Em algumas APIs de data de linguagens de programação, os meses têm índice 0 (0 = janeiro, 11 = dezembro). Se você está gerando expressões cron programaticamente a partir de objetos de data, verifique se não está deslocado em um no campo de mês.

Valide Suas Expressões

O Cron Parser do Toova mostra os próximos cinco horários de execução agendados para qualquer expressão, suporta a sintaxe Quartz de 5 e 6 campos e sinaliza valores inválidos em linha. Para uma verificação rápida, o crontab.guru é uma ferramenta interativa muito conhecida que descreve expressões em linguagem simples. Vale a pena manter os dois nos favoritos.

Ao trabalhar com timestamps e horários agendados, o Conversor de Timestamp traduz entre timestamps Unix e datas legíveis por humanos em qualquer fuso horário. Para tarefas que envolvem agendamento sensível a fuso horário, combine-o com o Conversor de Fuso Horário para verificar offsets, transições de horário de verão e equivalentes UTC antes de escrever sua expressão final.