Skip to content

Agendamento cron

Cron todo dia às 9h

A expressão cron para rodar todo dia às 9h é 0 9 * * *: minuto 0 da hora 9, todos os dias da semana. Se isso é 9h no seu relógio depende do fuso do agendador.

Todo dia às 9h
Expressão0 9 * * *
Execuções365 vezes em 2027
OnCalendar do systemd*-*-* 09:00:00

Como funciona

9 no campo de hora com 0 no campo de minuto dá 09:00. Tarefas de início de expediente são onde o fuso horário mais atrapalha, porque a ideia é justamente que as pessoas vejam o resultado ao começar o dia.

Cada plataforma trata o fuso de um jeito. O cronie lê CRON_TZ=America/Sao_Paulo na linha de cima; o Kubernetes usa spec.timeZone; o GitHub Actions aceita timezone ao lado do cron; Vercel e Cloudflare só trabalham em UTC, então você converte na mão.

Para 9h no horário de Brasília num agendador em UTC, escreva 0 12 * * *. Como o Brasil não tem horário de verão desde 2019, a conversão vale o ano todo. Se a equipe está em Portugal ou nos EUA, a conversão muda duas vezes por ano.

Explicação campo a campo
CampoValorSignificado
Minuto0minuto 0 (hora cheia)
Hora9hora 9 (9h)
Dia do mês*todo dia do mês
Mês*todo mês
Dia da semana*todo dia da semana

Próximas execuções

Relógio do agendador

Como no GitHub Actions sem timezone, na Vercel, na Cloudflare e no Kubernetes com timeZone "Etc/UTC".

Próximas execuções, calculadas no seu navegador a partir de agora
ExecuçãoSeu horárioUTC
1Calculando… 
2  
3  
4  
5  

Versões prontas para colar

O mesmo agendamento em cada agendador, com o que muda em cada um.

crontab (Linux, macOS, BSD)

crontab -e
# m h dom mon dow  command
0 9 * * * /usr/local/bin/job.sh >> /var/log/job.log 2>&1
  • O cron usa o fuso horário do servidor. No cronie (Fedora, RHEL), CRON_TZ=America/Sao_Paulo numa linha acima muda o fuso das linhas seguintes.

GitHub Actions

.github/workflows/scheduled.yml
on:
  schedule:
    - cron: '0 9 * * *'
      # timezone: 'America/Sao_Paulo'  # opcional; sem ele, UTC
  workflow_dispatch: {}
  • Roda em UTC, a menos que você defina timezone, e só no branch padrão. A documentação do GitHub avisa que execuções agendadas podem atrasar em horários de pico e que, em repositórios públicos, o agendamento é desativado após 60 dias sem atividade.
  • O início de cada hora é o horário de maior fila no GitHub. Se o minuto exato não importa, troque o 0 por outro minuto, como 17, para atrasar menos.
  • Com timezone num fuso que tem horário de verão, um horário que não existe no dia da mudança é adiado para o próximo horário válido (2:30 vira 3:00, segundo a documentação).

CronJob do Kubernetes

cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
  name: scheduled-job
spec:
  schedule: "0 9 * * *"
  timeZone: "Etc/UTC"
  concurrencyPolicy: Forbid
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
            - name: job
              image: busybox:1.36
              command: ["/bin/sh", "-c", "date; echo running"]
  • spec.timeZone é estável desde o Kubernetes 1.27; sem ele, vale o fuso do kube-controller-manager. concurrencyPolicy: Forbid pula uma execução se a anterior ainda estiver rodando.

Cron Jobs da Vercel

vercel.json
{
  "crons": [
    { "path": "/api/cron", "schedule": "0 9 * * *" }
  ]
}
  • A Vercel sempre usa UTC, não aceita nomes como MON ou JAN e não deixa definir dia do mês e dia da semana ao mesmo tempo.
  • Cabe no plano Hobby, mas lá a precisão é por hora: o disparo pode acontecer em qualquer minuto dentro da hora agendada.

Cloudflare Workers

wrangler.toml
[triggers]
crons = ["0 9 * * *"]
  • Cron Triggers rodam em UTC. Mudanças podem levar até 15 minutos para se propagar pela rede da Cloudflare.

node-cron (Node.js)

scheduler.js
import cron from 'node-cron';

// 6 campos: o primeiro (segundos) é opcional
cron.schedule('0 0 9 * * *', async () => {
  await runJob();
}, { timezone: 'UTC', noOverlap: true });
  • O agendamento vive dentro do processo Node: se ele cair, nada roda; se houver três réplicas, a tarefa roda três vezes. noOverlap pula um disparo enquanto o anterior não terminou.

Timer do systemd

job.timer + job.service
# /etc/systemd/system/job.timer
[Unit]
Description=Run job.service every day at 09:00

[Timer]
OnCalendar=*-*-* 09:00:00
Persistent=true

[Install]
WantedBy=timers.target

# /etc/systemd/system/job.service
[Service]
Type=oneshot
ExecStart=/usr/local/bin/job.sh

# systemctl daemon-reload && systemctl enable --now job.timer
  • Confira com systemd-analyze calendar '*-*-* 09:00:00', que mostra a forma normalizada e a próxima execução. AccuracySec padrão é 1min, então o disparo pode variar até um minuto.
  • Persistent=true roda a tarefa assim que a máquina liga se o horário passou com ela desligada, algo que o cron não faz.

Spring @Scheduled e Quartz

Java
@Scheduled(cron = "0 0 9 * * *", zone = "UTC")
public void runJob() {
    // ...
}

// Quartz CronTrigger:
CronScheduleBuilder.cronSchedule("0 0 9 * * ?")
  • No Spring, o primeiro dos 6 campos são os segundos; o resto segue o cron comum (0 ou 7 = domingo).
  • No Quartz, um dos campos de dia precisa ser ?, por isso o dia da semana leva ?.

Armadilhas

Servidor em UTC, equipe em Brasília

Em UTC, 0 9 * * * roda às 06:00 no horário de Brasília. É o erro mais comum com relatórios matinais em GitHub Actions e Vercel: o fuso do agendador não é o seu.

Fim de semana incluído

0 9 * * * roda também no sábado e no domingo. Só dias úteis é 0 9 * * 1-5; veja todo dia útil às 9h.

Horário de verão em outros países

Se a tarefa atende quem vive com horário de verão, um agendamento em UTC fica uma hora adiantado ou atrasado metade do ano. Use um agendador com fuso ou rode nas duas horas UTC possíveis e saia cedo se a hora local não for 9.

Perguntas frequentes

Qual é a expressão cron para todo dia às 9h?
0 9 * * *, que roda às 09:00 no fuso do agendador, todos os dias.
Como agendar um cron às 9h no horário de Brasília?
No cronie, coloque CRON_TZ=America/Sao_Paulo na linha de cima. No Kubernetes, defina spec.timeZone. No GitHub Actions, adicione timezone ao lado do cron. Em plataformas só UTC, use 0 12 * * *.
Como rodar às 9h30 todo dia?
30 9 * * * roda às 09:30.
Como rodar às 9h e às 17h?
0 9,17 * * * roda às 09:00 e às 17:00 todos os dias.

Revisado em por Arielton Oberek.