How to Schedule Daily Jobs at Midnight | CronBase
0 0 * * * Every day at midnight.
The `0 0 * * *` cron expression schedules a task to execute once every single day precisely at midnight. This consistent daily frequency is widely utilized for routine maintenance operations, including database backups, log rotations, system health reports, and data synchronization tasks across enterprise production environments.
- Minute
- 0
- Hour
- 0
- Day of Month
- *
- Month
- *
- Day of Week
- *
Next 5 Runs
- in 1h 9m
- in 1d 1h
- in 2d 1h
- in 3d 1h
- in 4d 1h
* Tools
Code & Implementations
#!/usr/bin/env bash
# Production Bash script for daily midnight execution with locking
set -euo pipefail
LOCK_FILE="/var/lock/daily_midnight_job.lock"
LOG_FILE="/var/log/daily_midnight_job.log"
# Implement file locking to prevent concurrent runs
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
echo "$(date -u) - ERROR: Job is already running. Exiting." >&2
exit 1
fi
echo "$(date -u) - INFO: Starting daily midnight maintenance..." >> "$LOG_FILE"
# Execute business logic
if ! /usr/local/bin/run-daily-cleanup >> "$LOG_FILE" 2>&1; then
echo "$(date -u) - ERROR: Daily cleanup failed!" >&2
exit 1
fi
echo "$(date -u) - INFO: Daily maintenance completed successfully." >> "$LOG_FILE" › Setup notes
Save this script to /usr/local/bin/daily-cleanup.sh, make it executable with chmod +x, and add '0 0 * * * /usr/local/bin/daily-cleanup.sh' to your system crontab.
// Production Node.js cron implementation using node-cron
const cron = require('node-cron');
const { exec } = require('child_process');
console.log('Daily midnight cron scheduler initialized.');
// Schedule '0 0 * * *' (Every day at midnight)
const task = cron.schedule('0 0 * * *', async () => {
const startTime = new Date().toISOString();
console.log(`[${startTime}] Starting daily midnight task...`);
try {
await runDailyMaintenance();
console.log(`[${new Date().toISOString()}] Daily task completed successfully.`);
} catch (error) {
console.error(`[${new Date().toISOString()}] Daily task failed:`, error);
}
}, {
scheduled: true,
timezone: "UTC"
});
async function runDailyMaintenance() {
return new Promise((resolve, reject) => {
exec('/usr/local/bin/daily-cleanup.sh', (error, stdout, stderr) => {
if (error) {
return reject(error);
}
resolve(stdout);
});
});
} › Setup notes
Install the node-cron dependency using 'npm install node-cron' and run this script as a long-lived background process using PM2 or Docker.
# Production Python cron runner utilizing APScheduler
import logging
import sys
import time
from apscheduler.schedulers.background import BackgroundScheduler
from pytz import utc
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s [%(levelname)s] %(message)s',
handlers=[logging.StreamHandler(sys.stdout)]
)
def run_daily_job():
logging.info("Executing scheduled daily midnight job...")
try:
# Simulate business logic execution
time.sleep(5)
logging.info("Daily midnight job completed successfully.")
except Exception as e:
logging.error(f"Daily job failed with exception: {str(e)}")
if __name__ == "__main__":
scheduler = BackgroundScheduler(timezone=utc)
scheduler.add_job(run_daily_job, 'cron', hour=0, minute=0, id='daily_midnight_job')
scheduler.start()
logging.info("Scheduler started. Waiting for execution at 00:00 UTC...")
try:
while True:
time.sleep(1)
except (KeyboardInterrupt, SystemExit):
scheduler.shutdown()
logging.info("Scheduler stopped cleanly.") › Setup notes
Install required modules via 'pip install apscheduler pytz' and run the script inside a systemd service to keep it active in the background.
package main
import (
"context"
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/robfig/cron/v3"
)
func main() {
logger := log.New(os.Stdout, "[CRON] ", log.LstdFlags|log.LUTC)
logger.Println("Initializing daily midnight cron scheduler...")
// Use UTC timezone explicitly to handle DST safely
c := cron.New(cron.WithLocation(time.UTC), cron.WithLogger(cron.VerbosePrintfLogger(logger)))
_, err := c.AddFunc("0 0 * * *", func() {
logger.Println("Starting execution of daily midnight job...")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer cancel()
if err := executeJob(ctx); err != nil {
logger.Printf("ERROR: Daily job failed: %v\n", err)
return
}
logger.Println("Daily job finished successfully.")
})
if err != nil {
logger.Fatalf("Failed to schedule job: %v", err)
return
}
c.Start()
defer c.Stop()
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
logger.Println("Shutting down scheduler gracefully...")
}
func executeJob(ctx context.Context) error {
return nil
} › Setup notes
Initialize the project using 'go mod init', download the package using 'go get github.com/robfig/cron/v3', and compile the binary for deployment.
package com.example.cron;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.Instant;
@Component
public class DailyMidnightScheduler {
private static final Logger logger = LoggerFactory.getLogger(DailyMidnightScheduler.class);
/**
* Executes once every day at midnight (00:00) UTC.
* Spring Scheduled uses a 6-field cron pattern: second, minute, hour, day, month, day-of-week.
*/
@Scheduled(cron = "0 0 0 * * *", zone = "UTC")
public void executeDailyTask() {
logger.info("Daily midnight task started at: {}", Instant.now());
try {
performMaintenance();
logger.info("Daily midnight task completed successfully.");
} catch (Exception e) {
logger.error("Critical error during daily execution: ", e);
}
}
private void performMaintenance() throws Exception {
Thread.sleep(2000);
}
} › Setup notes
Ensure that '@EnableScheduling' is declared on your main Spring Boot application class, and place this component class inside your component scan path.
apiVersion: batch/v1
kind: CronJob
metadata:
name: daily-midnight-maintenance
namespace: default
spec:
schedule: "0 0 * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 600
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: worker
image: busybox:1.36
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- "echo 'Starting daily cleanup...'; sleep 10; echo 'Cleanup finished successfully.'"
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "100m"
memory: "128Mi"
restartPolicy: OnFailure › Setup notes
Apply the manifest to your cluster using 'kubectl apply -f cronjob.yaml'. Monitor executions using 'kubectl get cronjob' and 'kubectl get jobs'.
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 0 * * ? *) Systemd Timer
OnCalendar*-*-* 00:00:00
[Unit]
Description=Timer for cron expression: 0 0 * * *
[Timer]
OnCalendar=*-*-* 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
What happens to a midnight cron job during Daylight Saving Time (DST) changes?
If your system runs on a local timezone that observes DST, the job may execute twice (when the clock falls back) or be skipped entirely (when the clock springs forward). To prevent this operational unpredictability, configure your servers and cron daemon to use Coordinated Universal Time (UTC) exclusively.
How can I prevent multiple daily cron jobs from overloading my database at midnight?
Avoid scheduling all daily tasks exactly at midnight. Implement random jitter within your scripts (e.g., sleeping for a random duration between 1 and 600 seconds before starting execution) or stagger the cron schedules across a broader maintenance window (such as 01:00, 02:00, etc.).
How do I monitor if a daily cron job failed to run or silent-failed?
Since daily jobs run infrequently, passive logging is insufficient. Implement an active 'dead-man's snitch' system where the job pings an external monitoring service upon successful completion. Set up alerts to trigger if no ping is received within 15 minutes after midnight.
Can I run a daily midnight job on weekdays only instead of every day?
Yes, you can modify the day-of-week field. To restrict execution to Monday through Friday at midnight, change the cron expression from '0 0 * * *' to '0 0 * * 1-5'. This ensures your weekend resources are not spent on business-day tasks.
What is the best way to handle long-running execution of a daily midnight task?
Ensure your scripts are idempotent and implement file locking using tools like flock in Bash or application-level locks. This prevents a delayed or hung instance from overlapping with the next day's scheduled execution, which could lead to data corruption or resource exhaustion.
* Explore
Related expressions you might need
Last verified: