Cron Expression: Every Day at Midnight (0 0 * * *)
Need to generate a cron expression?
Use CronOS to generate any cron expression you wish with natural language. Simply describe what you need, and we'll create the perfect cron expression for you. It's completely free!
Cron Expression: Every Day at Midnight (0 0 * * *)
The cron expression 0 0 * * * executes a task every day at midnight (00:00), making it one of the most commonly used patterns for daily backups, reports, cleanup operations, and data processing tasks.
Expression Breakdown
0 0 * * *
│ │ │ │ │
│ │ │ │ └─── Day of week: * (every day)
│ │ │ └───── Month: * (every month)
│ │ └─────── Day of month: * (every day)
│ └───────── Hour: 0 (at hour 0, midnight)
└─────────── Minute: 0 (at minute 0)
Field Values
| Field | Value | Meaning |
|---|---|---|
| Minute | 0 | At minute 0 |
| Hour | 0 | At hour 0 (midnight) |
| Day of Month | * | Every day (1-31) |
| Month | * | Every month (1-12) |
| Day of Week | * | Every day of week (0-7) |
Execution Time
This expression runs once per day at:
- 00:00 (midnight)
Common Use Cases
1. Daily Backups
0 0 * * * /usr/local/bin/daily-backup.sh
Create full backups of databases, files, or entire systems at midnight.
2. Daily Reports
0 0 * * * /usr/bin/python3 /scripts/generate-daily-report.py
Generate daily analytics reports, summaries, or data aggregations.
3. Log Rotation
0 0 * * * /usr/local/bin/rotate-logs.sh
Rotate, compress, or archive log files daily.
4. Database Maintenance
0 0 * * * /usr/local/bin/db-maintenance.sh
Run database cleanup, optimization, or maintenance tasks.
5. Cache Cleanup
0 0 * * * /usr/bin/python3 /scripts/cleanup-cache.py
Clear or refresh cached data at the start of each day.
6. Data Processing
0 0 * * * /usr/bin/python3 /scripts/process-daily-data.py
Process daily data batches, ETL operations, or data transformations.
Example Implementations
Daily Backup Script
#!/bin/bash
# /usr/local/bin/daily-backup.sh
BACKUP_DIR="/var/backups/daily"
SOURCE_DIR="/var/data"
TIMESTAMP=$(date +%Y%m%d)
LOG_FILE="/var/log/backups.log"
mkdir -p $BACKUP_DIR
# Create daily backup
tar -czf "$BACKUP_DIR/backup_$TIMESTAMP.tar.gz" \
-C $(dirname $SOURCE_DIR) \
$(basename $SOURCE_DIR) >> $LOG_FILE 2>&1
# Database backup (if using PostgreSQL)
# pg_dump -U dbuser app_db | gzip > "$BACKUP_DIR/db_backup_$TIMESTAMP.sql.gz"
# Clean up backups older than 30 days
find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete
find $BACKUP_DIR -name "*.sql.gz" -mtime +30 -delete
echo "$(date): Daily backup completed" >> $LOG_FILE
Python Daily Report
# generate-daily-report.py
import json
from datetime import datetime, timedelta
import sqlite3
def generate_daily_report():
conn = sqlite3.connect('/var/data/app.db')
cursor = conn.cursor()
# Get data from yesterday
yesterday = datetime.now() - timedelta(days=1)
start_date = yesterday.replace(hour=0, minute=0, second=0)
end_date = yesterday.replace(hour=23, minute=59, second=59)
# Aggregate metrics
cursor.execute('''
SELECT
COUNT(*) as total_requests,
AVG(response_time) as avg_response_time,
COUNT(CASE WHEN status_code >= 400 THEN 1 END) as errors,
COUNT(CASE WHEN status_code >= 500 THEN 1 END) as server_errors
FROM requests
WHERE timestamp >= ? AND timestamp <= ?
''', (start_date, end_date))
metrics = cursor.fetchone()
report = {
'date': yesterday.strftime('%Y-%m-%d'),
'total_requests': metrics[0],
'avg_response_time': round(metrics[1], 2) if metrics[1] else 0,
'errors': metrics[2],
'server_errors': metrics[3],
'error_rate': round((metrics[2] / metrics[0] * 100), 2) if metrics[0] > 0 else 0
}
# Save report
report_file = f'/var/reports/daily_report_{yesterday.strftime("%Y%m%d")}.json'
with open(report_file, 'w') as f:
json.dump(report, f, indent=2)
print(f"{datetime.now()}: Daily report generated for {yesterday.strftime('%Y-%m-%d')}")
conn.close()
if __name__ == '__main__':
generate_daily_report()
Log Rotation Script
#!/bin/bash
# /usr/local/bin/rotate-logs.sh
LOG_DIR="/var/log/app"
ARCHIVE_DIR="/var/log/archive"
RETENTION_DAYS=30
mkdir -p $ARCHIVE_DIR
# Rotate logs
for logfile in $LOG_DIR/*.log; do
if [ -f "$logfile" ]; then
filename=$(basename $logfile)
archive_path="$ARCHIVE_DIR/${filename}.$(date +%Y%m%d).gz"
# Compress and archive
gzip -c $logfile > $archive_path
# Truncate original log
> $logfile
echo "$(date): Rotated $filename"
fi
done
# Clean up old archives
find $ARCHIVE_DIR -name "*.gz" -mtime +$RETENTION_DAYS -delete
Best Practices
- System Load: Midnight is often a low-traffic period, ideal for heavy operations
- Error Handling: Implement comprehensive error handling and logging
- Locking: Use file locks to prevent concurrent execution
- Monitoring: Set up alerts for failed daily jobs
- Resource Management: Monitor CPU, memory, and I/O usage
- Backup Verification: Verify backups after creation
When to Use
✅ Good for:
- Daily backups
- Report generation
- Log rotation
- Database maintenance
- Cache cleanup
- Data processing
- ETL operations
❌ Avoid for:
- Real-time critical operations
- Tasks requiring immediate execution
- Very long-running processes (over 23 hours)
Related Patterns
| Pattern | Expression | Description |
|---|---|---|
| Daily at 1 AM | 0 1 * * * | One hour after midnight |
| Daily at 8 AM | 0 8 * * * | Start of business day |
| Daily at noon | 0 12 * * * | Midday |
| Daily at 6 PM | 0 18 * * * | End of business day |
Conclusion
The 0 0 * * * expression is perfect for daily maintenance tasks that should run at midnight. It's one of the most commonly used cron patterns in production environments, ideal for backups, reports, and cleanup operations that need to run once per day during low-traffic periods.
Need to generate a cron expression?
Use CronOS to generate any cron expression you wish with natural language. Simply describe what you need, and we'll create the perfect cron expression for you. It's completely free!