Quarterly Midnight Cleanups and Reports | CronBase
0 0 1 */3 * At midnight on the first day of every third month, starting in January.
This cron expression executes a task at midnight on the first day of every third month, initiating a quarterly schedule. It triggers at twelve AM on January first, April first, July first, and October first, providing a predictable cadence for financial reporting, automated data archiving, and long-term log rotation.
- Minute
- 0
- Hour
- 0
- Day of Month
- 1
- Month
- */3
- Day of Week
- *
Next 5 Runs
- in 67d 3h
- in 159d 3h
- in 249d 3h
- in 340d 3h
- in 432d 3h
* Tools
Code & Implementations
#!/usr/bin/env bash
set -euo pipefail
# Register this script in your system crontab using:
# 0 0 1 */3 * /usr/local/bin/quarterly_cleanup.sh >> /var/log/cron_quarterly.log 2>&1
LOG_FILE="/var/log/cron_quarterly.log"
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Starting quarterly maintenance task..." | tee -a "$LOG_FILE"
# Perform cleanup or reporting
if ! /usr/local/bin/perform_quarterly_audit.sh; then
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] ERROR: Quarterly audit failed!" >&2
exit 1
fi
echo "[$(date -u +'%Y-%m-%dT%H:%M:%SZ')] Quarterly maintenance completed successfully." | tee -a "$LOG_FILE" › Setup notes
Place this script in /usr/local/bin/quarterly_cleanup.sh, make it executable with chmod +x, and add the corresponding cron entry using crontab -e.
const cron = require('node-cron');
// Schedule quarterly task: 0 0 1 */3 * (At midnight on the 1st of every 3rd month)
cron.schedule('0 0 1 */3 *', async () => {
console.log(`[${new Date().toISOString()}] Starting quarterly data aggregation...`);
try {
await runQuarterlyAggregation();
console.log(`[${new Date().toISOString()}] Quarterly aggregation completed successfully.`);
} catch (error) {
console.error(`[${new Date().toISOString()}] CRITICAL: Quarterly job failed:`, error);
// Trigger alerting system here (e.g., PagerDuty, Sentry)
}
});
async function runQuarterlyAggregation() {
return new Promise((resolve) => setTimeout(resolve, 5000));
} › Setup notes
Install node-cron using 'npm install node-cron' and run this script as a long-running background process using a process manager like PM2.
import logging
from datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
def execute_quarterly_archive():
logger.info("Quarterly archive job started.")
try:
# Place resource-heavy database archiving logic here
logger.info("Successfully archived quarterly records.")
except Exception as e:
logger.error(f"Failed to execute quarterly archive: {str(e)}", exc_info=True)
if __name__ == '__main__':
scheduler = BlockingScheduler()
# Standard cron syntax: 0 0 1 */3 * -> month='1,4,7,10', day=1, hour=0, minute=0
scheduler.add_job(
execute_quarterly_archive,
'cron',
month='1,4,7,10',
day=1,
hour=0,
minute=0,
id='quarterly_cleanup_job'
)
logger.info("Scheduler initialized. Waiting for quarterly execution...")
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler shut down safely.") › Setup notes
Install apscheduler using 'pip install apscheduler' and run this script within a persistent execution environment.
package main
import (
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/robfig/cron/v3"
)
func main() {
logger := log.New(os.Stdout, "[QuarterlyCron] ", log.LstdFlags|log.Lshortfile)
c := cron.New()
// "0 0 1 */3 *" - At midnight on day-of-month 1 in every 3rd month
_, err := c.AddFunc("0 0 1 */3 *", func() {
logger.Println("Quarterly reporting job initiated...")
err := runQuarterlyReport()
if err != nil {
logger.Printf("CRITICAL: Quarterly report failed: %v\n", err)
return
}
logger.Println("Quarterly reporting completed successfully.")
})
if err != nil {
logger.Fatalf("Failed to initialize cron schedule: %v", err)
}
c.Start()
logger.Println("Cron scheduler started successfully.")
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
<-sigChan
logger.Println("Stopping scheduler gracefully...")
c.Stop()
}
func runQuarterlyReport() error {
time.Sleep(2 * time.Second)
return nil
} › Setup notes
Fetch the cron library using 'go get github.com/robfig/cron/v3', build the binary, and run it as a systemd service.
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 QuarterlyTaskScheduler {
private static final Logger logger = LoggerFactory.getLogger(QuarterlyTaskScheduler.class);
// Spring scheduled tasks use 6-field cron syntax: second, minute, hour, day, month, day-of-week
// "0 0 0 1 */3 *" translates to: midnight on the first day of every 3rd month
@Scheduled(cron = "0 0 0 1 */3 *")
public void executeQuarterlyMaintenance() {
logger.info("Starting scheduled quarterly maintenance task.");
try {
performDataPurge();
logger.info("Quarterly maintenance task completed successfully.");
} catch (Exception e) {
logger.error("Error occurred during quarterly maintenance execution: ", e);
}
}
private void performDataPurge() throws Exception {
Thread.sleep(5000);
}
} › Setup notes
Ensure @EnableScheduling is active in your main Spring Boot configuration class, and place this component inside your spring-scanned package.
apiVersion: batch/v1
kind: CronJob
metadata:
name: quarterly-cleanup-job
namespace: production
spec:
schedule: "0 0 1 */3 *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: cleanup-worker
image: alpine:3.18
command:
- /bin/sh
- -c
- |
echo "Starting quarterly storage optimization..."
# Execute storage maintenance tasks here
echo "Quarterly storage optimization completed successfully."
restartPolicy: OnFailure › Setup notes
Apply this manifest with 'kubectl apply -f cronjob.yaml' in your production namespace. The concurrencyPolicy is set to Forbid to prevent overlapping runs.
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 1 */3 ? *) Systemd Timer
OnCalendar*-00/3-01 00:00:00
[Unit]
Description=Timer for cron expression: 0 0 1 */3 *
[Timer]
OnCalendar=*-00/3-01 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
Which months exactly does this quarterly cron schedule run?
This cron schedule runs on the first day of January, April, July, and October. These months correspond to the standard calendar quarters (Q1, Q2, Q3, and Q4).
What happens if my server is offline at midnight on the first day of the quarter?
Standard Linux cron will miss the execution entirely. For critical business tasks, you should use an orchestrator like Kubernetes CronJobs, Airflow, or a tool like anacron that catches up on missed runs.
How do I test this quarterly cron expression without waiting three months?
You can temporarily modify the expression to run in the next few minutes (e.g., '*/5 * * * *') in your staging environment to verify the script logic, or trigger the job manually via systemctl or kubectl.
Can I offset this to run at 2 AM instead of midnight to avoid peak traffic?
Yes, you can shift the time by changing the hour field. Modify the expression to '0 2 1 */3 *' to run at 2:00 AM on the first of the month, reducing resource contention.
Does standard cron support timezone-aware quarterly scheduling?
No, standard system cron uses the local timezone of the host operating system. To run based on a specific timezone, you must configure the server's timezone or use an application-level scheduler.
* Explore
Related expressions you might need
Last verified: