Run Semi-Annual Tasks at Midnight | CronBase
0 0 1 */6 * At midnight on the first day of January and July
This standard cron expression schedules a job to run at midnight on the first day of January and July. This semi-annual cadence is ideal for long-term maintenance tasks, such as bi-annual database archiving, compliance auditing, certificate rotations, and generating fiscal half-year financial reports without disrupting daily production workloads.
- Minute
- 0
- Hour
- 0
- Day of Month
- 1
- Month
- */6
- Day of Week
- *
Next 5 Runs
- in 159d 3h
- in 340d 3h
- in 524d 3h
- in 706d 3h
- in 890d 3h
* Tools
Code & Implementations
#!/usr/bin/env bash
set -euo pipefail
# Script to install the semi-annual cron job safely
CRON_EXPR="0 0 1 */6 *"
JOB_CMD="/usr/local/bin/run-semi-annual-audit.sh"
LOG_FILE="/var/log/semi_annual_cron.log"
# Check if crontab is available
if ! command -v crontab &> /dev/null; then
echo "Error: crontab utility not found." >&2
exit 1
fi
# Backup current crontab, append new job, and reload
(crontab -l 2>/dev/null | grep -v "$JOB_CMD"; echo "$CRON_EXPR $JOB_CMD >> $LOG_FILE 2>&1") | crontab -
echo "Cron job successfully scheduled to run semi-annually." › Setup notes
Save this script as setup_cron.sh, make it executable with chmod +x, and run it as root or the user who needs to execute the task.
const cron = require('node-cron');
const { exec } = require('child_process');
// Schedule the job for midnight on the first of Jan and Jul
// '0 0 1 */6 *' is supported by node-cron
cron.schedule('0 0 1 */6 *', () => {
console.log(`[${new Date().toISOString()}] Starting semi-annual maintenance task...`);
try {
// Execute heavy data pipeline or cleanup task
exec('/usr/local/bin/archive-old-records.sh', (error, stdout, stderr) => {
if (error) {
console.error(`Execution failed: ${error.message}`);
return;
}
if (stderr) {
console.warn(`Warnings during run: ${stderr}`);
}
console.log(`Task completed successfully: ${stdout}`);
});
} catch (err) {
console.error('Fatal error initiating semi-annual task:', err);
}
}, {
scheduled: true,
timezone: "UTC"
}); › Setup notes
Install node-cron using npm install node-cron, and run this script using node scheduler.js.
import logging
from datetime import datetime
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("SemiAnnualScheduler")
def run_semi_annual_job():
logger.info("Starting semi-annual database compression and compliance reporting at %s", datetime.utcnow())
try:
# Place production logic here
logger.info("Semi-annual job completed successfully.")
except Exception as e:
logger.error("Error executing semi-annual job: %s", str(e), exc_info=True)
if __name__ == "__main__":
scheduler = BlockingScheduler()
# 0 0 1 */6 * matches month='1,7', day=1, hour=0, minute=0
trigger = CronTrigger(month='1,7', day=1, hour=0, minute=0, timezone='UTC')
scheduler.add_job(run_semi_annual_job, trigger)
logger.info("Scheduler initialized. Waiting for semi-annual trigger...")
try:
scheduler.start()
except (KeyboardInterrupt, SystemExit):
logger.info("Scheduler stopped.") › Setup notes
Install APScheduler using pip install apscheduler, and run this script as a background daemon process.
package main
import (
"log"
"os"
"os/signal"
"syscall"
"time"
"github.com/robfig/cron/v3"
)
func main() {
// Use UTC to prevent timezone drifts
nyc, err := time.LoadLocation("UTC")
if err != nil {
log.Fatalf("Failed to load timezone: %v", err)
}
c := cron.New(cron.WithLocation(nyc))
// Standard cron expression: 0 0 1 */6 *
_, err = c.AddFunc("0 0 1 */6 *", func() {
log.Println("Semi-annual job started...")
if err := executeSemiAnnualTask(); err != nil {
log.Printf("CRITICAL: Semi-annual job failed: %v", err)
// Trigger external alert system here
} else {
log.Println("Semi-annual job finished successfully.")
}
})
if err != nil {
log.Fatalf("Failed to schedule cron job: %v", err)
}
c.Start()
log.Println("Cron scheduler started successfully")
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
c.Stop()
}
func executeSemiAnnualTask() error {
// Simulated production task
time.Sleep(5 * time.Second)
return nil
} › Setup notes
Initialize a Go module, go get github.com/robfig/cron/v3, and run the program using go run main.go.
package com.example.scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class SemiAnnualScheduler {
private static final Logger logger = LoggerFactory.getLogger(SemiAnnualScheduler.class);
// Spring standard cron: second, minute, hour, day of month, month, day of week
// "0 0 0 1 1,7 *" runs at 00:00:00 on the 1st of January and July
@Scheduled(cron = "0 0 0 1 1,7 *", zone = "UTC")
public void runSemiAnnualMaintenance() {
logger.info("Starting semi-annual compliance and archiving workflow...");
try {
performArchiving();
logger.info("Semi-annual workflow completed successfully.");
} catch (Exception e) {
logger.error("CRITICAL: Semi-annual workflow failed!", e);
// Implement alert notification logic here (e.g., mail, pagerduty)
}
}
private void performArchiving() throws Exception {
// Production logic goes here
}
} › Setup notes
Ensure @EnableScheduling is declared on your main Spring Boot configuration class, then place this component class in your project.
apiVersion: batch/v1
kind: CronJob
metadata:
name: semi-annual-compliance-audit
namespace: production
spec:
schedule: "0 0 1 */6 *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
jobTemplate:
spec:
template:
spec:
containers:
- name: auditor
image: registry.example.com/ops/auditor:v2.1.0
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "1000m"
memory: "2Gi"
env:
- name: TZ
value: "UTC"
restartPolicy: OnFailure › Setup notes
Save this manifest to a file named cronjob.yaml and apply it to your cluster using kubectl apply -f cronjob.yaml.
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 */6 ? *) Systemd Timer
OnCalendar*-00/6-01 00:00:00
[Unit]
Description=Timer for cron expression: 0 0 1 */6 *
[Timer]
OnCalendar=*-00/6-01 00:00:00
Persistent=true
[Install]
WantedBy=timers.target
Last verified:
Frequently Asked Questions
How does standard cron interpret the `/6` step in the month field?
In standard cron, the step operator `*/6` starts from the first month (January) and increments by six. This resolves to January (month 1) and July (month 7). It does not run every six months from the date of deployment; it is pinned to the calendar year.
What happens if the server timezone changes mid-year?
If the underlying system timezone changes, the next execution will align with the new timezone's midnight. To prevent unexpected shifts in financial or compliance reporting, always force your cron runtime or container environment to execute in UTC.
How can I safely test a job that only runs twice a year?
You should never wait six months to verify your job. Inject a test environment variable to bypass the schedule check, or temporarily modify the cron expression to run in the next five minutes in a staging environment to validate the execution logic and permissions.
How should I handle failures for a semi-annual job?
Since this job runs infrequently, a failure is highly critical. Implement an explicit retry policy with exponential backoff, and integrate an external alerting service (like PagerDuty or Slack webhooks) inside the execution block to immediately notify on-call engineers.
Will this job conflict with monthly or daily cron jobs?
Yes, many automated tasks run at midnight on the first of the month. To avoid CPU or database IOPS exhaustion, consider shifting this semi-annual job to a quiet hour (e.g., 3:00 AM) or running it in an isolated, auto-scaling worker pool.
* Explore
Related expressions you might need
Last verified: