Quarterly Midnight Cron Job on the 15th | CronBase
0 0 15 */3 * At midnight on the fifteenth day of every third month.
The `0 0 15 */3 *` cron expression schedules a task to run at midnight (00:00) on the 15th day of every third month. This quarterly cycle typically triggers in January, April, July, and October, making it ideal for seasonal maintenance, financial reporting, and long-term log archiving.
- Minute
- 0
- Hour
- 0
- Day of Month
- 15
- Month
- */3
- Day of Week
- *
Next 5 Runs
- in 81d 3h
- in 173d 3h
- in 263d 3h
- in 354d 3h
- in 446d 3h
* Tools
Code & Implementations
#!/usr/bin/env bash
# Set up a system-wide cron entry in /etc/cron.d/quarterly-job
# Ensure the target script exists and has executable permissions
cat << 'EOF' > /etc/cron.d/quarterly-job
# Run the quarterly report script at midnight on the 15th of every 3rd month
0 0 15 */3 * root /usr/local/bin/run-quarterly-report.sh >> /var/log/quarterly-job.log 2>&1
EOF
chmod 0644 /etc/cron.d/quarterly-job
echo "Cron job successfully registered in /etc/cron.d/" › Setup notes
Place this script in your deployment pipeline. It creates a system-level cron entry under /etc/cron.d that routes output to a dedicated log file for easy auditing.
const cron = require('node-cron');
const { exec } = require('child_process');
// Schedule task to run at 00:00 on day 15 of every 3rd month
cron.schedule('0 0 15 */3 *', () => {
console.log('[INFO] Triggering quarterly database archiving task...');
exec('/usr/local/bin/archive-quarterly-data.sh', (error, stdout, stderr) => {
if (error) {
console.error(`[ERROR] Execution failed: ${error.message}`);
return;
}
if (stderr) {
console.warn(`[WARN] Process stderr: ${stderr}`);
}
console.log(`[SUCCESS] Output: ${stdout}`);
});
}, {
scheduled: true,
timezone: "UTC"
}); › Setup notes
Install the dependency using npm install node-cron. Ensure the Node.js process is managed by a process manager like PM2 to keep it alive perpetually.
from apscheduler.schedulers.blocking import BlockingScheduler
import logging
import subprocess
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('QuarterlyScheduler')
def run_quarterly_task():
logger.info("Starting quarterly maintenance script...")
try:
result = subprocess.run(["/usr/local/bin/quarterly-cleanup.sh"], capture_output=True, text=True, check=True)
logger.info(f"Task completed successfully: {result.stdout}")
except subprocess.CalledProcessError as err:
logger.error(f"Task failed with exit code {err.returncode}. Error: {err.stderr}")
scheduler = BlockingScheduler(timezone="UTC")
# standard cron fields: minute, hour, day, month, day_of_week
scheduler.add_job(run_quarterly_task, 'cron', month='*/3', day=15, hour=0, minute=0)
try:
logger.info("Scheduler started. Waiting for next quarterly execution...")
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler stopped.") › Setup notes
Run this script using Python 3 after installing APScheduler: pip install apscheduler. It is configured to run in UTC to prevent timezone issues.
package main
import (
"log"
"os/exec"
"time"
"github.com/robfig/cron/v3"
)
func main() {
// Use UTC timezone to guarantee consistency across DST shifts
nyc, err := time.LoadLocation("UTC")
if err != nil {
log.Fatalf("Failed to load timezone: %v", err)
}
c := cron.New(cron.WithLocation(nyc))
// Register the job using standard 5-field cron syntax
_, err = c.AddFunc("0 0 15 */3 *", func() {
log.Println("Executing scheduled quarterly routine...")
cmd := exec.Command("/usr/local/bin/quarterly-audit")
out, err := cmd.CombinedOutput()
if err != nil {
log.Printf("Error running quarterly routine: %v, Output: %s", err, string(out))
return
}
log.Printf("Quarterly routine finished: %s", string(out))
})
if err != nil {
log.Fatalf("Error scheduling cron job: %v", err)
}
c.Start()
select {} // Block main thread forever
} › Setup notes
Compile and run this program. Ensure your target binary /usr/local/bin/quarterly-audit is present and executable by the user running the Go process.
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.logging.Logger;
@Component
public class QuarterlyTaskScheduler {
private static final Logger LOGGER = Logger.getLogger(QuarterlyTaskScheduler.class.getName());
// Spring Cron supports 6 fields: second, minute, hour, day, month, day-of-week
@Scheduled(cron = "0 0 0 15 */3 *", zone = "UTC")
public void executeQuarterlyJob() {
LOGGER.info("Starting scheduled quarterly integration job...");
try {
Process process = Runtime.getRuntime().exec("/usr/local/bin/quarterly-sync.sh");
int exitCode = process.waitFor();
if (exitCode == 0) {
LOGGER.info("Quarterly integration completed successfully.");
} else {
LOGGER.severe("Quarterly integration failed with exit code: " + exitCode);
}
} catch (IOException | InterruptedException e) {
LOGGER.severe("Exception during quarterly job execution: " + e.getMessage());
Thread.currentThread().interrupt();
}
}
} › Setup notes
Enable scheduling in your Spring Boot application by adding @EnableScheduling to your main class, then place this bean class inside your component scan path.
apiVersion: batch/v1
kind: CronJob
metadata:
name: quarterly-data-cleanup
namespace: production
spec:
schedule: "0 0 15 */3 *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: clean-worker
image: python:3.10-slim
command:
- python
- -c
- "print('Running scheduled quarterly data retention script...')"
restartPolicy: OnFailure › Setup notes
Apply this manifest using kubectl apply -f cronjob.yaml. The concurrencyPolicy: Forbid setting prevents concurrent runs if a previous run is hanging.
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 15 */3 ? *) Systemd Timer
OnCalendar*-00/3-15 00:00:00
[Unit]
Description=Timer for cron expression: 0 0 15 */3 *
[Timer]
OnCalendar=*-00/3-15 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
Which months exactly does this cron expression run in?
Standard cron engines evaluate `*/3` starting from the first month of the year. Therefore, this schedule executes on the 15th of January, April, July, and October.
What happens if the system is offline at midnight on the 15th?
Standard cron will skip the execution entirely. For critical quarterly tasks, you should integrate an orchestrator like Anacron, or design your application to check the last run timestamp upon startup and trigger missed executions.
How do timezone changes or Daylight Saving Time affect this job?
Running at exactly midnight (00:00) is generally safe from DST skips, but fallback transitions can cause double executions in autumn. To prevent this, configure your system clock or container runtime to run in Coordinated Universal Time (UTC).
Can I use this schedule for quarterly financial reporting tasks?
Yes, this is a standard cadence for quarterly reports. However, because it runs on the 15th, ensure that all transaction data from the previous quarter has been fully reconciled and closed before the job begins.
How should I handle failures for a job that runs so infrequently?
Because this job only triggers four times a year, failure visibility is critical. Implement structured logging, external health checks (like Dead Man's Snitches), and configure immediate alerting via Slack, PagerDuty, or email upon failure.
* Explore
Related expressions you might need
Last verified: