Schedule Monthly Tasks on the First at 9 AM | CronBase
0 9 1 * * At nine o'clock in the morning on the first day of every month
This standard cron expression schedules a recurring job to execute precisely at nine AM on the first day of every calendar month. It is commonly utilized in production environments to trigger monthly billing cycles, compile monthly usage reports, clear temporary storage, or initiate major recurring database backups during business hours.
- Minute
- 0
- Hour
- 9
- Day of Month
- 1
- Month
- *
- Day of Week
- *
Next 5 Runs
- in 6d 12h
- in 37d 12h
- in 67d 12h
- in 98d 12h
- in 128d 12h
* Tools
Code & Implementations
#!/usr/bin/env bash
# System crontab entry using flock to prevent concurrent executions.
# Ensure the script runs with a lock and redirects output to a structured log file.
0 9 1 * * /usr/bin/flock -n /var/run/monthly_backup.lock /usr/local/bin/monthly_backup.sh >> /var/log/cron/monthly_backup.log 2>&1 › Setup notes
Place this entry in your system crontab using crontab -e. Ensure the flock utility is installed and that the target log directory exists with appropriate write permissions.
const cron = require('node-cron');
// Schedule the task to run at 09:00 on day 1 of every month
cron.schedule('0 9 1 * *', async () => {
console.log(`[${new Date().toISOString()}] Starting monthly billing aggregation...`);
try {
await runBillingPipeline();
console.log(`[${new Date().toISOString()}] Monthly billing completed successfully.`);
} catch (error) {
console.error(`[${new Date().toISOString()}] CRITICAL: Monthly billing failed:`, error);
// Integrate with incident response tooling (e.g., PagerDuty, Opsgenie) here
}
}, {
scheduled: true,
timezone: "UTC"
});
async function runBillingPipeline() {
return new Promise((resolve) => setTimeout(resolve, 5000));
} › Setup notes
Install the dependency using npm install node-cron. Run this script inside a process manager like PM2 to guarantee continuous execution.
import logging
from datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def execute_monthly_data_sync():
logger.info("Initiating monthly data synchronization pipeline.")
try:
# Business logic goes here
logger.info("Monthly data synchronization completed successfully.")
except Exception as e:
logger.error(f"Failed monthly sync: {str(e)}", exc_info=True)
if __name__ == "__main__":
scheduler = BlockingScheduler()
trigger = CronTrigger(day=1, hour=9, minute=0, timezone='UTC')
scheduler.add_job(execute_monthly_data_sync, trigger=trigger, id='monthly_sync_job')
logger.info("Starting scheduler for monthly sync job...")
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler stopped cleanly.") › Setup notes
Install the required package with pip install apscheduler. Run this script as a background daemon or containerized service.
package main
import (
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/robfig/cron/v3"
)
func main() {
logger := log.New(os.Stdout, "[MonthlyJob] ", log.LstdFlags|log.Lshortfile)
nyc, err := time.LoadLocation("UTC")
if err != nil {
logger.Fatalf("Failed to load timezone: %v", err)
}
c := cron.New(cron.WithLocation(nyc))
_, err = c.AddFunc("0 9 1 * *", func() {
logger.Println("Starting monthly database maintenance...")
if err := runMaintenance(); err != nil {
logger.Printf("ERROR: Maintenance failed: %v\n", err)
} else {
logger.Println("Monthly maintenance completed successfully.")
}
})
if err != nil {
logger.Fatalf("Failed to schedule job: %v", err)
}
c.Start()
logger.Println("Scheduler running, waiting for next execution...")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
logger.Println("Stopping scheduler...")
c.Stop()
}
func runMaintenance() error {
time.Sleep(2 * time.Second)
return nil
} › Setup notes
Initialize your module with go mod init and import github.com/robfig/cron/v3. Compile and run the binary in your production environment.
package com.example.cron;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class MonthlyReportScheduler {
private static final Logger logger = LoggerFactory.getLogger(MonthlyReportScheduler.class);
// Standard cron mapping to Spring's 6-field syntax (second, minute, hour, day, month, day-of-week)
@Scheduled(cron = "0 0 9 1 * *", zone = "UTC")
public void generateMonthlyInvoices() {
logger.info("Starting execution of monthly invoice generation pipeline.");
try {
processInvoices();
logger.info("Monthly invoice generation completed successfully.");
} catch (Exception e) {
logger.error("Critical failure during monthly invoice generation", e);
}
}
private void processInvoices() throws InterruptedException {
Thread.sleep(5000);
}
} › Setup notes
Ensure @EnableScheduling is declared on your main Spring Boot Application class. Spring will bootstrap this component and execute it automatically using its internal scheduler.
apiVersion: batch/v1
kind: CronJob
metadata:
name: monthly-data-cleanup
namespace: production
spec:
schedule: "0 9 1 * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: cleanup-executor
image: alpine:3.18
command:
- /bin/sh
- -c
- "echo 'Starting monthly cleanup'; sleep 10; echo 'Cleanup finished'"
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"
restartPolicy: OnFailure › Setup notes
Apply this manifest to your cluster using kubectl apply -f cronjob.yaml. The Forbid concurrency policy ensures that if a previous run is lagging, a new job will not spawn.
Last verified:
Monitor this schedule in production
Get alerted the moment this cron job fails, is late, or doesn't run. BetterStack tracks execution, duration, and output — no infrastructure required.
Platform Equivalents
AWS EventBridge
Standard cron expressions often need conversion for AWS EventBridge schedules.
cron(0 9 1 * ? *) Systemd Timer
OnCalendar*-*-01 09:00:00
[Unit]
Description=Timer for cron expression: 0 9 1 * *
[Timer]
OnCalendar=*-*-01 09:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
How does daylight saving time affect a monthly cron running at 9 AM?
If your system timezone is set to a local zone that observes DST, the job will shift relative to UTC. In the spring, it may execute an hour earlier in UTC, and in autumn, an hour later. Running servers on UTC avoids these shifts entirely.
What happens if the server is offline at 9:00 AM on the first of the month?
Standard cron daemons do not catch up on missed executions. If your server is offline during that exact minute, the job will not run until the first of the next month. Use tools like anacron or job schedulers with run-missed flags if high availability is required.
How do I test a monthly cron job without waiting for the first of the month?
You can temporarily change the schedule to run every few minutes (e.g., `*/5 * * * *`) in a staging environment, or trigger the underlying script/container manually. Using tools like `cron-mock` or injecting system times in your test suite are also recommended.
Can I use this expression to generate reports for the previous month safely?
Yes, but you must account for late-arriving data. Running at 9:00 AM gives upstream systems nine hours to finalize day-30 or day-31 data. However, for financial systems, it is safer to query data with an explicit date range limit (e.g., up to midnight of the last day) to avoid including new day-1 data.
How do I prevent duplicate runs if the monthly job takes longer than 24 hours?
While monthly jobs rarely run long enough to overlap with the next month's run, they can overlap with other daily tasks. Use a locking mechanism like `flock` in Bash, a Redis-based distributed lock (Redlock) in microservices, or `concurrencyPolicy: Forbid` in Kubernetes to prevent concurrent executions.
* Explore
Related expressions you might need
Last verified: